Index: /trunk/src/libs/xpcom18a4/python/src/module/_xpcom.cpp
===================================================================
--- /trunk/src/libs/xpcom18a4/python/src/module/_xpcom.cpp	(revision 22686)
+++ /trunk/src/libs/xpcom18a4/python/src/module/_xpcom.cpp	(revision 22687)
@@ -496,5 +496,117 @@
 static nsIEventQueue* g_mainEventQ = nsnull;
 
-static PyObject* 
+# ifdef RT_OS_DARWIN
+#  include <iprt/time.h>
+#  include <iprt/thread.h>
+#  include <iprt/err.h>
+#  include <CarbonEvents.h>
+
+// Wrapper that checks if the queue has pending events.
+DECLINLINE(bool)
+hasEventQueuePendingEvents(nsIEventQueue *pQueue)
+{
+	PRBool fHasEvents = PR_FALSE;
+	nsresult rc = pQueue->PendingEvents(&fHasEvents);
+	return NS_SUCCEEDED(rc) && fHasEvents ? true : false;
+}
+
+// Wrapper that checks if the queue has pending events.
+DECLINLINE(bool)
+isEventQueueNative(nsIEventQueue *pQueue)
+{
+	PRBool fIsNative = PR_FALSE;
+	nsresult rc = pQueue->IsQueueNative(&fIsNative);
+	return NS_SUCCEEDED(rc) && fIsNative ? true : false;
+}
+
+
+// Common fallback for waiting (and maybe processing) events. Caller process
+// any pending events when 0 is returned.
+static nsresult
+waitForEventsCommonFallback(nsIEventQueue *pQueue, PRInt32 cMsTimeout)
+{
+	if (cMsTimeout < 0) {
+		// WaitForEvent probably does the trick here.
+		PLEvent *pEvent = NULL;
+		nsresult rc = -1;
+		Py_BEGIN_ALLOW_THREADS;
+		rc = pQueue->WaitForEvent(&pEvent);
+		Py_END_ALLOW_THREADS;
+		if (NS_SUCCEEDED(rc)) {
+			pQueue->HandleEvent(pEvent);
+			return 0;
+		}
+	} else {
+		// Poll until time out or event is encountered. We have
+		// no other choice here.
+		uint64_t const StartMillTS = RTTimeMilliTS();
+		for (;;)
+		{
+			// Any pending events?
+			if (hasEventQueuePendingEvents(pQueue))
+				return 0;
+
+    			// Work any native per-thread event loops for good measure.
+#  ifdef RT_OS_DARWIN
+			RunCurrentEventLoop(0.0005 /*sec*/);
+#  endif
+
+			// Any pending events?
+			if (hasEventQueuePendingEvents(pQueue))
+				return 0;
+
+			// Timed out?
+			uint64_t cMsElapsed = RTTimeMilliTS() - StartMillTS;
+			if (cMsElapsed > (uint32_t)cMsTimeout)
+				break;
+
+			// Sleep a bit; return 0 if interrupt (see the select code edition).
+			uint32_t cMsLeft = (uint32_t)cMsTimeout - (uint32_t)cMsElapsed;
+			int rc = RTThreadSleep(RT_MIN(cMsLeft, 250));
+			if (rc == VERR_INTERRUPTED)
+				return 0;
+		}
+	}
+
+	return 1;
+}
+
+
+// Takes care of the waiting on darwin. Caller process any pending events when
+// 0 is returned.
+static nsresult
+waitForEventsOnDarwin(nsIEventQueue *pQueue, PRInt32 cMsTimeout)
+{
+	// This deals with the common case where the caller is the main
+	// application thread and the queue is a native one.
+    	if (	isEventQueueNative(pQueue)
+	    &&	GetCurrentEventLoop() == GetMainEventLoop()
+	) {
+    		OSStatus     orc       = -1;
+		EventTimeout rdTimeout = cMsTimeout < 0
+		                       ? kEventDurationForever
+		                       : (double)cMsTimeout / 1000;
+		Py_BEGIN_ALLOW_THREADS;
+		orc = RunCurrentEventLoop(rdTimeout);
+		Py_END_ALLOW_THREADS;
+		if (!orc || orc == eventLoopQuitErr)
+			return 0;
+
+		if (orc != eventLoopTimedOutErr) {
+			NS_WARNING("Unexpected status code from RunCurrentEventLoop");
+			RTThreadSleep(1); // throttle
+		}
+
+		return hasEventQueuePendingEvents(pQueue) ? 0 : 1;
+	}
+
+	// All native queus are driven by the main application loop... Use the
+	// fallback for now.
+	return waitForEventsCommonFallback(pQueue, cMsTimeout);
+}
+
+# endif /* RT_OS_DARWIN */
+
+static PyObject*
 PyXPCOMMethod_WaitForEvents(PyObject *self, PyObject *args)
 {
@@ -505,10 +617,21 @@
 
   nsIEventQueue* q = g_mainEventQ;
+  if (q == nsnull)
+    return NULL;
+
+  NS_WARN_IF_FALSE(isEventQueueNative(q), "The event queue must be native!");
+
+  PRInt32 result = 0;
+# ifdef RT_OS_DARWIN
+  if (aTimeout != 0 && !hasEventQueuePendingEvents(q))
+    result = waitForEventsOnDarwin(q, aTimeout);
+  if (result == 0)
+    q->ProcessPendingEvents();
+
+# else  /* !RT_OS_DARWIN */
+
   PRBool hasEvents = PR_FALSE;
   nsresult rc;
-  PRInt32 fd, result = 0;
-
-  if (q == nsnull) 
-    return NULL;
+  PRInt32 fd;
 
   if (aTimeout == 0)
@@ -521,5 +644,5 @@
   if (hasEvents)
     goto ok;
-  
+
   fd = q->GetEventQueueSelectFD();
   if (fd < 0 && aTimeout < 0)
@@ -537,18 +660,10 @@
   /* Cannot perform timed wait otherwise */
   if (fd < 0)
-#ifdef RT_OS_DARWIN
-      /** 
-       * @todo: maybe need some way to implement timed wait on Darwin,
-       *        just return immediately instead
-       */
-      goto ok;
-#else
       return NULL;
-#endif
-  
+
   {
     fd_set fdsetR, fdsetE;
     struct timeval tv;
-    
+
     FD_ZERO(&fdsetR);
     FD_SET(fd, &fdsetR);
@@ -560,5 +675,5 @@
         tv.tv_usec = ((PRInt64)aTimeout % 1000) * 1000;
       }
-    
+
     /** @todo: What to do for XPCOM platforms w/o select() ? */
     Py_BEGIN_ALLOW_THREADS;
@@ -569,4 +684,5 @@
  ok:
   q->ProcessPendingEvents();
+# endif /* !RT_OS_DARWIN */
 
   return PyInt_FromLong(result);
@@ -583,5 +699,5 @@
 }
 
