Index: /trunk/include/VBox/com/EventQueue.h
===================================================================
--- /trunk/include/VBox/com/EventQueue.h	(revision 22846)
+++ /trunk/include/VBox/com/EventQueue.h	(revision 22847)
@@ -91,8 +91,29 @@
     BOOL handleEvent (Event *event);
     static int processThreadEventQueue(uint32_t cMsTimeout, bool (*pfnExitCheck)(void *pvUser) = 0,
-                                       void *pvUser = 0, uint32_t cMsPollInterval = 1000,
-                                       bool fReturnOnEvent = true);
+                                     void *pvUser = 0, uint32_t cMsPollInterval = 1000,
+                                     bool fReturnOnEvent = true);
+    /**
+     * Process events pending on this event queue, and wait 
+     * up to given timeout, if nothing is available.
+     * Must be called on same thread this event queue was created on.
+     */
+    int processEventQueue(uint32_t cMsTimeout);
+    /**
+     * Interrupt thread waiting on event queue processing.
+     * Can be called on any thread.
+     */
+    int interruptEventQueueProcessing();
+    /** 
+     * Initialize/deinitialize event queues.
+     */
+    static int init();
+    static int deinit();
+    /**
+     * Get main event queue instance.
+     */
+    static EventQueue* getMainEventQueue();
 
 private:
+    static EventQueue* mMainQueue;
 
 #if !defined (VBOX_WITH_XPCOM)
Index: /trunk/src/VBox/Main/glue/EventQueue.cpp
===================================================================
--- /trunk/src/VBox/Main/glue/EventQueue.cpp	(revision 22846)
+++ /trunk/src/VBox/Main/glue/EventQueue.cpp	(revision 22847)
@@ -69,4 +69,6 @@
 
 #endif // !defined (RT_OS_WINDOWS)
