aboutsummaryrefslogtreecommitdiff
path: root/nx-X11/programs/Xserver/hw/nxagent/Handlers.c
diff options
context:
space:
mode:
Diffstat (limited to 'nx-X11/programs/Xserver/hw/nxagent/Handlers.c')
-rw-r--r--nx-X11/programs/Xserver/hw/nxagent/Handlers.c1272
1 files changed, 1272 insertions, 0 deletions
diff --git a/nx-X11/programs/Xserver/hw/nxagent/Handlers.c b/nx-X11/programs/Xserver/hw/nxagent/Handlers.c
new file mode 100644
index 000000000..dc9770c75
--- /dev/null
+++ b/nx-X11/programs/Xserver/hw/nxagent/Handlers.c
@@ -0,0 +1,1272 @@
+/**************************************************************************/
+/* */
+/* Copyright (c) 2001, 2007 NoMachine, http://www.nomachine.com/. */
+/* */
+/* NXAGENT, NX protocol compression and NX extensions to this software */
+/* are copyright of NoMachine. Redistribution and use of the present */
+/* software is allowed according to terms specified in the file LICENSE */
+/* which comes in the source distribution. */
+/* */
+/* Check http://www.nomachine.com/licensing.html for applicability. */
+/* */
+/* NX and NoMachine are trademarks of NoMachine S.r.l. */
+/* */
+/* All rights reserved. */
+/* */
+/**************************************************************************/
+
+#include "dixstruct.h"
+#include "scrnintstr.h"
+#include "windowstr.h"
+#include "osdep.h"
+
+#include "Agent.h"
+#include "Handlers.h"
+#include "Display.h"
+#include "Events.h"
+#include "Client.h"
+#include "Reconnect.h"
+#include "Dialog.h"
+#include "Drawable.h"
+#include "Splash.h"
+#include "Screen.h"
+#include "Millis.h"
+
+#include "NXlib.h"
+
+/*
+ * Set here the required log level.
+ */
+
+#define PANIC
+#define WARNING
+#undef TEST
+#undef DEBUG
+#undef DUMP
+
+/*
+ * Log begin and end of the important
+ * handlers.
+ */
+
+#undef BLOCKS
+
+/*
+ * If not defined, flush immediately
+ * upon entering the block handler.
+ */
+
+#define FLUSH_AFTER_MULTIPLE_READS
+
+/*
+ * Introduce a small delay after each
+ * loop if the session is down. The
+ * value is in milliseconds.
+ */
+
+#define LOOP_DELAY_IF_DOWN 50
+
+/*
+ * The soft limit should roughly match
+ * the size of the Xlib I/O buffer.
+ */
+
+#define BYTES_BEFORE_SOFT_TOKEN 2048
+#define BYTES_BEFORE_HARD_TOKEN 65536
+
+/*
+ * Maximum number of synchronization
+ * requests before waiting for the
+ * remote.
+ */
+
+#define TOKENS_PENDING_LIMIT 8
+
+/*
+ * Limits are very unobtrusive. We don't
+ * want to interfere with the normal
+ * dispatching.
+ */
+
+#define BYTES_BEFORE_YIELD 1048576
+#define TIME_BEFORE_YIELD 500
+
+/*
+ * Dinamically reduce the display buffer
+ * size after a congestion.
+ */
+
+#undef DYNAMIC_DISPLAY_BUFFER
+
+/*
+ * Minimum display buffer size.
+ */
+
+#define MINIMUM_DISPLAY_BUFFER 512
+
+/*
+ * Used in the handling of the X desktop
+ * manager protocol.
+ */
+
+int nxagentXdmcpUp = 0;
+int nxagentXdmcpAlertUp = 0;
+
+/*
+ * Also used in the block, wakeup and
+ * sync handlers.
+ */
+
+int nxagentBuffer;
+int nxagentBlocking;
+int nxagentCongestion;
+
+double nxagentBytesIn;
+double nxagentBytesOut;
+
+/*
+ * Total number of descriptors ready
+ * as reported by the wakeup handler.
+ */
+
+int nxagentReady;
+
+/*
+ * Timestamp of the last write to the
+ * remote display.
+ */
+
+int nxagentFlush;
+
+/*
+ * Arbitrate the bandwidth among our
+ * clients.
+ */
+
+struct _TokensRec nxagentTokens = { 0, 0, 0 };
+struct _DispatchRec nxagentDispatch = { UNDEFINED, 0, 0, 0 };
+
+/*
+ * Called just before blocking, waiting
+ * for our clients or the X server.
+ */
+
+void nxagentBlockHandler(pointer data, struct timeval **timeout, pointer mask)
+{
+ /*
+ * Zero timeout.
+ */
+
+ static struct timeval zero;
+
+ /*
+ * Current timestamp.
+ */
+
+ static int now;
+
+ /*
+ * Pending bytes to write to the
+ * network.
+ */
+
+ static int flushable;
+
+ /*
+ * Set if we need to synchronize
+ * any drawable.
+ */
+
+ static int synchronize;
+
+ #ifdef BLOCKS
+ fprintf(stderr, "[Begin block]\n");
+ #endif
+
+ now = GetTimeInMillis();
+
+ if (nxagentNeedConnectionChange() == 1)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentBlockHandler: Calling nxagentHandleConnectionChanges "
+ "with ioError [%d] sigHup [%d].\n", nxagentException.ioError, nxagentException.sigHup);
+ #endif
+
+ nxagentHandleConnectionChanges();
+ }
+
+ if (nxagentOption(Rootless) &&
+ nxagentLastWindowDestroyed && nxagentRootlessDialogPid == 0 &&
+ now > nxagentLastWindowDestroyedTime + 30 * 1000)
+ {
+ #ifdef WARNING
+ fprintf(stderr, "nxagentBlockHandler: No application running. Closing the session.\n");
+ #endif
+
+ nxagentTerminateSession();
+ }
+
+ #ifdef TEST
+
+ if (nxagentLastWindowDestroyed == 1)
+ {
+ fprintf(stderr, "nxagentBlockHandler: Elapsed time [%lu].\n",
+ now - nxagentLastWindowDestroyedTime);
+ }
+
+ #endif
+
+ /*
+ * Slow down the agent if the session is
+ * not connected to a valid display.
+ */
+
+ if (NXDisplayError(nxagentDisplay) == 1 && nxagentShadowCounter == 0)
+ {
+ usleep(LOOP_DELAY_IF_DOWN * 1000);
+
+ now = GetTimeInMillis();
+ }
+
+ /*
+ * Update the shadow display. This is
+ * only for test purposes.
+ */
+
+ #ifdef DUMP
+
+ nxagentPixmapOnShadowDisplay(NULL);
+
+ nxagentFbOnShadowDisplay();
+
+ #endif
+
+ /*
+ * We need this here because some window
+ * configuration changes can be generated
+ * by the X server outside the control of
+ * the DIX.
+ */
+
+ nxagentFlushConfigureWindow();
+
+ /*
+ * Check whether there is any drawable to
+ * synchronize.
+ */
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentBlockHandler: Checking synchronization at %s with "
+ "[%d][%d][%d].\n", GetTimeInMillisAsString(), nxagentCorruptedWindows,
+ nxagentCorruptedBackgrounds, nxagentCorruptedPixmaps);
+ #endif
+
+ synchronize = (nxagentCorruptedWindows > 0 ||
+ nxagentCorruptedBackgrounds > 0 ||
+ nxagentCorruptedPixmaps > 0);
+
+ /*
+ * The synchronization function requires a mask as
+ * parameter:
+ *
+ * EVENT_BREAK Breaks if an user input, like
+ * a key press or a mouse move,
+ * is detected.
+ *
+ * CONGESTION_BREAK Breaks if the congestion beco-
+ * mes greater than 4.
+ *
+ * BLOCKING_BREAK Breaks if the display descript-
+ * or becomes blocked for write
+ * during the loop.
+ *
+ * ALWAYS_BREAK Any of the previous conditions
+ * is met.
+ *
+ * NEVER_BREAK The loop continues until all
+ * the drawables are synchronized.
+ */
+
+ if (synchronize == 1)
+ {
+ /*
+ * We should not enter the synchronization
+ * loop if there is any user input pending,
+ * i.e. if we are in the middle of a scroll
+ * operation.
+ */
+
+ if (nxagentForceSynchronization == 1)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentBlockHandler: Going to force a synchronization at %s.\n",
+ GetTimeInMillisAsString());
+ #endif
+
+ nxagentSynchronizationLoop(NEVER_BREAK);
+
+ nxagentForceSynchronization = 0;
+ }
+ else if (nxagentUserInput(NULL) == 0 &&
+ nxagentBlocking == 0 &&
+ nxagentCongestion <= 4)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentBlockHandler: Going to synchronize at %s.\n",
+ GetTimeInMillisAsString());
+ #endif
+
+ nxagentSynchronizationLoop(ALWAYS_BREAK);
+ }
+ #ifdef TEST
+ else
+ {
+ fprintf(stderr, "nxagentBlockHandler: Not synchronizing with [%d][%d].\n",
+ nxagentBlocking, nxagentCongestion);
+ }
+ #endif
+
+ /*
+ * Check if we have more corrupted resources
+ * and whether the conditions are satisfied
+ * to continue with the synchronization.
+ */
+
+ synchronize = (nxagentCongestion <= 4 &&
+ (nxagentCorruptedWindows > 0 ||
+ nxagentCorruptedBackgrounds > 0 ||
+ nxagentCorruptedPixmaps > 0));
+
+ if (synchronize == 1)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentBlockHandler: Setting a zero timeout with [%d][%d][%d] and "
+ "congestion [%d].\n", nxagentCorruptedWindows, nxagentCorruptedBackgrounds,
+ nxagentCorruptedPixmaps, nxagentCongestion);
+ #endif
+
+ zero.tv_sec = 0;
+ zero.tv_usec = 0;
+
+ *timeout = &zero;
+ }
+ #ifdef TEST
+ else
+ {
+ if (nxagentCorruptedWindows == 0 &&
+ nxagentCorruptedBackgrounds == 0 &&
+ nxagentCorruptedPixmaps == 0)
+ {
+ fprintf(stderr, "nxagentBlockHandler: Nothing more to synchronize at %s.\n",
+ GetTimeInMillisAsString());
+ }
+ else
+ {
+ fprintf(stderr, "nxagentBlockHandler: Delaying synchronization with [%d][%d][%d] and "
+ "congestion [%d].\n", nxagentCorruptedWindows, nxagentCorruptedBackgrounds,
+ nxagentCorruptedPixmaps, nxagentCongestion);
+ }
+ }
+ #endif
+ }
+
+ /*
+ * If the remote X server is blocking, reduce the
+ * amount of data sent in a single display update
+ * by reducing the size of the display buffer.
+ */
+
+ #ifdef DYNAMIC_DISPLAY_BUFFER
+
+ if (nxagentBlocking == 1 &&
+ nxagentBuffer > MINIMUM_DISPLAY_BUFFER)
+ {
+ nxagentBuffer >>= 1;
+
+ if (nxagentBuffer < MINIMUM_DISPLAY_BUFFER)
+ {
+ nxagentBuffer = MINIMUM_DISPLAY_BUFFER;
+ }
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchHandler: Reducing the display buffer to [%d] bytes.\n",
+ nxagentBuffer);
+ #endif
+
+ NXSetDisplayBuffer(nxagentDisplay, nxagentBuffer);
+ }
+ else if (nxagentBuffer < nxagentOption(DisplayBuffer) &&
+ nxagentCongestion == 0)
+ {
+ nxagentBuffer = nxagentOption(DisplayBuffer);
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchHandler: Increasing the display buffer to [%d] bytes.\n",
+ nxagentBuffer);
+ #endif
+
+ NXSetDisplayBuffer(nxagentDisplay, nxagentBuffer);
+ }
+
+ #endif /* #ifdef DYNAMIC_DISPLAY_BUFFER */
+
+ /*
+ * Dispatch to the clients the events that
+ * may have become available.
+ */
+
+ if (nxagentPendingEvents(nxagentDisplay) > 0)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentBlockHandler: Reading the events available.\n");
+ #endif
+
+ nxagentDispatchEvents(NULL);
+ }
+
+ /*
+ * Check if there is any data remaining,
+ * either in the display buffer or in
+ * the NX transport.
+ */
+
+ flushable = NXDisplayFlushable(nxagentDisplay);
+
+ if (flushable > 0)
+ {
+ #ifdef FLUSH_AFTER_MULTIPLE_READS
+
+ /*
+ * Flush all the outstanding data if
+ * the wakeup handler didn't detect
+ * any activity.
+ */
+
+ if (nxagentReady == 0 || now - nxagentFlush >=
+ nxagentOption(DisplayCoalescence))
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentBlockHandler: Flushing the display with [%d] bytes to flush.\n",
+ flushable);
+ #endif
+
+ NXFlushDisplay(nxagentDisplay, NXFlushLink);
+
+ /*
+ * New events may have become available
+ * after the flush.
+ */
+
+ if (nxagentPendingEvents(nxagentDisplay) > 0)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentBlockHandler: Reading the events available.\n");
+ #endif
+
+ nxagentDispatchEvents(NULL);
+ }
+ }
+ else
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentBlockHandler: Delaying flush with [%d][%d] and [%d] bytes.\n",
+ synchronize, nxagentReady, flushable);
+ #endif
+
+ zero.tv_sec = 0;
+ zero.tv_usec = 0;
+
+ *timeout = &zero;
+ }
+
+ #else /* #ifdef FLUSH_AFTER_MULTIPLE_READS */
+
+ /*
+ * We are entering the select. Tell the NX
+ * transport to write any produced data to
+ * the remote end.
+ */
+
+ NXFlushDisplay(nxagentDisplay, NXFlushLink);
+
+ if (nxagentPendingEvents(nxagentDisplay) > 0)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentBlockHandler: Reading the events available.\n");
+ #endif
+
+ nxagentDispatchEvents(NULL);
+ }
+
+ #endif /* #ifdef FLUSH_AFTER_MULTIPLE_READS */
+ }
+ else
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentBlockHandler: Nothing to flush with [%d][%d].\n",
+ synchronize, nxagentReady);
+ #endif
+
+ if (nxagentQueuedEvents(nxagentDisplay) > 0)
+ {
+ #ifdef WARNING
+ fprintf(stderr, "nxagentBlockHandler: WARNING! Forcing a null timeout with events queued.\n");
+ #endif
+
+ zero.tv_sec = 0;
+ zero.tv_usec = 0;
+
+ *timeout = &zero;
+ }
+ }
+
+ /*
+ * WaitForSomething() sets a zero timeout if there
+ * are clients with input, but doesn't stop the
+ * timer. The select is then interrupted to update
+ * the schedule time even if, what the dispatcher
+ * cares, is only the number of ticks at the time
+ * the client is scheduled in.
+ */
+
+ #ifdef SMART_SCHEDULE
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentBlockHandler: Stopping the smart schedule timer.\n");
+ #endif
+
+ nxagentStopTimer();
+
+ #endif
+
+ #ifdef BLOCKS
+ fprintf(stderr, "[End block]\n");
+ #endif
+}
+
+void nxagentWakeupHandler(pointer data, int count, pointer mask)
+{
+ #ifdef BLOCKS
+ fprintf(stderr, "[Begin wakeup]\n");
+ #endif
+
+ if (nxagentException.sigHup || nxagentException.ioError)
+ {
+ #ifdef TEST
+ fprintf(stderr,"nxagentWakeupHandler: Got SIGHUP or I/O error.\n");
+ #endif
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentBlockHandler: Calling nxagentHandleConnectionStates "
+ "with ioError [%d] sigHup [%d].\n", nxagentException.ioError, nxagentException.sigHup);
+ #endif
+
+ nxagentHandleConnectionStates();
+ }
+
+ #ifdef SMART_SCHEDULE
+
+ if (SmartScheduleDisable == 1)
+ {
+
+ #endif
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentWakeupHandler: Resetting the dispatch state after wakeup.\n");
+ #endif
+
+ nxagentDispatch.start = GetTimeInMillis();
+
+ nxagentDispatch.in = nxagentBytesIn;
+ nxagentDispatch.out = nxagentBytesOut;
+
+ #ifdef SMART_SCHEDULE
+
+ }
+
+ #endif
+
+ /*
+ * Can become true during the dispatch loop.
+ */
+
+ nxagentBlocking = 0;
+
+ /*
+ * Check if we got new events.
+ */
+
+ if (count > 0 && FD_ISSET(nxagentXConnectionNumber, (fd_set *) mask))
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentWakeupHandler: Reading the X events with count [%d].\n",
+ count);
+ #endif
+
+ nxagentDispatchEvents(NULL);
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentWakeupHandler: Removing the X descriptor from the count.\n");
+ #endif
+
+ FD_CLR(nxagentXConnectionNumber, (fd_set *) mask);
+
+ count--;
+ }
+ else if (nxagentQueuedEvents(nxagentDisplay) == 1)
+ {
+ /*
+ * We may have left some events in
+ * the queue.
+ */
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentWakeupHandler: Reading the queued X events with count [%d].\n",
+ count);
+ #endif
+
+ nxagentDispatchEvents(NULL);
+ }
+
+ /*
+ * Save the number of descriptors ready.
+ */
+
+ if (count <= 0)
+ {
+ count = (XFD_ANYSET(&ClientsWithInput) ? 1 : 0);
+ }
+
+ nxagentReady = count;
+
+ #ifdef TEST
+
+ if (nxagentReady == 0)
+ {
+ fprintf(stderr, "nxagentWakeupHandler: No X clients found to be processed.\n");
+ }
+
+ #endif
+
+ /*
+ * If the XDM connection can't be established
+ * we'll need to create a dialog to notify the
+ * user and give him/her a chance to terminate
+ * the session.
+ */
+
+ if (nxagentOption(Xdmcp) == 1 && nxagentXdmcpUp == 0)
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentWakeupHandler: XdmcpState [%d].\n", XdmcpState);
+ #endif
+
+ if (XdmcpState == XDM_RUN_SESSION)
+ {
+ nxagentXdmcpUp = 1;
+ }
+
+ if (nxagentXdmcpUp == 0)
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentWakeupHandler: XdmcpTime [%lu].\n",
+ GetTimeInMillis() - XdmcpStartTime);
+ #endif
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentWakeupHandler: XdmcpTimeOutRtx [%d].\n",
+ XdmcpTimeOutRtx);
+ #endif
+
+ if (nxagentXdmcpAlertUp == 0 &&
+ GetTimeInMillis() - XdmcpStartTime >= XDM_TIMEOUT)
+ {
+ #ifdef WARNING
+ fprintf(stderr, "nxagentWakeupHandler: WARNING! The XDM session seems to be "
+ "unable to start after [%ld] ms.\n",(long int)(GetTimeInMillis() - XdmcpStartTime));
+ #endif
+
+ NXTransAlert(FAILED_XDMCP_CONNECTION_ALERT, NX_ALERT_REMOTE);
+
+ nxagentXdmcpAlertUp = 1;
+ }
+ }
+ }
+
+ #ifdef BLOCKS
+ fprintf(stderr, "[End wakeup]\n");
+ #endif
+}
+
+void nxagentShadowBlockHandler(pointer data, struct timeval **timeout, pointer mask)
+{
+ static struct timeval zero;
+
+ int changed;
+ int suspended = 0;
+ int result;
+
+ #ifdef BLOCKS
+ fprintf(stderr, "[Begin block]\n");
+ #endif
+
+ if (nxagentNeedConnectionChange() == 1)
+ {
+ nxagentHandleConnectionChanges();
+ }
+
+ if (nxagentSessionState == SESSION_DOWN)
+ {
+ usleep(50 * 1000);
+ }
+
+ #ifndef __CYGWIN32__
+
+ if (nxagentReadEvents(nxagentDisplay) > 0 ||
+ nxagentReadEvents(nxagentShadowDisplay) > 0)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentShadowBlockHandler: Reading X events queued.\n");
+ #endif
+
+ nxagentDispatchEvents(NULL);
+ }
+
+ if (nxagentShadowResize == 1)
+ {
+ nxagentShadowResize = 0;
+
+ nxagentShadowAdaptToRatio();
+ }
+
+ #else
+
+ if (nxagentReadEvents(nxagentDisplay) > 0)
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentShadowBlockHandler: Reading X events queued.\n");
+ #endif
+
+ nxagentDispatchEvents(NULL);
+ }
+
+ #endif
+
+ changed = 0;
+
+ nxagentShadowPoll(nxagentShadowPixmapPtr, nxagentShadowGCPtr, nxagentShadowDepth, nxagentShadowWidth,
+ nxagentShadowHeight, nxagentShadowBuffer, &changed, &suspended);
+
+ result = nxagentShadowSendUpdates(&suspended);
+
+ if (nxagentBlocking == 0)
+ {
+ nxagentSynchronizeDrawable((DrawablePtr) nxagentShadowPixmapPtr, DONT_WAIT,
+ ALWAYS_BREAK, nxagentShadowWindowPtr);
+ }
+
+ /*
+ * We are entering the select. Tell the NX
+ * transport to write any produced data to
+ * the remote end.
+ */
+/*
+FIXME: Must queue multiple writes and handle
+ the events by resembling the ordinary
+ block handler.
+*/
+
+ NXFlushDisplay(nxagentDisplay, NXFlushLink);
+
+ if (*timeout == NULL)
+ {
+ *timeout = &zero;
+ }
+
+ #ifdef __CYGWIN32__
+
+ usleep(50 * 1000);
+
+ (*timeout) -> tv_sec = 0;
+ (*timeout) -> tv_usec = 50 * 1000;
+
+ #else
+
+ if (changed == 0)
+ {
+ (*timeout) -> tv_sec = 0;
+ (*timeout) -> tv_usec = 50 * 1000;
+ }
+ else
+ {
+ (*timeout) -> tv_sec = 0;
+ (*timeout) -> tv_usec = 0;
+ }
+
+ #endif
+
+ #ifdef BLOCKS
+ fprintf(stderr, "[End block]\n");
+ #endif
+}
+
+void nxagentShadowWakeupHandler(pointer data, int count, pointer mask)
+{
+ #ifdef BLOCKS
+ fprintf(stderr, "[Begin wakeup]\n");
+ #endif
+
+ if (nxagentException.sigHup || nxagentException.ioError)
+ {
+ #ifdef TEST
+ fprintf(stderr,"nxagentShadowWakeupHandler: Got SIGHUP or I/O error.\n");
+ #endif
+
+ nxagentHandleConnectionStates();
+ }
+
+ #ifdef SMART_SCHEDULE
+
+ if (SmartScheduleDisable == 1)
+ {
+
+ #endif
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentShadowWakeupHandler: Resetting the dispatch state after wakeup.\n");
+ #endif
+
+ nxagentDispatch.start = GetTimeInMillis();
+
+ nxagentDispatch.in = nxagentBytesIn;
+ nxagentDispatch.out = nxagentBytesOut;
+
+ #ifdef SMART_SCHEDULE
+
+ }
+
+ #endif
+
+ /*
+ * Can become true during the dispatch loop.
+ */
+
+ nxagentBlocking = 0;
+
+ /*
+ * Check if we got new events.
+ */
+
+ if (count > 0 && FD_ISSET(nxagentXConnectionNumber, (fd_set *) mask))
+ {
+ #ifdef TEST
+ fprintf(stderr, "nxagentShadowWakeupHandler: Reading the X events with count [%d].\n",
+ count);
+ #endif
+
+ nxagentDispatchEvents(NULL);
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentShadowWakeupHandler: Removing the X descriptor from the count.\n");
+ #endif
+
+ FD_CLR(nxagentXConnectionNumber, (fd_set *) mask);
+
+ count--;
+ }
+ else if (nxagentQueuedEvents(nxagentDisplay) == 1)
+ {
+ /*
+ * We may have left some events in
+ * the queue.
+ */
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentShadowWakeupHandler: Reading the queued X events with count [%d].\n",
+ count);
+ #endif
+
+ nxagentDispatchEvents(NULL);
+ }
+
+ /*
+ * Save the number of descriptors ready.
+ */
+
+ if (count <= 0)
+ {
+ count = (XFD_ANYSET(&ClientsWithInput) ? 1 : 0);
+ }
+
+ nxagentReady = count;
+
+ #ifdef TEST
+
+ if (nxagentReady == 0)
+ {
+ fprintf(stderr, "nxagentShadowWakeupHandler: No X clients found to be processed.\n");
+ }
+
+ #endif
+
+ #ifdef BLOCKS
+ fprintf(stderr, "[End wakeup]\n");
+ #endif
+}
+
+void nxagentHandleCollectInputFocusEvent(int resource)
+{
+ Window window;
+ int revert_to;
+
+ if (NXGetCollectedInputFocus(nxagentDisplay, resource, &window, &revert_to) == 0)
+ {
+ #ifdef PANIC
+ fprintf(stderr, "nxagentHandleCollectInputFocusEvent: PANIC! Failed to get the input focus "
+ "reply for resource [%d].\n", resource);
+ #endif
+ }
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentHandleCollectInputFocusEvent: Received a sync reply with [%d] pending.\n",
+ nxagentTokens.pending);
+ #endif
+
+ nxagentTokens.pending--;
+
+ nxagentCongestion = (nxagentTokens.pending >= TOKENS_PENDING_LIMIT / 2);
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentHandleCollectInputFocusEvent: Current congestion level is [%d].\n",
+ nxagentCongestion);
+ #endif
+}
+
+Bool nxagentCollectInputFocusPredicate(Display *display, XEvent *X, XPointer ptr)
+{
+ return (X -> xclient.window == 0 &&
+ X -> xclient.message_type == 0 &&
+ X -> xclient.format == 32 &&
+ X -> xclient.data.l[0] == NXCollectInputFocusNotify);
+}
+
+void nxagentDispatchHandler(ClientPtr client, int in, int out)
+{
+ /*
+ * This function is called by the dispatcher (with 0
+ * bytes out) after a new request has been processed.
+ * It is also called by the write handler (with 0
+ * bytes in) after more data has been written to the
+ * display. It may be optionally called in the block
+ * and wakeup handlers. In this case both in and out
+ * must be 0.
+ */
+
+ if (out > 0)
+ {
+ /*
+ * Called by the display write callback.
+ */
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentDispatchHandler: Called with [%d] bytes written.\n",
+ out);
+ #endif
+
+ nxagentBytesOut += out;
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentDispatchHandler: Total bytes are [%.0f] in [%.0f] out.\n",
+ nxagentBytesIn, nxagentBytesOut);
+ #endif
+
+ /*
+ * Don't take care of the synchronization if
+ * the NX transport is running. The NX trans-
+ * port has its own token-based control flow.
+ *
+ * We can't produce more output here because
+ * we are in the middle of the flush. We will
+ * take care of the sync requests when called
+ * by the dispatcher.
+ */
+
+ if (nxagentOption(LinkType) == LINK_TYPE_NONE)
+ {
+ nxagentTokens.soft += out;
+
+ if (out > BYTES_BEFORE_HARD_TOKEN)
+ {
+ nxagentTokens.hard += out;
+ }
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentDispatchHandler: Sync bytes accumulated are [%d] and [%d].\n",
+ nxagentTokens.soft, nxagentTokens.hard);
+ #endif
+ }
+
+ #ifdef SMART_SCHEDULE
+
+ if (SmartScheduleDisable == 1)
+ {
+
+ #endif
+
+ /*
+ * Pay attention to the next client if this
+ * client produced enough output.
+ */
+
+ if (nxagentBytesOut - nxagentDispatch.out > BYTES_BEFORE_YIELD)
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentDispatchHandler: Yielding with [%ld][%.0f][%.0f] for client [%d].\n",
+ GetTimeInMillis() - nxagentDispatch.start, nxagentBytesIn - nxagentDispatch.in,
+ nxagentBytesOut - nxagentDispatch.out, nxagentDispatch.client);
+ #endif
+
+ nxagentDispatch.start = GetTimeInMillis();
+
+ nxagentDispatch.in = nxagentBytesIn;
+ nxagentDispatch.out = nxagentBytesOut;
+
+ isItTimeToYield = 1;
+ }
+ #ifdef DEBUG
+ else
+ {
+ fprintf(stderr, "nxagentDispatchHandler: Dispatching with [%ld][%.0f][%.0f] for client [%d].\n",
+ GetTimeInMillis() - nxagentDispatch.start, nxagentBytesIn - nxagentDispatch.in,
+ nxagentBytesOut - nxagentDispatch.out, nxagentDispatch.client);
+ }
+ #endif
+
+ #ifdef SMART_SCHEDULE
+
+ }
+
+ #endif
+
+ return;
+ }
+ else if (in > 0)
+ {
+ /*
+ * Called by the dispatcher.
+ */
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentDispatchHandler: Called with [%d] bytes processed for client [%d].\n",
+ in, client -> index);
+ #endif
+
+ /*
+ * This is presently unused.
+ *
+ * nxagentClientAddBytes(client, in);
+ *
+ * #ifdef DEBUG
+ * fprintf(stderr, "nxagentDispatchHandler: Bytes processed for client [%d] are [%ld].\n",
+ * client -> index, nxagentClientBytes(client));
+ * #endif
+ *
+ */
+
+ nxagentBytesIn += in;
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentDispatchHandler: Total bytes are [%.0f] in [%.0f] out.\n",
+ nxagentBytesIn, nxagentBytesOut);
+ #endif
+
+ /*
+ * When using the dumb scheduler, before reading from
+ * another client, the dispatcher tries to drain all
+ * the input from the client being processed. This
+ * means that, if isItTimeToYield is never set and the
+ * client never produces any output, we'll stick into
+ * the inner dispatch loop forever.
+ */
+
+ #ifdef SMART_SCHEDULE
+
+ if (SmartScheduleDisable == 1)
+ {
+
+ #endif
+
+ if (client -> index != nxagentDispatch.client)
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentDispatchHandler: Resetting the dispatch state with [%d][%d].\n",
+ nxagentDispatch.client, client -> index);
+ #endif
+
+ nxagentDispatch.client = client -> index;
+ nxagentDispatch.start = GetTimeInMillis();
+
+ nxagentDispatch.in = nxagentBytesIn;
+ nxagentDispatch.out = nxagentBytesOut;
+ }
+ else
+ {
+ static unsigned long int now;
+
+ now = GetTimeInMillis();
+
+ if (now - nxagentDispatch.start > TIME_BEFORE_YIELD ||
+ nxagentBytesIn - nxagentDispatch.in > BYTES_BEFORE_YIELD)
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentDispatchHandler: Yielding with [%ld][%.0f][%.0f] for client [%d].\n",
+ now - nxagentDispatch.start, nxagentBytesIn - nxagentDispatch.in, nxagentBytesOut -
+ nxagentDispatch.out, nxagentDispatch.client);
+ #endif
+
+ nxagentDispatch.start = now;
+
+ nxagentDispatch.in = nxagentBytesIn;
+ nxagentDispatch.out = nxagentBytesOut;
+
+ isItTimeToYield = 1;
+ }
+ #ifdef DEBUG
+ else
+ {
+ fprintf(stderr, "nxagentDispatchHandler: Dispatching with [%ld][%.0f][%.0f] for client [%d].\n",
+ now - nxagentDispatch.start, nxagentBytesIn - nxagentDispatch.in, nxagentBytesOut -
+ nxagentDispatch.out, nxagentDispatch.client);
+ }
+ #endif
+ }
+
+ #ifdef SMART_SCHEDULE
+
+ }
+
+ #endif
+
+ }
+
+ /*
+ * Let's see if it's time to sync.
+ */
+
+ if (nxagentOption(LinkType) == LINK_TYPE_NONE)
+ {
+ if (nxagentTokens.hard > BYTES_BEFORE_HARD_TOKEN)
+ {
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentDispatchHandler: Requesting a hard sync reply with [%d] bytes.\n",
+ nxagentTokens.hard);
+ #endif
+
+ XSync(nxagentDisplay, 0);
+
+ if (nxagentPendingEvents(nxagentDisplay) > 0)
+ {
+ nxagentDispatchEvents(NULL);
+ }
+
+ nxagentTokens.soft = 0;
+ nxagentTokens.hard = 0;
+ }
+ else if (nxagentTokens.soft > BYTES_BEFORE_SOFT_TOKEN)
+ {
+ /*
+ * Alternatively, the amounts of bytes
+ * accounted for each sync request may
+ * be decreased according to the number
+ * of pending replies already awaited.
+ *
+ * else if (nxagentTokens.soft > (BYTES_BEFORE_SOFT_TOKEN / (nxagentTokens.pending + 1)))
+ */
+
+ int resource;
+
+ /*
+ * Wait eventually for the number of
+ * synchronization requests to return
+ * below the limit.
+ */
+
+ #ifdef TEST
+
+ if (nxagentTokens.pending == TOKENS_PENDING_LIMIT)
+ {
+ fprintf(stderr, "nxagentDispatchHandler: WARNING! Waiting for the synchronization reply.\n");
+ }
+
+ #endif
+
+ while (nxagentTokens.pending == TOKENS_PENDING_LIMIT)
+ {
+ if (nxagentWaitEvents(nxagentDisplay, NULL) == -1)
+ {
+ nxagentTokens.pending = 0;
+
+ nxagentTokens.soft = 0;
+
+ return;
+ }
+
+ nxagentDispatchEvents(NULL);
+
+ nxagentBlocking = 1;
+ }
+
+ /*
+ * Send a new synchronization request.
+ */
+
+ resource = nxagentWaitForResource(NXGetCollectInputFocusResource,
+ nxagentCollectInputFocusPredicate);
+
+ if (resource == -1)
+ {
+ #ifdef PANIC
+ fprintf(stderr, "nxagentDispatchHandler: PANIC! Cannot allocate any valid resource.\n");
+ #endif
+
+ nxagentTokens.soft = 0;
+
+ return;
+ }
+
+ #ifdef DEBUG
+ fprintf(stderr, "nxagentDispatchHandler: Requesting a sync reply with [%d] bytes "
+ "and [%d] pending.\n", nxagentTokens.soft, nxagentTokens.pending);
+ #endif
+
+ NXCollectInputFocus(nxagentDisplay, resource);
+
+ NXFlushDisplay(nxagentDisplay, NXFlushBuffer);
+
+ if (nxagentPendingEvents(nxagentDisplay) > 0)
+ {
+ nxagentDispatchEvents(NULL);
+ }
+
+ nxagentTokens.pending++;
+
+ nxagentCongestion = (nxagentTokens.pending >= TOKENS_PENDING_LIMIT / 2);
+
+ #ifdef TEST
+ fprintf(stderr, "nxagentDispatchHandler: Current congestion level is [%d].\n",
+ nxagentCongestion);
+ #endif
+
+ nxagentTokens.soft = 0;
+ }
+ }
+
+ /*
+ * Check if there are events to read.
+ */
+
+ if (nxagentPendingEvents(nxagentDisplay) > 0)
+ {
+ nxagentDispatchEvents(NULL);
+ }
+}