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