+
+EventQueue* EventQueue::mMainQueue = NULL;
 
 /**
@@ -146,4 +148,210 @@
 }
 
+/* static */ int EventQueue::init()
+{
+    mMainQueue = new EventQueue();
+#if defined (VBOX_WITH_XPCOM)
+    nsCOMPtr<nsIEventQueue> q;
+    nsresult rv = NS_GetMainEventQ(getter_AddRefs(q));
+    Assert(NS_SUCCEEDED(rv));
+    Assert(q == mMainQueue->mEventQ);
+    PRBool fIsNative = PR_FALSE;
+    rv = mMainQueue->mEventQ->IsQueueNative(&fIsNative);
+    Assert(NS_SUCCEEDED(rv) && fIsNative);
+#endif
+    return VINF_SUCCESS;
+}
+
+/* static */ int EventQueue::deinit()
+{
+    delete mMainQueue;
+    mMainQueue = NULL;
+    return VINF_SUCCESS;
+}
+
+/* static */ EventQueue* EventQueue::getMainEventQueue()
+{
+    return mMainQueue;
+}
+
+#ifdef RT_OS_DARWIN
+static int
+timedWaitForEventsOnDarwin(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.
+  OSStatus       orc       = -1;
+  CFTimeInterval rdTimeout = (double)cMsTimeout / 1000;
+  orc = CFRunLoopRunInMode(kCFRunLoopDefaultMode, rdTimeout, true /*returnAfterSourceHandled*/);
+  if (orc == kCFRunLoopRunHandledSource)
+    orc = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, false /*returnAfterSourceHandled*/);
+  if (!orc || orc == kCFRunLoopRunHandledSource)
+    return VINF_SUCCESS;
+
+  if (orc != kCFRunLoopRunTimedOut) 
+  {
+      NS_WARNING("Unexpected status code from CFRunLoopRunInMode");
+  }
+
+  return VERR_TIMEOUT;
+}
+#endif
+
+#ifdef RT_OS_WINDOWS
+static int
+processPendingEventsOnWindows()
+{
+    MSG Msg;
+    int rc = VERR_TIMEOUT;
+    while (PeekMessage(&Msg, NULL /*hWnd*/, 0 /*wMsgFilterMin*/, 0 /*wMsgFilterMax*/, PM_REMOVE))
+    {
+        if (Msg.message == WM_QUIT)
+            rc = VERR_INTERRUPTED;
+        DispatchMessage(&Msg);
+        if (rc == VERR_INTERRUPTED)
+            break;
+        rc = VINF_SUCCESS; 
+    }    
+    return rc;
+}
+/** For automatic cleanup,   */
+class MyThreadHandle
+{
+public:
+  HANDLE mh;
+  
+  MyThreadHandle()
+  {
+    if (!DuplicateHandle(GetCurrentProcess(), 
+                         GetCurrentThread(), 
+                         GetCurrentProcess(),
+                         &mh, 
+                         0 /*dwDesiredAccess*/, 
+                         FALSE /*bInheritHandle*/,
+                         DUPLICATE_SAME_ACCESS))
+      mh = INVALID_HANDLE_VALUE;
+  }
+
+  ~MyThreadHandle()
+  {
+    CloseHandle(mh);
+    mh = INVALID_HANDLE_VALUE;
+  }
+};
+#endif
+#include <stdio.h>
+int EventQueue::processEventQueue(uint32_t cMsTimeout)
+{
+    int rc = VINF_SUCCESS;
+#if defined (VBOX_WITH_XPCOM)
+    do {
+      PRBool fHasEvents = PR_FALSE;
+      nsresult rc;
+      
+      rc = mEventQ->PendingEvents(&fHasEvents);
+      if (NS_FAILED (rc))
+          return VERR_INTERNAL_ERROR_3;
+
+      if (fHasEvents || cMsTimeout == 0)
+          break;
+
+      /**
+       * Unfortunately, WaitForEvent isn't interruptible with Ctrl-C,
+       * while select() is.
+       */
+
+      if (cMsTimeout == RT_INDEFINITE_WAIT)
+      {
+#if 0
+          PLEvent *pEvent = NULL;
+          int rc1 = mEventQ->WaitForEvent(&pEvent);
+          if (NS_FAILED(rc1) || pEvent == NULL)
+          {
+                rc = VERR_INTERRUPTED;
+                break;
+          }
+          mEventQ->HandleEvent(pEvent);
+          break;
+#else
+          /* Pretty close to forever */
+          cMsTimeout = 0xffff0000;
+#endif
+      }
+      
+      /* Bit tricky part - perform timed wait */
+#  ifdef RT_OS_DARWIN
+      rc = timedWaitForEventsOnDarwin(mEventQ, cMsTimeout);
+#  else
+      int fd = mEventQ->GetEventQueueSelectFD();
+      fd_set fdsetR, fdsetE;
+      struct timeval tv;
+      
+      FD_ZERO(&fdsetR);
+      FD_SET(fd, &fdsetR);
+      
+      fdsetE = fdsetR;
+      tv.tv_sec = (PRInt64)cMsTimeout / 1000;
+      tv.tv_usec = ((PRInt64)cMsTimeout % 1000) * 1000;
+
+      int aCode = select(fd + 1, &fdsetR, NULL, &fdsetE, &tv);
+      if (aCode == 0)
+        rc = VERR_TIMEOUT;
+      else if (aCode == EINTR)
+        rc = VERR_INTERRUPTED;
+      else if (aCode < 0)
+        rc = VERR_INTERNAL_ERROR_4;
+      
+#  endif      
+    } while (0);
+
+    mEventQ->ProcessPendingEvents();
+#else /* Windows */
+    do {
+        int aCode = processPendingEventsOnWindows();
+        if (aCode != VERR_TIMEOUT || cMsTimeout == 0)
+        {
+            rc = aCode;
+            break;
+        }
+        
+        if (cMsTimeout == RT_INDEFINITE_WAIT)
+        {
+            Event* aEvent = NULL;
+          
+            fHasEvent = waitForEvent(&aEvent);
+            if (fHasEvent)
+              handleEvent(aEvent);
+            else
+              rc = VERR_INTERRUPTED;
+            break;
+        }
+
+        /* Perform timed wait */
+        MyThreadHandle aHandle;
+
+        DWORD aCode = MsgWaitForMultipleObjects(1, &aHandle.mh, 
+                                             TRUE /*fWaitAll*/, 
+                                             0 /*ms*/, 
+                                             QS_ALLINPUT);
+        if (aCode == WAIT_TIMEOUT)
+            rc = VERR_TIMEOUT;
+        else if (aCode == WAIT_OBJECT_0)
+            rc = VINF_SUCCESS;
+        else
+            rc = VERR_INTERNAL_ERROR_4;
+    } while (0);
+
+    processPendingEventsOnWindows();
+#endif
+    return rc;
+
+}
+
+int EventQueue::interruptEventQueueProcessing()
+{
+    postEvent(NULL);
+    return VINF_SUCCESS;
+}
+
 /**
  *  Posts an event to this event loop asynchronously.
@@ -287,25 +495,4 @@
 
 #else
-
-/** For automatic cleanup.  */
-class MyThreadHandle
-{
-public:
-    HANDLE mh;
-
-    MyThreadHandle(HANDLE hThread)
-    {
-        if (!DuplicateHandle(GetCurrentProcess(), hThread, GetCurrentProcess(),
-                             &mh, 0 /*dwDesiredAccess*/, FALSE /*bInheritHandle*/,
-                             DUPLICATE_SAME_ACCESS))
-            mh = INVALID_HANDLE_VALUE;
-    }
-
-    ~MyThreadHandle()
-    {
-        CloseHandle(mh);
-        mh = INVALID_HANDLE_VALUE;
-    }
-};
 
 /** COM version of nsIEventQueue::PendingEvents. */
