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;
|
|||
|
}
|
|||
|
}
|