-static PyObject* 
+static PyObject*
 PyXPCOMMethod_InterruptWait(PyObject *self, PyObject *args)
 {
@@ -610,5 +726,5 @@
 static void deinitVBoxPython();
 
-static PyObject* 
+static PyObject*
 PyXPCOMMethod_DeinitCOM(PyObject *self, PyObject *args)
 {
@@ -621,5 +737,5 @@
 static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
 
-static PyObject* 
+static PyObject*
 PyXPCOMMethod_AttachThread(PyObject *self, PyObject *args)
 {
@@ -653,5 +769,5 @@
 }
 
-static PyObject* 
+static PyObject*
 PyXPCOMMethod_DetachThread(PyObject *self, PyObject *args)
 {
@@ -684,5 +800,6 @@
     return PyInt_FromLong(result);
 }
-#endif
+
+#endif /* VBOX */
 
 extern PYXPCOM_EXPORT PyObject *PyXPCOMMethod_IID(PyObject *self, PyObject *args);
@@ -863,12 +980,13 @@
 }
 
-static 
+static
 void deinitVBoxPython()
 {
 
   if (g_mainEventQ)
-    NS_RELEASE(g_mainEventQ); 
-  
+    NS_RELEASE(g_mainEventQ);
+
   com::Shutdown();
 }
-#endif
+
+#endif /* VBOX_PYXPCOM */