@@ -386,5 +573,5 @@
         return VERR_NOT_FOUND;
 #else
-    MyThreadHandle q(GetCurrentThread());
+    MyThreadHandle q;
 #endif
 
@@ -530,5 +717,4 @@
     return VINF_SUCCESS;
 }
-
 }
 /* namespace com */
Index: /trunk/src/VBox/Main/glue/initterm.cpp
===================================================================
--- /trunk/src/VBox/Main/glue/initterm.cpp	(revision 22846)
+++ /trunk/src/VBox/Main/glue/initterm.cpp	(revision 22847)
@@ -53,4 +53,5 @@
 #include "VBox/com/com.h"
 #include "VBox/com/assert.h"
+#include "VBox/com/EventQueue.h"
 
 #include "../include/Logging.h"
@@ -497,4 +498,6 @@
     AssertComRC (rc);
 
+    EventQueue::init();
+
     return rc;
 }
@@ -503,4 +506,6 @@
 {
     HRESULT rc = S_OK;
+
+    EventQueue::deinit();
 
 #if !defined (VBOX_WITH_XPCOM)
Index: /trunk/src/libs/xpcom18a4/python/src/module/_xpcom.cpp
===================================================================
--- /trunk/src/libs/xpcom18a4/python/src/module/_xpcom.cpp	(revision 22846)
+++ /trunk/src/libs/xpcom18a4/python/src/module/_xpcom.cpp	(revision 22847)
@@ -493,136 +493,7 @@
 
 #ifdef VBOX
-//#define USE_EVENTQUEUE  1
-
-# ifdef USE_EVENTQUEUE
+
 #  include <VBox/com/EventQueue.h>
 #  include <iprt/err.h>
-# else
-#  include <iprt/cdefs.h>
-# endif
-
-static nsIEventQueue* g_mainEventQ = nsnull;
-
-# ifndef USE_EVENTQUEUE /** @todo Make USE_EVENTQUEUE default. */
-// 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 is native or not.
-DECLINLINE(bool)
-isEventQueueNative(nsIEventQueue *pQueue)
-{
-	PRBool fIsNative = PR_FALSE;
-	nsresult rc = pQueue->IsQueueNative(&fIsNative);
-	return NS_SUCCEEDED(rc) && fIsNative ? true : false;
-}
-
-# ifdef RT_OS_DARWIN
-#  include <iprt/time.h>
-#  include <iprt/thread.h>
-#  include <iprt/err.h>
-#  include <CoreFoundation/CFRunLoop.h>
-#  if MAC_OS_X_VERSION_MAX_ALLOWED == 1040 /* ASSUMES this means we're using the 10.4 SDK. */
-#   include <CarbonEvents.h>
-#  endif
-
-// 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
-			CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, false /*returnAfterSourceHandled*/);
-#  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)
-#  if MAC_OS_X_VERSION_MAX_ALLOWED == 1040 /* ASSUMES this means we're using the 10.4 SDK. */
-	    &&  GetCurrentEventLoop() == GetMainEventLoop()
-#  else
-	    &&  CFRunLoopGetMain() == CFRunLoopGetCurrent()
-#  endif
-	) {
-    		OSStatus       orc       = -1;
-		CFTimeInterval rdTimeout = cMsTimeout < 0
-		                         ? 1.0e10
-		                         : (double)cMsTimeout / 1000;
-		Py_BEGIN_ALLOW_THREADS;
-		orc = CFRunLoopRunInMode(kCFRunLoopDefaultMode, rdTimeout, true /*returnAfterSourceHandled*/);
-		if (orc == kCFRunLoopRunHandledSource)
-		    orc = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, false /*returnAfterSourceHandled*/);
-		Py_END_ALLOW_THREADS;
-		if (!orc || orc == kCFRunLoopRunHandledSource)
-			return 0;
-
-		if (orc != kCFRunLoopRunTimedOut) {
-			NS_WARNING("Unexpected status code from CFRunLoopRunInMode");
-			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 */
-# endif /* !USE_EVENTQUEUE */
 
 static PyObject*
@@ -634,100 +505,21 @@
     return NULL; /** @todo throw exception */
 
-  nsIEventQueue* q = g_mainEventQ;
-  if (q == nsnull)
-    return NULL; /** @todo throw exception */
-
-# ifdef USE_EVENTQUEUE
   int rc;
-  
-  Py_BEGIN_ALLOW_THREADS;
-  rc = com::EventQueue::processThreadEventQueue(aTimeout < 0 ? RT_INDEFINITE_WAIT : (uint32_t)aTimeout);
-  Py_END_ALLOW_THREADS;
-  
+  com::EventQueue* aEventQ = com::EventQueue::getMainEventQueue();
+  NS_WARN_IF_FALSE(aEventQ != nsnull, "Null main event queue");
+  if (!aEventQ)
+      return NULL;
+
+  Py_BEGIN_ALLOW_THREADS
+  rc = aEventQ->processEventQueue(aTimeout < 0 ? RT_INDEFINITE_WAIT : (uint32_t)aTimeout);
+  Py_END_ALLOW_THREADS
   if (RT_SUCCESS(rc))
       return PyInt_FromLong(0);
+
   if (   rc == VERR_TIMEOUT
       || rc == VERR_INTERRUPTED)
       return PyInt_FromLong(1);
-  return NULL; /** @todo throw exception */
-
-# else  /* !USE_EVENTQUEUE */
-  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;
-
-  if (aTimeout == 0)
-    goto ok;
-
-  rc = q->PendingEvents(&hasEvents);
-  if (NS_FAILED (rc))
-    return NULL;
-
-  if (hasEvents)
-    goto ok;
-
-  fd = q->GetEventQueueSelectFD();
-  if (fd < 0 && aTimeout < 0)
-  {
-    /* fallback */
-    PLEvent *pEvent = NULL;
-    Py_BEGIN_ALLOW_THREADS
-    rc = q->WaitForEvent(&pEvent);
-    Py_END_ALLOW_THREADS
-    if (NS_SUCCEEDED(rc))
-      q->HandleEvent(pEvent);
-    goto ok;
-  }
-
-  /* Cannot perform timed wait otherwise */
-  if (fd < 0)
-      return NULL;
-
-  {
-    fd_set fdsetR, fdsetE;
-    struct timeval tv;
-
-    FD_ZERO(&fdsetR);
-    FD_SET(fd, &fdsetR);
-
-    fdsetE = fdsetR;
-    if (aTimeout > 0)
-      {
-        tv.tv_sec = (PRInt64)aTimeout / 1000;
-        tv.tv_usec = ((PRInt64)aTimeout % 1000) * 1000;
-      }
-
-    /** @todo: What to do for XPCOM platforms w/o select() ? */
-    Py_BEGIN_ALLOW_THREADS;
-    int n = select(fd + 1, &fdsetR, NULL, &fdsetE, aTimeout < 0 ? NULL : &tv);
-    result = (n == 0) ?  1 :  0;
-    Py_END_ALLOW_THREADS;
-  }
- ok:
-  q->ProcessPendingEvents();
-#  endif /* !RT_OS_DARWIN */
-  return PyInt_FromLong(result);
-# endif /* !USE_EVENTQUEUE */
-}
-
-PR_STATIC_CALLBACK(void *) PyHandleEvent(PLEvent *ev)
-{
-  return nsnull;
-}
-
-PR_STATIC_CALLBACK(void) PyDestroyEvent(PLEvent *ev)
-{
-  delete ev;
+
+  return NULL; /** @todo throw correct exception */
 }
 
