195 lines
5.1 KiB
C
195 lines
5.1 KiB
C
/*
|
||
* tkUnixEvent.c --
|
||
*
|
||
* This file implements an event source for X displays for the
|
||
* UNIX version of Tk.
|
||
*
|
||
* Copyright (c) 1995 Sun Microsystems, Inc.
|
||
*
|
||
* See the file "license.terms" for information on usage and redistribution
|
||
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||
*
|
||
* SCCS: @(#) tkUnixEvent.c 1.5 96/02/15 18:55:30
|
||
*/
|
||
|
||
#include "tkInt.h"
|
||
#include "tkUnixInt.h"
|
||
#include <signal.h>
|
||
|
||
/*
|
||
* Prototypes for procedures that are referenced only in this file:
|
||
*/
|
||
|
||
static void DisplayCheckProc _ANSI_ARGS_((ClientData clientData,
|
||
int flags));
|
||
static void DisplaySetupProc _ANSI_ARGS_((ClientData clientData,
|
||
int flags));
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* DisplaySetupProc --
|
||
*
|
||
* This procedure is part of the event source for UNIX X displays.
|
||
* It is invoked by Tcl_DoOneEvent before it calls select to check
|
||
* for events on all displays.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* Tells the notifier which files should be waited for.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
static void
|
||
DisplaySetupProc(clientData, flags)
|
||
ClientData clientData; /* Not used. */
|
||
int flags; /* Flags passed to Tk_DoOneEvent:
|
||
* if it doesn't include
|
||
* TCL_WINDOW_EVENTS then we do
|
||
* nothing. */
|
||
{
|
||
TkDisplay *dispPtr;
|
||
static Tcl_Time dontBlock = {0, 0};
|
||
|
||
if (!(flags & TCL_WINDOW_EVENTS)) {
|
||
return;
|
||
}
|
||
|
||
for (dispPtr = tkDisplayList; dispPtr != NULL; dispPtr = dispPtr->nextPtr) {
|
||
Tcl_File handle;
|
||
XFlush(dispPtr->display);
|
||
if (XQLength(dispPtr->display) > 0) {
|
||
Tcl_SetMaxBlockTime(&dontBlock);
|
||
}
|
||
handle = Tcl_GetFile(
|
||
(ClientData)ConnectionNumber(dispPtr->display), TCL_UNIX_FD);
|
||
Tcl_WatchFile(handle, TCL_READABLE);
|
||
}
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* DisplayCheckProc --
|
||
*
|
||
* This procedure is the second part of the "event source" for
|
||
* X displays. It is invoked by Tcl_DoOneEvent after it calls
|
||
* select (or whatever it uses to wait for events).
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* Makes entries on the Tcl event queue for all the events available
|
||
* from all the displays.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
static void
|
||
DisplayCheckProc(clientData, flags)
|
||
ClientData clientData; /* Not used. */
|
||
int flags; /* Flags passed to Tk_DoOneEvent:
|
||
* if it doesn't include
|
||
* TCL_WINDOW_EVENTS then we do
|
||
* nothing. */
|
||
{
|
||
TkDisplay *dispPtr;
|
||
XEvent event;
|
||
int numFound;
|
||
|
||
if (!(flags & TCL_WINDOW_EVENTS)) {
|
||
return;
|
||
}
|
||
|
||
for (dispPtr = tkDisplayList; dispPtr != NULL; dispPtr = dispPtr->nextPtr) {
|
||
Tcl_File handle;
|
||
/*
|
||
* Note: we should not need to do a flush of the output queues before
|
||
* calling XEventsQueued because it was done by DisplaySetupProc.
|
||
*/
|
||
|
||
handle = Tcl_GetFile(
|
||
(ClientData) ConnectionNumber(dispPtr->display), TCL_UNIX_FD);
|
||
if (Tcl_FileReady(handle, TCL_READABLE) != 0) {
|
||
numFound = XEventsQueued(dispPtr->display, QueuedAfterReading);
|
||
if (numFound == 0) {
|
||
|
||
/*
|
||
* Things are very tricky if there aren't any events readable
|
||
* at this point (after all, there was supposedly data
|
||
* available on the connection). A couple of things could
|
||
* have occurred:
|
||
*
|
||
* One possibility is that there were only error events in the
|
||
* input from the server. If this happens, we should return
|
||
* (we don't want to go to sleep in XNextEvent below, since
|
||
* this would block out other sources of input to the
|
||
* process).
|
||
*
|
||
* Another possibility is that our connection to the server
|
||
* has been closed. This will not necessarily be detected in
|
||
* XEventsQueued (!!), so if we just return then there will be
|
||
* an infinite loop. To detect such an error, generate a NoOp
|
||
* protocol request to exercise the connection to the server,
|
||
* then return. However, must disable SIGPIPE while sending
|
||
* the request, or else the process will die from the signal
|
||
* and won't invoke the X error function to print a nice (?!)
|
||
* message.
|
||
*/
|
||
|
||
void (*oldHandler)();
|
||
|
||
oldHandler = (void (*)()) signal(SIGPIPE, SIG_IGN);
|
||
XNoOp(dispPtr->display);
|
||
XFlush(dispPtr->display);
|
||
(void) signal(SIGPIPE, oldHandler);
|
||
}
|
||
} else {
|
||
numFound = XQLength(dispPtr->display);
|
||
}
|
||
|
||
/*
|
||
* Transfer events from the X event queue to the Tk event queue.
|
||
*/
|
||
|
||
while (numFound > 0) {
|
||
XNextEvent(dispPtr->display, &event);
|
||
Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
|
||
numFound--;
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* TkCreateXEventSource --
|
||
*
|
||
* This procedure is called during Tk initialization to create
|
||
* the event source for X Window events.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* A new event source is created.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
TkCreateXEventSource()
|
||
{
|
||
static int initialized = 0;
|
||
|
||
if (!initialized) {
|
||
Tcl_CreateEventSource(DisplaySetupProc, DisplayCheckProc,
|
||
(ClientData) NULL);
|
||
initialized = 1;
|
||
}
|
||
}
|