1
0
mirror of https://github.com/Interlisp/maiko.git synced 2026-01-16 08:15:31 +00:00
Interlisp.maiko/src/xlspwin.c
Nick Briggs 377a6f3f47
Rewrite keyboard and async I/O handling to improve performance and reduce dependency on async I/O signals (#392)
* 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
2021-09-02 12:42:51 -07:00

394 lines
17 KiB
C

/* $Id: xlspwin.c,v 1.4 2001/12/26 22:17:07 sybalsky Exp $ (C) Copyright Venue, All Rights Reserved
*/
/************************************************************************/
/* */
/* (C) Copyright 1989, 1990, 1990, 1991, 1992, 1993, */
/* 1994, 1995, 1999, 2000, 2001 Venue. */
/* All Rights Reserved. */
/* */
/* Manufactured in the United States of America. */
/* */
/************************************************************************/
#include "version.h"
#include <stdio.h>
#include <sys/time.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "lispemul.h"
#include "xdefs.h"
#include "xbitmaps.h"
#include "keyboard.h"
#include "devif.h"
#include "dbprint.h"
#include "xlspwindefs.h"
#include "commondefs.h"
#include "xcursordefs.h"
#include "xmkicondefs.h"
extern DLword *EmKbdAd068K, *EmKbdAd168K, *EmKbdAd268K, *EmKbdAd368K, *EmKbdAd468K, *EmKbdAd568K,
*EmRealUtilin68K;
extern DLword *CTopKeyevent;
extern LispPTR *KEYBUFFERING68k;
extern int URaid_req;
extern DLword *DisplayRegion68k;
extern int Current_Hot_X, Current_Hot_Y; /* X Cursor hotspots */
extern char Window_Title[255];
extern char Icon_Title[255];
extern int save_argc;
extern char **save_argv;
extern DspInterface currentdsp;
XGCValues gcv;
XEvent report;
Cursor WaitCursor, DefaultCursor, VertScrollCursor, VertThumbCursor, ScrollUpCursor,
ScrollDownCursor, HorizScrollCursor, HorizThumbCursor, ScrollLeftCursor, ScrollRightCursor;
extern int LispWindowRequestedX, LispWindowRequestedY;
extern unsigned LispWindowRequestedWidth, LispWindowRequestedHeight;
/************************************************************************/
/* */
/* */
/* */
/* */
/* */
/************************************************************************/
void Create_LispWindow(DspInterface dsp)
{
XSizeHints szhint = {0};
XWMHints Lisp_WMhints = {0};
XClassHint xclasshint = {0};
XTextProperty IconText = {0}, WindowNameText = {0};
XSetWindowAttributes Lisp_SetWinAttributes = {0};
Screen *screen;
int Col2, Row2, Col3, Row3, GravSize;
char *WT, *IT;
WT = Window_Title;
IT = Icon_Title;
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);
screen = ScreenOfDisplay(dsp->display_id, DefaultScreen(dsp->display_id));
dsp->LispWindow = XCreateSimpleWindow(
dsp->display_id, RootWindowOfScreen(screen), LispWindowRequestedX, /* Default upper left */
LispWindowRequestedY, /* Default upper left */
dsp->Visible.width + OUTER_SB_WIDTH(dsp), /* Default width */
dsp->Visible.height + OUTER_SB_WIDTH(dsp), /* Default height */
0, /* Default border */
BlackPixelOfScreen(screen), WhitePixelOfScreen(screen));
Lisp_SetWinAttributes.bit_gravity = dsp->BitGravity;
Lisp_SetWinAttributes.override_redirect = False;
Lisp_SetWinAttributes.backing_store = DoesBackingStore(screen);
XChangeWindowAttributes(dsp->display_id, dsp->LispWindow, CWBitGravity | CWOverrideRedirect,
&Lisp_SetWinAttributes);
dsp->DisableEventMask = NoEventMask;
dsp->EnableEventMask = ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask |
StructureNotifyMask | PointerMotionMask | ExposureMask | KeyPressMask |
KeyReleaseMask;
/* Have to make the GC before we make the icon. */
gcv.function = GXcopy;
gcv.foreground =
BlackPixelOfScreen(ScreenOfDisplay(dsp->display_id, DefaultScreen(dsp->display_id)));
gcv.background =
WhitePixelOfScreen(ScreenOfDisplay(dsp->display_id, DefaultScreen(dsp->display_id)));
dsp->Copy_GC =
XCreateGC(dsp->display_id, dsp->LispWindow, GCForeground | GCBackground | GCFunction, &gcv);
szhint.max_width = dsp->Display.width + OUTER_SB_WIDTH(dsp);
szhint.max_height = dsp->Display.height + OUTER_SB_WIDTH(dsp);
szhint.min_width = OUTER_SB_WIDTH(dsp);
szhint.min_height = OUTER_SB_WIDTH(dsp);
szhint.win_gravity = dsp->BitGravity;
szhint.flags = PMaxSize | PWinGravity | PSize;
Lisp_WMhints.icon_pixmap = make_Xicon(dsp);
Lisp_WMhints.input = True;
Lisp_WMhints.flags = IconPixmapHint | InputHint;
xclasshint.res_name = *save_argv;
xclasshint.res_class = *save_argv;
XStringListToTextProperty(&WT, 1, &WindowNameText);
XStringListToTextProperty(&IT, 1, &IconText);
XSetWMProperties(dsp->display_id, dsp->LispWindow, &WindowNameText, &IconText, save_argv,
save_argc, &szhint, &Lisp_WMhints, &xclasshint);
XSelectInput(dsp->display_id, dsp->LispWindow, dsp->EnableEventMask);
init_Xcursor(dsp);
dsp->DisplayWindow = XCreateSimpleWindow(dsp->display_id, dsp->LispWindow, 0, 0,
dsp->Visible.width, dsp->Visible.height, 0,
BlackPixelOfScreen(screen), WhitePixelOfScreen(screen));
XChangeWindowAttributes(dsp->display_id, dsp->DisplayWindow,
CWBitGravity | CWOverrideRedirect | CWBackingStore,
&Lisp_SetWinAttributes);
XSelectInput(dsp->display_id, dsp->DisplayWindow, dsp->EnableEventMask);
XMapWindow(dsp->display_id, dsp->DisplayWindow);
/*********************************************************************/
/* Create all the vanilla pixmaps and cursors for the display window */
/*********************************************************************/
dsp->ScrollBarPixmap = XCreatePixmapFromBitmapData(
dsp->display_id, dsp->LispWindow, (char *)check_bits, check_width, check_height,
BlackPixelOfScreen(screen), WhitePixelOfScreen(screen), DefaultDepthOfScreen(screen));
dsp->GravityOnPixmap = XCreatePixmapFromBitmapData(
dsp->display_id, dsp->LispWindow, (char *)check_bits, 16, 16, BlackPixelOfScreen(screen),
WhitePixelOfScreen(screen), DefaultDepthOfScreen(screen));
dsp->GravityOffPixmap = XCreatePixmapFromBitmapData(
dsp->display_id, dsp->LispWindow, (char *)plain_bits, 16, 16, BlackPixelOfScreen(screen),
WhitePixelOfScreen(screen), DefaultDepthOfScreen(screen));
set_Xcursor(dsp, default_cursor.cuimage, (int)default_cursor.cuhotspotx,
(int)(15 - default_cursor.cuhotspoty), &DefaultCursor, 0);
set_Xcursor(dsp, wait_cursor.cuimage, (int)wait_cursor.cuhotspotx,
(int)(15 - wait_cursor.cuhotspoty), &WaitCursor, 0);
set_Xcursor(dsp, scrolldown_cursor.cuimage, (int)scrolldown_cursor.cuhotspotx,
(int)(15 - scrolldown_cursor.cuhotspoty), &ScrollDownCursor, 0);
set_Xcursor(dsp, scrollleft_cursor.cuimage, (int)scrollleft_cursor.cuhotspotx,
(int)(15 - scrollleft_cursor.cuhotspoty), &ScrollLeftCursor, 0);
set_Xcursor(dsp, vertscroll_cursor.cuimage, (int)vertscroll_cursor.cuhotspotx,
(int)(15 - vertscroll_cursor.cuhotspoty), &VertScrollCursor, 0);
set_Xcursor(dsp, vertthumb_cursor.cuimage, (int)vertthumb_cursor.cuhotspotx,
(int)(15 - vertthumb_cursor.cuhotspoty), &VertThumbCursor, 0);
set_Xcursor(dsp, horizscroll_cursor.cuimage, (int)horizscroll_cursor.cuhotspotx,
(int)(15 - horizscroll_cursor.cuhotspoty), &HorizScrollCursor, 0);
set_Xcursor(dsp, horizthumb_cursor.cuimage, (int)horizthumb_cursor.cuhotspotx,
(int)(15 - horizthumb_cursor.cuhotspoty), &HorizThumbCursor, 0);
set_Xcursor(dsp, scrollright_cursor.cuimage, (int)scrollright_cursor.cuhotspotx,
(int)(15 - scrollright_cursor.cuhotspoty), &ScrollRightCursor, 0);
set_Xcursor(dsp, scrollup_cursor.cuimage, (int)scrollup_cursor.cuhotspotx,
(int)(15 - scrollup_cursor.cuhotspoty), &ScrollUpCursor, 0);
/********************************/
/* Make all the toolkit windows */
/********************************/
dsp->VerScrollBar = XCreateSimpleWindow(dsp->display_id, dsp->LispWindow, Col2,
0 - dsp->InternalBorderWidth, /* y */
dsp->ScrollBarWidth, /* width */
dsp->Visible.height, dsp->InternalBorderWidth,
BlackPixelOfScreen(screen), WhitePixelOfScreen(screen));
DefineCursor(dsp, dsp->VerScrollBar, &VertScrollCursor);
XMapWindow(dsp->display_id, dsp->VerScrollBar);
dsp->HorScrollBar = XCreateSimpleWindow(dsp->display_id, dsp->LispWindow,
0 - dsp->InternalBorderWidth, Row2, /* y */
dsp->Visible.width, /* width */
dsp->ScrollBarWidth, dsp->InternalBorderWidth,
BlackPixelOfScreen(screen), WhitePixelOfScreen(screen));
DefineCursor(dsp, dsp->HorScrollBar, &HorizScrollCursor);
XChangeWindowAttributes(dsp->display_id, dsp->HorScrollBar, CWOverrideRedirect,
&Lisp_SetWinAttributes);
XMapWindow(dsp->display_id, dsp->HorScrollBar);
dsp->VerScrollButton = XCreateSimpleWindow(
dsp->display_id, dsp->VerScrollBar, 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,
dsp->InternalBorderWidth, BlackPixelOfScreen(screen), WhitePixelOfScreen(screen));
XChangeWindowAttributes(dsp->display_id, dsp->VerScrollButton, CWOverrideRedirect,
&Lisp_SetWinAttributes);
XSetWindowBackgroundPixmap(dsp->display_id, dsp->VerScrollButton, dsp->ScrollBarPixmap);
XClearWindow(dsp->display_id, dsp->VerScrollButton);
XMapWindow(dsp->display_id, dsp->VerScrollButton);
dsp->HorScrollButton = XCreateSimpleWindow(
dsp->display_id, dsp->HorScrollBar,
(int)((dsp->Visible.x * dsp->Visible.width) / dsp->Display.width),
0 - dsp->InternalBorderWidth, /* y */
(int)((dsp->Visible.width * dsp->Visible.width) / dsp->Display.width) + 1,
dsp->ScrollBarWidth, dsp->InternalBorderWidth, BlackPixelOfScreen(screen),
WhitePixelOfScreen(screen));
XChangeWindowAttributes(dsp->display_id, dsp->HorScrollButton, CWOverrideRedirect,
&Lisp_SetWinAttributes);
XSetWindowBackgroundPixmap(dsp->display_id, dsp->HorScrollButton, dsp->ScrollBarPixmap);
XClearWindow(dsp->display_id, dsp->HorScrollButton);
XMapWindow(dsp->display_id, dsp->HorScrollButton);
dsp->NWGrav = XCreateSimpleWindow(dsp->display_id, dsp->LispWindow, Col2, Row2, GravSize,
GravSize, dsp->InternalBorderWidth, BlackPixelOfScreen(screen),
WhitePixelOfScreen(screen));
XSetWindowBackgroundPixmap(dsp->display_id, dsp->NWGrav, dsp->GravityOnPixmap);
DefineCursor(dsp, dsp->NWGrav, &DefaultCursor);
XChangeWindowAttributes(dsp->display_id, dsp->NWGrav, CWOverrideRedirect, &Lisp_SetWinAttributes);
XClearWindow(dsp->display_id, dsp->NWGrav);
XMapWindow(dsp->display_id, dsp->NWGrav);
dsp->SEGrav = XCreateSimpleWindow(dsp->display_id, dsp->LispWindow, Col3, Row3, GravSize,
GravSize, dsp->InternalBorderWidth, BlackPixelOfScreen(screen),
WhitePixelOfScreen(screen));
XSetWindowBackgroundPixmap(dsp->display_id, dsp->SEGrav, dsp->GravityOffPixmap);
DefineCursor(dsp, dsp->SEGrav, &DefaultCursor);
XChangeWindowAttributes(dsp->display_id, dsp->SEGrav, CWOverrideRedirect, &Lisp_SetWinAttributes);
XClearWindow(dsp->display_id, dsp->NWGrav);
XMapWindow(dsp->display_id, dsp->SEGrav);
dsp->SWGrav = XCreateSimpleWindow(dsp->display_id, dsp->LispWindow, Col2, Row3, GravSize,
GravSize, dsp->InternalBorderWidth, BlackPixelOfScreen(screen),
WhitePixelOfScreen(screen));
XSetWindowBackgroundPixmap(dsp->display_id, dsp->SWGrav, dsp->GravityOffPixmap);
DefineCursor(dsp, dsp->SWGrav, &DefaultCursor);
XClearWindow(dsp->display_id, dsp->NWGrav);
XMapWindow(dsp->display_id, dsp->SWGrav);
dsp->NEGrav = XCreateSimpleWindow(dsp->display_id, dsp->LispWindow, Col3, Row2, GravSize,
GravSize, dsp->InternalBorderWidth, BlackPixelOfScreen(screen),
WhitePixelOfScreen(screen));
XSetWindowBackgroundPixmap(dsp->display_id, dsp->NEGrav, dsp->GravityOffPixmap);
DefineCursor(dsp, dsp->NEGrav, &DefaultCursor);
XClearWindow(dsp->display_id, dsp->NWGrav);
XMapWindow(dsp->display_id, dsp->NEGrav);
/* DefineCursor( dsp, dsp->DisplayWindow, &WaitCursor ); */
XLOCK;
XMapWindow(dsp->display_id, dsp->LispWindow);
XFlush(dsp->display_id);
XUNLOCK(dsp);
}
void lisp_Xvideocolor(int flag)
{
Screen *screen;
XEvent event;
unsigned long newForeground;
XLOCK;
screen = ScreenOfDisplay(currentdsp->display_id, DefaultScreen(currentdsp->display_id));
newForeground = flag ? WhitePixelOfScreen(screen) : BlackPixelOfScreen(screen);
/* window -- are we making a change? */
XGetGCValues(currentdsp->display_id, currentdsp->Copy_GC, GCForeground | GCBackground, &gcv);
if (newForeground != gcv.foreground) {
/* swap foreground and background in the graphics context*/
gcv.background = gcv.foreground;
gcv.foreground = newForeground;
XChangeGC(currentdsp->display_id, currentdsp->Copy_GC, GCForeground | GCBackground, &gcv);
/* notify the display code to refresh the visible screen with new fg/bg colors */
event.type = Expose;
event.xexpose.window = currentdsp->DisplayWindow;
event.xexpose.x = 0;
event.xexpose.y = 0;
event.xexpose.width = currentdsp->Visible.width;
event.xexpose.height = currentdsp->Visible.height;
XSendEvent(currentdsp->display_id, currentdsp->DisplayWindow, True, 0, &event);
}
XFlush(currentdsp->display_id);
XUNLOCK(currentdsp);
} /* end lisp_Xvideocolor */
void set_Xmouseposition(int x, int y)
{
int dest_x, dest_y;
TPRINT(("set_Xmouseposition(%d,%d)\n", x, y));
dest_x = (x & 0xFFFF) + Current_Hot_X - currentdsp->Visible.x;
dest_y = (y & 0xFFFF) + Current_Hot_Y - currentdsp->Visible.y;
if ((dest_x >= 0) && (dest_x <= currentdsp->Visible.width) && (dest_y >= 0) &&
(dest_y <= currentdsp->Visible.height)) {
XLOCK;
XWarpPointer(currentdsp->display_id, (Window)NULL, currentdsp->DisplayWindow, 0, 0, 0, 0,
dest_x, dest_y);
XFlush(currentdsp->display_id);
XUNLOCK(currentdsp);
}
} /* end set_Xmouseposition */
/************************************************************************/
/* */
/* D o R i n g */
/* */
/* Take keyboard events and turn them into Lisp event info */
/* (when running under X) */
/* */
/************************************************************************/
void DoRing() {
DLword w, r;
KBEVENT *kbevent;
TPRINT(("TRACE: DoRing()\n"));
do_ring:
/* DEL is not generally present on a Mac X keyboard, Ctrl-shift-ESC would be 18496 */
if (((*EmKbdAd268K) & 2113) == 0) { /*Ctrl-shift-NEXT*/
error("****** EMERGENCY Interrupt ******");
*EmKbdAd268K = KB_ALLUP; /*reset*/
((RING *)CTopKeyevent)->read = 0; /* reset queue */
((RING *)CTopKeyevent)->write = MINKEYEVENT;
/*return(0);*/
} else if (((*EmKbdAd268K) & 2114) == 0) { /* Ctrl-Shift-DEL */
*EmKbdAd268K = KB_ALLUP; /*reset*/
URaid_req = T;
((RING *)CTopKeyevent)->read = 0; /* reset queue */
((RING *)CTopKeyevent)->write = MINKEYEVENT;
/*return(0);*/
}
#ifdef OS4_TYPE4BUG
else if (((*EmKbdAd268K) & 2120) == 0) { /* Ctrl-Shift-Return */
*EmKbdAd268K = KB_ALLUP; /*reset*/
URaid_req = T;
((RING *)CTopKeyevent)->read = 0; /* reset queue */
((RING *)CTopKeyevent)->write = MINKEYEVENT;
}
#endif
r = RING_READ(CTopKeyevent);
w = RING_WRITE(CTopKeyevent);
if (r == w) /* event queue FULL */
goto KBnext;
kbevent = (KBEVENT *)(CTopKeyevent + w);
/* RCLK(kbevent->time); */
kbevent->W0 = *EmKbdAd068K;
kbevent->W1 = *EmKbdAd168K;
kbevent->W2 = *EmKbdAd268K;
kbevent->W3 = *EmKbdAd368K;
kbevent->W4 = *EmKbdAd468K;
kbevent->W5 = *EmKbdAd568K;
kbevent->WU = *EmRealUtilin68K;
if (r == 0) /* Queue was empty */
((RING *)CTopKeyevent)->read = w;
if (w >= MAXKEYEVENT)
((RING *)CTopKeyevent)->write = MINKEYEVENT;
else
((RING *)CTopKeyevent)->write = w + KEYEVENTSIZE;
KBnext:
if (*KEYBUFFERING68k == NIL) *KEYBUFFERING68k = ATOM_T;
}