@@ -735,24 +527,12 @@
 PyXPCOMMethod_InterruptWait(PyObject *self, PyObject *args)
 {
-  nsIEventQueue* q = g_mainEventQ;
-  PRInt32 result = 0;
-  nsresult rc;
-
-  PLEvent *ev = new PLEvent();
-  if (!ev)
-  {
-    result = 1;
-    goto done;
-  }
-  q->InitEvent (ev, NULL, PyHandleEvent, PyDestroyEvent);
-  rc = q->PostEvent (ev);
-  if (NS_FAILED(rc))
-  {
-    result = 2;
-    goto done;
-  }
-
- done:
-  return PyInt_FromLong(result);
+  com::EventQueue* aEventQ = com::EventQueue::getMainEventQueue();
+  NS_WARN_IF_FALSE(aEventQ != nsnull, "Null main event queue");
+  if (!aEventQ)
+      return NULL;
+
+  aEventQ->interruptEventQueueProcessing();
+
+  return PyInt_FromLong(0);
 }
 
@@ -1004,9 +784,4 @@
     rc = com::Initialize();
 
-    if (NS_SUCCEEDED(rc))
-    {
-      NS_GetMainEventQ (&g_mainEventQ);
-    }
-
     init_xpcom();
   }
@@ -1016,8 +791,4 @@
 void deinitVBoxPython()
 {
-
-  if (g_mainEventQ)
-    NS_RELEASE(g_mainEventQ);
-
   com::Shutdown();
 }
