mirror of
https://github.com/Interlisp/maiko.git
synced 2026-02-09 01:31:11 +00:00
* Rewrite keyboard and async I/O handling to improve performance and reduce dependency on async I/O signals Replaces the SIGIO handler, which used to process X events in the interrupt context, with a stub routine that sets a flag to signal processing is required. Actual event processing is moved to the main dispatch loop where Lisp periodic interrupts are handled. Removes the X connection file descriptor from the set of fds contributing to SIGIO events and moves the processing of X events to where the Lisp periodic interrupt is handled in the main dispatch loop. This code is already guarded by a check for XPending() so can be called regardless of whether any file descriptors are known to be ready. Actual processing of async I/O events and X events are handled by procedures process_io_events() and process_Xevents() respectively. For the most part these are a renaming of getsignaldata() and getXsignaldata(). The Lisp periodic timer (VTALRM) was set to operate with a 25000 us period (40 Hz), but on modern hardware it is possible to run this timer with a period of 10000 us (100 Hz) Incidentally, a bug was noted (and fixed) in the X event handling code for motion events: Mouse motion without any keyboard activity should not add an entry to the keyboard event ring buffer as these events do not represent a key state change. Since the ring buffer is of limited size, when it is filled new events are ignored until the buffered events are processed. This resulted in the loss of a key/mouse button transition (up or down) if the mouse was moved about "too much" between keyboard events. A few incidental cleanups were also made: - KBDEventFlg initialization fixed (wrong semantic type) - Event_Req renamed to IO_Signalled (more appropriate name) - int_io_open() sets up process (self) to handle SIGIO generated by O_ASYNC operations - LOCK_X_EVENTS turned off since X library calls can no longer happen in an interrupt context * Use of O_ASYNC must depend on the symbol being defined (looking at you, Cygwin) * Add SA_RESTART flag to sigaction for SIGVTALRM periodic interrupt * LOCK_X_UPDATE is no longer needed and should not be defined by default for Solaris in version.h
344 lines
13 KiB
C
344 lines
13 KiB
C
/* $Id: xwinman.c,v 1.3 2001/12/26 22:17:07 sybalsky Exp $ (C) Copyright Venue, All Rights Reserved
|
|
*/
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* (C) Copyright 1989, 1990, 1990, 1991, 1992, 1993, 1994, 2000 Venue. */
|
|
/* All Rights Reserved. */
|
|
/* Manufactured in the United States of America. */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
#include "version.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xutil.h>
|
|
|
|
#include "lispemul.h"
|
|
#include "miscstat.h"
|
|
#include "devif.h"
|
|
#include "xdefs.h"
|
|
#include "xscroll.h"
|
|
#include "xwinmandefs.h"
|
|
#include "keyeventdefs.h"
|
|
#include "xlspwindefs.h"
|
|
#include "xscrolldefs.h"
|
|
|
|
int Mouse_Included = FALSE;
|
|
|
|
extern Cursor WaitCursor, DefaultCursor, VertScrollCursor, VertThumbCursor, ScrollUpCursor,
|
|
ScrollDownCursor, HorizScrollCursor, HorizThumbCursor, ScrollLeftCursor, ScrollRightCursor;
|
|
|
|
extern DspInterface currentdsp;
|
|
|
|
extern DLword *EmCursorX68K, *EmCursorY68K;
|
|
extern DLword *EmMouseX68K, *EmMouseY68K, *EmKbdAd068K, *EmRealUtilin68K;
|
|
extern LispPTR *CLastUserActionCell68k;
|
|
extern MISCSTATS *MiscStats;
|
|
extern int KBDEventFlg;
|
|
extern u_char *SUNLispKeyMap;
|
|
#define KEYCODE_OFFSET 7 /* Sun Keycode offset */
|
|
|
|
/* bits within the EmRealUtilin word */
|
|
#define KEYSET_LEFT 8
|
|
#define KEYSET_LEFTMIDDLE 9
|
|
#define KEYSET_MIDDLE 10
|
|
#define KEYSET_RIGHTMIDDLE 11
|
|
#define KEYSET_RIGHT 12
|
|
/* Mouse buttons */
|
|
#define MOUSE_LEFT 13
|
|
#define MOUSE_RIGHT 14
|
|
#define MOUSE_MIDDLE 15
|
|
|
|
/* bound: return b if it is between a and c otherwise it returns a or c */
|
|
int bound(int a, int b, int c)
|
|
{
|
|
if (b <= a)
|
|
return (a);
|
|
else if (b >= c)
|
|
return (c);
|
|
else
|
|
return (b);
|
|
}
|
|
|
|
void Set_BitGravity(XButtonEvent *event, DspInterface dsp, Window window, int grav)
|
|
{
|
|
Window OldWindow;
|
|
|
|
/* Change Background Pixmap of Gravity Window */
|
|
XLOCK;
|
|
switch (dsp->BitGravity) {
|
|
case NorthWestGravity: OldWindow = dsp->NWGrav; break;
|
|
case NorthEastGravity: OldWindow = dsp->NEGrav; break;
|
|
case SouthWestGravity: OldWindow = dsp->SWGrav; break;
|
|
case SouthEastGravity: OldWindow = dsp->SEGrav; break;
|
|
};
|
|
|
|
dsp->BitGravity = grav;
|
|
|
|
XSetWindowBackgroundPixmap(event->display, OldWindow, dsp->GravityOffPixmap);
|
|
XClearWindow(event->display, OldWindow);
|
|
|
|
XSetWindowBackgroundPixmap(event->display, window, dsp->GravityOnPixmap);
|
|
XClearWindow(event->display, window);
|
|
XUNLOCK(dsp);
|
|
} /* end Set_BitGravity */
|
|
|
|
static void lisp_Xconfigure(DspInterface dsp, int x, int y, int lspWinWidth, int lspWinHeight)
|
|
{
|
|
int GravSize, Col2, Row2, Col3, Row3;
|
|
|
|
/* The Visible width and height changes when */
|
|
/* we configure the window. Make them */
|
|
/* stay within bounds. */
|
|
dsp->Visible.width =
|
|
bound(OUTER_SB_WIDTH(dsp) + 2, lspWinWidth, dsp->Display.width + OUTER_SB_WIDTH(dsp)) -
|
|
OUTER_SB_WIDTH(dsp);
|
|
dsp->Visible.height =
|
|
bound(OUTER_SB_WIDTH(dsp) + 2, lspWinHeight, dsp->Display.height + OUTER_SB_WIDTH(dsp)) -
|
|
OUTER_SB_WIDTH(dsp);
|
|
|
|
GravSize = (int)(dsp->ScrollBarWidth / 2) - (dsp->InternalBorderWidth);
|
|
Col2 = dsp->Visible.width;
|
|
Row2 = dsp->Visible.height;
|
|
Col3 = dsp->Visible.width + (int)(OUTER_SB_WIDTH(dsp) / 2);
|
|
Row3 = dsp->Visible.height + (int)(OUTER_SB_WIDTH(dsp) / 2);
|
|
|
|
XLOCK;
|
|
XMoveResizeWindow(dsp->display_id, dsp->DisplayWindow, 0, 0, dsp->Visible.width,
|
|
dsp->Visible.height);
|
|
/* Scroll bars */
|
|
XMoveResizeWindow(dsp->display_id, dsp->VerScrollBar, Col2, 0 - dsp->InternalBorderWidth, /* y */
|
|
dsp->ScrollBarWidth, /* width */
|
|
dsp->Visible.height); /* height */
|
|
XMoveResizeWindow(dsp->display_id, dsp->HorScrollBar, 0 - dsp->InternalBorderWidth, Row2, /* y */
|
|
dsp->Visible.width, /* width */
|
|
dsp->ScrollBarWidth); /* height */
|
|
|
|
/* Scroll buttons */
|
|
XMoveResizeWindow(
|
|
dsp->display_id, dsp->HorScrollButton,
|
|
(int)((dsp->Visible.x * dsp->Visible.width) / dsp->Display.width), /* x */
|
|
0 - dsp->InternalBorderWidth, /* y */
|
|
(int)((dsp->Visible.width * dsp->Visible.width) / dsp->Display.width) + 1, /* width */
|
|
dsp->ScrollBarWidth); /* height */
|
|
XMoveResizeWindow(
|
|
dsp->display_id, dsp->VerScrollButton, 0 - dsp->InternalBorderWidth, /* x */
|
|
(int)((dsp->Visible.y * dsp->Visible.height) / dsp->Display.height), /* y */
|
|
dsp->ScrollBarWidth, /* width */
|
|
(int)((dsp->Visible.height * dsp->Visible.height) / dsp->Display.height) + 1); /* height */
|
|
|
|
/* Gravity windows */
|
|
XMoveResizeWindow(dsp->display_id, dsp->NWGrav, Col2, Row2, GravSize, GravSize);
|
|
XMoveResizeWindow(dsp->display_id, dsp->NEGrav, Col3, Row2, GravSize, GravSize);
|
|
XMoveResizeWindow(dsp->display_id, dsp->SEGrav, Col3, Row3, GravSize, GravSize);
|
|
XMoveResizeWindow(dsp->display_id, dsp->SWGrav, Col2, Row3, GravSize, GravSize);
|
|
Scroll(dsp, dsp->Visible.x, dsp->Visible.y);
|
|
XFlush(dsp->display_id);
|
|
XUNLOCK(dsp);
|
|
} /* end lisp_Xconfigure */
|
|
|
|
void enable_Xkeyboard(DspInterface dsp)
|
|
{
|
|
XLOCK;
|
|
XSelectInput(dsp->display_id, dsp->DisplayWindow, dsp->EnableEventMask);
|
|
XFlush(dsp->display_id);
|
|
XUNLOCK(dsp);
|
|
}
|
|
|
|
void disable_Xkeyboard(DspInterface dsp)
|
|
{
|
|
XLOCK;
|
|
XSelectInput(dsp->display_id, dsp->DisplayWindow, dsp->DisableEventMask);
|
|
XFlush(dsp->display_id);
|
|
XUNLOCK(dsp);
|
|
}
|
|
|
|
void beep_Xkeyboard(DspInterface dsp)
|
|
{
|
|
#ifdef TRACE
|
|
printf("TRACE: beep_Xkeyboard()\n");
|
|
#endif
|
|
|
|
XLOCK;
|
|
XBell(dsp->display_id, (int)50);
|
|
XFlush(dsp->display_id);
|
|
XUNLOCK(dsp);
|
|
|
|
} /* end beep_Xkeyboard */
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* p r o c e s s _ X e v e n t s */
|
|
/* */
|
|
/* Take X key/mouse events and turn them into Lisp events */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
extern int Current_Hot_X, Current_Hot_Y; /* Cursor hotspot */
|
|
|
|
void process_Xevents(DspInterface dsp)
|
|
{
|
|
XEvent report;
|
|
|
|
while (XPending(dsp->display_id)) {
|
|
XNextEvent(dsp->display_id, &report);
|
|
if (report.xany.window == dsp->DisplayWindow) /* Try the most important window first. */
|
|
switch (report.type) {
|
|
case MotionNotify:
|
|
*CLastUserActionCell68k = MiscStats->secondstmp;
|
|
*EmCursorX68K = (*((DLword *)EmMouseX68K)) =
|
|
(short)((report.xmotion.x + dsp->Visible.x) & 0xFFFF) - Current_Hot_X;
|
|
*EmCursorY68K = (*((DLword *)EmMouseY68K)) =
|
|
(short)((report.xmotion.y + dsp->Visible.y) & 0xFFFF) - Current_Hot_Y;
|
|
break;
|
|
case KeyPress:
|
|
kb_trans(SUNLispKeyMap[(report.xkey.keycode) - KEYCODE_OFFSET], FALSE);
|
|
DoRing();
|
|
if ((KBDEventFlg += 1) > 0) Irq_Stk_End = Irq_Stk_Check = 0;
|
|
break;
|
|
case KeyRelease:
|
|
kb_trans(SUNLispKeyMap[(report.xkey.keycode) - KEYCODE_OFFSET], TRUE);
|
|
DoRing();
|
|
if ((KBDEventFlg += 1) > 0) Irq_Stk_End = Irq_Stk_Check = 0;
|
|
break;
|
|
case ButtonPress:
|
|
switch (report.xbutton.button) {
|
|
case Button1: PUTBASEBIT68K(EmRealUtilin68K, MOUSE_LEFT, FALSE); break;
|
|
case Button2: PUTBASEBIT68K(EmRealUtilin68K, MOUSE_MIDDLE, FALSE); break;
|
|
case Button3: PUTBASEBIT68K(EmRealUtilin68K, MOUSE_RIGHT, FALSE); break;
|
|
case Button4: PUTBASEBIT68K(EmRealUtilin68K, KEYSET_LEFT, FALSE); break;
|
|
case Button5: PUTBASEBIT68K(EmRealUtilin68K, KEYSET_LEFTMIDDLE, FALSE); break;
|
|
case Button5 + 1: PUTBASEBIT68K(EmRealUtilin68K, KEYSET_RIGHT, FALSE); break;
|
|
case Button5 + 2: PUTBASEBIT68K(EmRealUtilin68K, KEYSET_RIGHTMIDDLE, FALSE); break;
|
|
default: break;
|
|
}
|
|
DoRing();
|
|
if ((KBDEventFlg += 1) > 0) Irq_Stk_End = Irq_Stk_Check = 0;
|
|
break;
|
|
case ButtonRelease:
|
|
switch (report.xbutton.button) {
|
|
case Button1: PUTBASEBIT68K(EmRealUtilin68K, MOUSE_LEFT, TRUE); break;
|
|
case Button2: PUTBASEBIT68K(EmRealUtilin68K, MOUSE_MIDDLE, TRUE); break;
|
|
case Button3: PUTBASEBIT68K(EmRealUtilin68K, MOUSE_RIGHT, TRUE); break;
|
|
case Button4: PUTBASEBIT68K(EmRealUtilin68K, KEYSET_LEFT, TRUE); break;
|
|
case Button5: PUTBASEBIT68K(EmRealUtilin68K, KEYSET_LEFTMIDDLE, TRUE); break;
|
|
case Button5 + 1: PUTBASEBIT68K(EmRealUtilin68K, KEYSET_RIGHT, TRUE); break;
|
|
case Button5 + 2: PUTBASEBIT68K(EmRealUtilin68K, KEYSET_RIGHTMIDDLE, TRUE); break;
|
|
default: break;
|
|
}
|
|
DoRing();
|
|
if ((KBDEventFlg += 1) > 0) Irq_Stk_End = Irq_Stk_Check = 0;
|
|
break;
|
|
case EnterNotify: Mouse_Included = TRUE; break;
|
|
case LeaveNotify: Mouse_Included = FALSE; break;
|
|
case Expose:
|
|
(dsp->bitblt_to_screen)(dsp, 0, report.xexpose.x + dsp->Visible.x,
|
|
report.xexpose.y + dsp->Visible.y, report.xexpose.width,
|
|
report.xexpose.height);
|
|
break;
|
|
default: break;
|
|
}
|
|
else if (report.xany.window == dsp->LispWindow)
|
|
switch (report.xany.type) {
|
|
case ConfigureNotify:
|
|
lisp_Xconfigure(dsp, report.xconfigure.x, report.xconfigure.y, report.xconfigure.width,
|
|
report.xconfigure.height);
|
|
break;
|
|
case EnterNotify: enable_Xkeyboard(currentdsp); break;
|
|
case LeaveNotify: break;
|
|
case MapNotify:
|
|
/* Turn the blitting to the screen on */
|
|
break;
|
|
case UnmapNotify:
|
|
/* Turn the blitting to the screen off */
|
|
break;
|
|
default: break;
|
|
}
|
|
else if (report.xany.window == dsp->HorScrollBar)
|
|
switch (report.type) {
|
|
case ButtonPress:
|
|
switch (report.xbutton.button) {
|
|
case Button1:
|
|
DefineCursor(dsp, dsp->HorScrollBar, &ScrollLeftCursor);
|
|
ScrollLeft(dsp);
|
|
break;
|
|
case Button2:
|
|
DefineCursor(dsp, dsp->HorScrollBar, &HorizThumbCursor);
|
|
break;
|
|
case Button3:
|
|
DefineCursor(dsp, dsp->HorScrollBar, &ScrollRightCursor);
|
|
ScrollRight(dsp);
|
|
break;
|
|
default: break;
|
|
} /* end switch */
|
|
break;
|
|
case ButtonRelease:
|
|
switch (report.xbutton.button) {
|
|
case Button1:
|
|
DefineCursor(dsp, report.xany.window, &HorizScrollCursor);
|
|
break;
|
|
case Button2:
|
|
JumpScrollHor(dsp, report.xbutton.x);
|
|
DefineCursor(dsp, report.xany.window, &HorizScrollCursor);
|
|
break;
|
|
case Button3:
|
|
DefineCursor(dsp, report.xany.window, &HorizScrollCursor);
|
|
break;
|
|
default: break;
|
|
} /* end switch */
|
|
default: break;
|
|
}
|
|
else if (report.xany.window == dsp->VerScrollBar)
|
|
switch (report.type) {
|
|
case ButtonPress:
|
|
switch (report.xbutton.button) {
|
|
case Button1:
|
|
DefineCursor(dsp, report.xany.window, &ScrollUpCursor);
|
|
ScrollUp(dsp);
|
|
break;
|
|
case Button2:
|
|
DefineCursor(dsp, report.xany.window, &VertThumbCursor);
|
|
break;
|
|
case Button3:
|
|
DefineCursor(dsp, report.xany.window, &ScrollDownCursor);
|
|
ScrollDown(dsp);
|
|
break;
|
|
default: break;
|
|
} /* end switch */
|
|
break;
|
|
case ButtonRelease:
|
|
switch (report.xbutton.button) {
|
|
case Button1:
|
|
DefineCursor(dsp, report.xany.window, &VertScrollCursor);
|
|
break;
|
|
case Button3:
|
|
DefineCursor(dsp, report.xany.window, &VertScrollCursor);
|
|
break;
|
|
case Button2:
|
|
JumpScrollVer(dsp, report.xbutton.y);
|
|
DefineCursor(dsp, report.xany.window, &VertScrollCursor);
|
|
break;
|
|
default: break;
|
|
} /* end switch */
|
|
break;
|
|
default: break;
|
|
}
|
|
else if ((report.xany.window == dsp->NEGrav) && (report.xany.type == ButtonPress) &&
|
|
((report.xbutton.button & 0xFF) == Button1))
|
|
Set_BitGravity(&report.xbutton, dsp, dsp->NEGrav, NorthEastGravity);
|
|
else if ((report.xany.window == dsp->SEGrav) && (report.xany.type == ButtonPress) &&
|
|
((report.xbutton.button & 0xFF) == Button1))
|
|
Set_BitGravity(&report.xbutton, dsp, dsp->SEGrav, SouthEastGravity);
|
|
else if ((report.xany.window == dsp->SWGrav) && (report.xany.type == ButtonPress) &&
|
|
((report.xbutton.button & 0xFF) == Button1))
|
|
Set_BitGravity(&report.xbutton, dsp, dsp->SWGrav, SouthWestGravity);
|
|
else if ((report.xany.window == dsp->NWGrav) && (report.xany.type == ButtonPress) &&
|
|
((report.xbutton.button & 0xFF) == Button1))
|
|
Set_BitGravity(&report.xbutton, dsp, dsp->NWGrav, NorthWestGravity);
|
|
XFlush(dsp->display_id);
|
|
} /* end while */
|
|
} /* end process_Xevents */
|