stk/Tk/unix/tkUnixEvent.c

195 lines
5.1 KiB
C
Raw Normal View History

1996-09-27 06:29:02 -04:00
/*
* 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;
}
}