/*1* tkUnixEvent.c --2*3* This file implements an event source for X displays for the4* UNIX version of Tk.5*6* Copyright (c) 1995 Sun Microsystems, Inc.7*8* See the file "license.terms" for information on usage and redistribution9* of this file, and for a DISCLAIMER OF ALL WARRANTIES.10*11* SCCS: @(#) tkUnixEvent.c 1.5 96/02/15 18:55:3012*/1314#include "tkInt.h"15#include "tkUnixInt.h"16#include <signal.h>1718/*19* Prototypes for procedures that are referenced only in this file:20*/2122static void DisplayCheckProc _ANSI_ARGS_((ClientData clientData,23int flags));24static void DisplaySetupProc _ANSI_ARGS_((ClientData clientData,25int flags));2627/*28*----------------------------------------------------------------------29*30* DisplaySetupProc --31*32* This procedure is part of the event source for UNIX X displays.33* It is invoked by Tcl_DoOneEvent before it calls select to check34* for events on all displays.35*36* Results:37* None.38*39* Side effects:40* Tells the notifier which files should be waited for.41*42*----------------------------------------------------------------------43*/4445static void46DisplaySetupProc(clientData, flags)47ClientData clientData; /* Not used. */48int flags; /* Flags passed to Tk_DoOneEvent:49* if it doesn't include50* TCL_WINDOW_EVENTS then we do51* nothing. */52{53TkDisplay *dispPtr;54static Tcl_Time dontBlock = {0, 0};5556if (!(flags & TCL_WINDOW_EVENTS)) {57return;58}5960for (dispPtr = tkDisplayList; dispPtr != NULL; dispPtr = dispPtr->nextPtr) {61Tcl_File handle;62XFlush(dispPtr->display);63if (XQLength(dispPtr->display) > 0) {64Tcl_SetMaxBlockTime(&dontBlock);65}66handle = Tcl_GetFile(67(ClientData)ConnectionNumber(dispPtr->display), TCL_UNIX_FD);68Tcl_WatchFile(handle, TCL_READABLE);69}70}7172/*73*----------------------------------------------------------------------74*75* DisplayCheckProc --76*77* This procedure is the second part of the "event source" for78* X displays. It is invoked by Tcl_DoOneEvent after it calls79* select (or whatever it uses to wait for events).80*81* Results:82* None.83*84* Side effects:85* Makes entries on the Tcl event queue for all the events available86* from all the displays.87*88*----------------------------------------------------------------------89*/9091static void92DisplayCheckProc(clientData, flags)93ClientData clientData; /* Not used. */94int flags; /* Flags passed to Tk_DoOneEvent:95* if it doesn't include96* TCL_WINDOW_EVENTS then we do97* nothing. */98{99TkDisplay *dispPtr;100XEvent event;101int numFound;102103if (!(flags & TCL_WINDOW_EVENTS)) {104return;105}106107for (dispPtr = tkDisplayList; dispPtr != NULL; dispPtr = dispPtr->nextPtr) {108Tcl_File handle;109/*110* Note: we should not need to do a flush of the output queues before111* calling XEventsQueued because it was done by DisplaySetupProc.112*/113114handle = Tcl_GetFile(115(ClientData) ConnectionNumber(dispPtr->display), TCL_UNIX_FD);116if (Tcl_FileReady(handle, TCL_READABLE) != 0) {117numFound = XEventsQueued(dispPtr->display, QueuedAfterReading);118if (numFound == 0) {119120/*121* Things are very tricky if there aren't any events readable122* at this point (after all, there was supposedly data123* available on the connection). A couple of things could124* have occurred:125*126* One possibility is that there were only error events in the127* input from the server. If this happens, we should return128* (we don't want to go to sleep in XNextEvent below, since129* this would block out other sources of input to the130* process).131*132* Another possibility is that our connection to the server133* has been closed. This will not necessarily be detected in134* XEventsQueued (!!), so if we just return then there will be135* an infinite loop. To detect such an error, generate a NoOp136* protocol request to exercise the connection to the server,137* then return. However, must disable SIGPIPE while sending138* the request, or else the process will die from the signal139* and won't invoke the X error function to print a nice (?!)140* message.141*/142143void (*oldHandler)();144145oldHandler = (void (*)()) signal(SIGPIPE, SIG_IGN);146XNoOp(dispPtr->display);147XFlush(dispPtr->display);148(void) signal(SIGPIPE, oldHandler);149}150} else {151numFound = XQLength(dispPtr->display);152}153154/*155* Transfer events from the X event queue to the Tk event queue.156*/157158while (numFound > 0) {159XNextEvent(dispPtr->display, &event);160Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);161numFound--;162}163}164}165166/*167*----------------------------------------------------------------------168*169* TkCreateXEventSource --170*171* This procedure is called during Tk initialization to create172* the event source for X Window events.173*174* Results:175* None.176*177* Side effects:178* A new event source is created.179*180*----------------------------------------------------------------------181*/182183void184TkCreateXEventSource()185{186static int initialized = 0;187188if (!initialized) {189Tcl_CreateEventSource(DisplaySetupProc, DisplayCheckProc,190(ClientData) NULL);191initialized = 1;192}193}194195196