Create an X connection for each thread, and process X events in the
thread that created the corresponding X window.
Spawn a separate thread to run the desktop message loop in desktop
mode.

diff --git a/windows/x11drv/event.c b/windows/x11drv/event.c
index ef1c597..743f894 100644
--- a/windows/x11drv/event.c
+++ b/windows/x11drv/event.c
@@ -34,7 +34,6 @@
 #include "queue.h"
 #include "win.h"
 #include "winpos.h"
-#include "services.h"
 #include "file.h"
 #include "windef.h"
 #include "x11drv.h"
@@ -87,8 +86,6 @@
 };
 
 
-static void CALLBACK EVENT_Flush( ULONG_PTR arg );
-static void CALLBACK EVENT_ProcessAllEvents( ULONG_PTR arg );
 static void EVENT_ProcessEvent( XEvent *event );
 static BOOL X11DRV_CheckFocus(void);
 
@@ -129,60 +126,21 @@
 static void EVENT_EnterNotify( HWND hWnd, XCrossingEvent *event );
 */
 
-static void EVENT_GetGeometry( Window win, int *px, int *py,
+static void EVENT_GetGeometry( Display *display, Window win, int *px, int *py,
                                unsigned int *pwidth, unsigned int *pheight );
 
 
-static BOOL bUserRepaintDisabled = TRUE;
-
 /* Static used for the current input method */
 static INPUT_TYPE current_input_type = X11DRV_INPUT_ABSOLUTE;
 static BOOL in_transition = FALSE; /* This is not used as for today */
 
-static HANDLE service_object, service_timer;
 
 /***********************************************************************
- *           EVENT_Init
+ *           process_events
  */
-void X11DRV_EVENT_Init(void)
-{
-    /* Install the X event processing callback */
-    if ((service_object = SERVICE_AddObject( FILE_DupUnixHandle( ConnectionNumber(display), GENERIC_READ|SYNCHRONIZE ),
-                           EVENT_ProcessAllEvents, 0 )) == INVALID_HANDLE_VALUE)
-    {
-        ERR("cannot add service object\n");
-        ExitProcess(1);
-    }
-
-    /* Install the XFlush timer callback */
-    service_timer = SERVICE_AddTimer( 200, EVENT_Flush, 0 );
-}
-
-/***********************************************************************
- *           X11DRV_EVENT_Cleanup
- */
-void X11DRV_EVENT_Cleanup(void)
-{
-    SERVICE_Delete( service_timer );
-    SERVICE_Delete( service_object );
-}
-
-/***********************************************************************
- *           EVENT_Flush
- */
-static void CALLBACK EVENT_Flush( ULONG_PTR arg )
-{
-    TSXFlush( display );
-}
-
-/***********************************************************************
- *           EVENT_ProcessAllEvents
- */
-static void CALLBACK EVENT_ProcessAllEvents( ULONG_PTR arg )
+static void process_events( Display *display )
 {
     XEvent event;
-  
-    TRACE( "called (thread %lx).\n", GetCurrentThreadId() );
 
     wine_tsx11_lock();
     while ( XPending( display ) )
@@ -196,24 +154,46 @@
 }
 
 /***********************************************************************
- *		Synchronize (X11DRV.@)
+ *		X11DRV_Synchronize
  *
  * Synchronize with the X server. Should not be used too often.
  */
 void X11DRV_Synchronize( void )
 {
+    Display *display = thread_display();
     TSXSync( display, False );
-    EVENT_ProcessAllEvents( 0 );
+    process_events( display );
 }
 
+
 /***********************************************************************
- *		UserRepaintDisable (X11DRV.@)
+ *           MsgWaitForMultipleObjects   (X11DRV.@)
  */
-void X11DRV_UserRepaintDisable( BOOL bDisabled )
+DWORD X11DRV_MsgWaitForMultipleObjects( DWORD count, HANDLE *handles,
+                                        BOOL wait_all, DWORD timeout )
 {
-    bUserRepaintDisabled = bDisabled;
+    HANDLE new_handles[MAXIMUM_WAIT_OBJECTS+1];  /* FIXME! */
+    DWORD i, ret;
+    struct x11drv_thread_data *data = NtCurrentTeb()->driver_data;
+
+    if (!data || data->process_event_count)
+        return WaitForMultipleObjects( count, handles, wait_all, timeout );
+
+    for (i = 0; i < count; i++) new_handles[i] = handles[i];
+    new_handles[count] = data->display_fd;
+
+    data->process_event_count++;
+    wine_tsx11_lock();
+    XFlush( gdi_display );
+    XFlush( data->display );
+    wine_tsx11_unlock();
+    ret = WaitForMultipleObjects( count+1, new_handles, wait_all, timeout );
+    if (ret == count) process_events( data->display );
+    data->process_event_count--;
+    return ret;
 }
 
+
 /***********************************************************************
  *           EVENT_ProcessEvent
  *
@@ -222,6 +202,7 @@
 static void EVENT_ProcessEvent( XEvent *event )
 {
   HWND hWnd;
+  Display *display = event->xany.display;
 
   TRACE( "called.\n" );
 
@@ -302,7 +283,7 @@
       Window   	root, child;
       int      	root_x, root_y, child_x, child_y;
       unsigned	u;
-      TSXQueryPointer( display, X11DRV_GetXRootWindow(), &root, &child,
+      TSXQueryPointer( display, root_window, &root, &child,
 		       &root_x, &root_y, &child_x, &child_y, &u);
       if (TSXFindContext( display, child, winContext, (char **)&hWnd ) != 0)
 	return;
@@ -311,7 +292,7 @@
     }
   }
 
-  if ( !hWnd && event->xany.window != X11DRV_GetXRootWindow()
+  if ( !hWnd && event->xany.window != root_window
              && event->type != PropertyNotify 
              && event->type != MappingNotify)
       ERR("Got event %s for unknown Window %08lx\n",
@@ -359,7 +340,7 @@
       BOOL bIsDisabled;
       XFocusChangeEvent *xfocChange = (XFocusChangeEvent*)event;
 
-      if (!hWnd || bUserRepaintDisabled) return;
+      if (!hWnd) return;
 
       bIsDisabled = GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED;
 
@@ -393,34 +374,32 @@
       /* Save the last window which had the focus */
       XFocusChangeEvent *xfocChange = (XFocusChangeEvent*)event;
       glastXFocusWin = xfocChange->window;
-      if (!hWnd || bUserRepaintDisabled) return;
+      if (!hWnd) return;
       if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED) glastXFocusWin = 0;
       EVENT_FocusOut( hWnd, (XFocusChangeEvent*)event );
       break;
     }
       
     case Expose:
-      if (bUserRepaintDisabled) return;
       EVENT_Expose( hWnd, (XExposeEvent *)event );
       break;
       
     case GraphicsExpose:
-      if (bUserRepaintDisabled) return;
       EVENT_GraphicsExpose( hWnd, (XGraphicsExposeEvent *)event );
       break;
       
     case ConfigureNotify:
-      if (!hWnd || bUserRepaintDisabled) return;
+      if (!hWnd) return;
       EVENT_ConfigureNotify( hWnd, (XConfigureEvent*)event );
       break;
 
     case SelectionRequest:
-      if (!hWnd || bUserRepaintDisabled) return;
+      if (!hWnd) return;
       EVENT_SelectionRequest( hWnd, (XSelectionRequestEvent *)event, FALSE );
       break;
 
     case SelectionClear:
-      if (!hWnd || bUserRepaintDisabled) return;
+      if (!hWnd) return;
       EVENT_SelectionClear( hWnd, (XSelectionClearEvent*) event );
       break;
       
@@ -429,7 +408,7 @@
       break;
 
     case ClientMessage:
-      if (!hWnd || bUserRepaintDisabled) return;
+      if (!hWnd) return;
       EVENT_ClientMessage( hWnd, (XClientMessageEvent *) event );
       break;
 
@@ -443,12 +422,12 @@
       break;
       
     case MapNotify:
-      if (!hWnd || bUserRepaintDisabled) return;
+      if (!hWnd) return;
       EVENT_MapNotify( hWnd, (XMapEvent *)event );
       break;
 
     case UnmapNotify:
-      if (!hWnd || bUserRepaintDisabled) return;
+      if (!hWnd) return;
       EVENT_UnmapNotify( hWnd, (XUnmapEvent *)event );
       break;
 
@@ -483,7 +462,7 @@
   return ((*pWndB) != NULL);
 }
 
-static Window __get_common_ancestor( Window A, Window B,
+static Window __get_common_ancestor( Display *display, Window A, Window B,
                                      Window** children, unsigned* total )
 {
     /* find the real root window */
@@ -507,7 +486,7 @@
     return 0 ;
 }
 
-static Window __get_top_decoration( Window w, Window ancestor )
+static Window __get_top_decoration( Display *display, Window w, Window ancestor )
 {
   Window*     children, root, prev = w, parent = w;
   unsigned    total;
@@ -529,7 +508,7 @@
   return i;
 }
 
-static HWND EVENT_QueryZOrder( HWND hWndCheck)
+static HWND EVENT_QueryZOrder( Display *display, HWND hWndCheck)
 {
   HWND      hwndInsertAfter = HWND_TOP;
   WND      *pWndCheck = WIN_FindWndPtr(hWndCheck);
@@ -550,14 +529,14 @@
   WIN_ReleaseWndPtr(pDesktop->child);
   WIN_ReleaseDesktop();
   
-  parent = __get_common_ancestor( X11DRV_WND_GetXWindow(pWndZ), 
+  parent = __get_common_ancestor( display, X11DRV_WND_GetXWindow(pWndZ),
 				  X11DRV_WND_GetXWindow(pWnd),
 				  &children, &total );
   if( parent && children )
   {
       /* w is the ancestor if pWndCheck that is a direct descendant of 'parent' */
 
-      w = __get_top_decoration( X11DRV_WND_GetXWindow(pWndCheck), parent );
+      w = __get_top_decoration( display, X11DRV_WND_GetXWindow(pWndCheck), parent );
 
       if( w != children[total-1] ) /* check if at the top */
       {
@@ -572,7 +551,7 @@
 	      if( pWnd != pWndCheck )
               {
 		  if( !(pWnd->dwExStyle & WS_EX_MANAGED) ||
-		      !(w = __get_top_decoration( X11DRV_WND_GetXWindow(pWnd), parent )) )
+		      !(w = __get_top_decoration( display, X11DRV_WND_GetXWindow(pWnd), parent )) )
 		    continue;
 		  pos = __td_lookup( w, children, total );
 		  if( pos < best && pos > check )
@@ -856,6 +835,7 @@
  */
 static BOOL X11DRV_CheckFocus(void)
 {
+    Display *display = thread_display();
   HWND   hWnd;
   Window xW;
   int	   state;
@@ -873,7 +853,7 @@
  * Helper function for ConfigureNotify handling.
  * Get the new geometry of a window relative to the root window.
  */
-static void EVENT_GetGeometry( Window win, int *px, int *py,
+static void EVENT_GetGeometry( Display *display, Window win, int *px, int *py,
                                unsigned int *pwidth, unsigned int *pheight )
 {
     Window root, top;
@@ -911,8 +891,8 @@
   
     /* Get geometry and Z-order according to X */
 
-    EVENT_GetGeometry( event->window, &x, &y, &width, &height );
-    newInsertAfter = EVENT_QueryZOrder( hWnd );
+    EVENT_GetGeometry( event->display, event->window, &x, &y, &width, &height );
+    newInsertAfter = EVENT_QueryZOrder( event->display, hWnd );
 
     /* Get geometry and Z-order according to Wine */
 
@@ -966,7 +946,8 @@
  *           EVENT_SelectionRequest_TARGETS
  *  Service a TARGETS selection request event
  */
-static Atom EVENT_SelectionRequest_TARGETS( Window requestor, Atom target, Atom rprop )
+static Atom EVENT_SelectionRequest_TARGETS( Display *display, Window requestor,
+                                            Atom target, Atom rprop )
 {
     Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
     Atom* targets;
@@ -1057,7 +1038,8 @@
  *           EVENT_SelectionRequest_STRING
  *  Service a STRING selection request event
  */
-static Atom EVENT_SelectionRequest_STRING( Window requestor, Atom target, Atom rprop )
+static Atom EVENT_SelectionRequest_STRING( Display *display, Window requestor,
+                                           Atom target, Atom rprop )
 {
     static UINT text_cp = (UINT)-1;
     HANDLE hUnicodeText;
@@ -1123,7 +1105,8 @@
  *           EVENT_SelectionRequest_PIXMAP
  *  Service a PIXMAP selection request event
  */
-static Atom EVENT_SelectionRequest_PIXMAP( Window requestor, Atom target, Atom rprop )
+static Atom EVENT_SelectionRequest_PIXMAP( Display *display, Window requestor,
+                                           Atom target, Atom rprop )
 {
     HANDLE hClipData = 0;
     Pixmap pixmap = 0;
@@ -1222,7 +1205,8 @@
  *  Service a Wine Clipboard Format selection request event.
  *  For <WCF>* data types we simply copy the data to X without conversion.
  */
-static Atom EVENT_SelectionRequest_WCF( Window requestor, Atom target, Atom rprop )
+static Atom EVENT_SelectionRequest_WCF( Display *display, Window requestor,
+                                        Atom target, Atom rprop )
 {
     HANDLE hClipData = 0;
     void*  lpClipData;
@@ -1281,6 +1265,7 @@
  */
 static Atom EVENT_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
 {
+    Display *display = pevent->display;
     Atom           rprop;
     Atom           atype=AnyPropertyType;
     int		   aformat;
@@ -1375,6 +1360,7 @@
  */
 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
 {
+    Display *display = event->display;
   XSelectionEvent result;
   Atom 	          rprop = None;
   Window          request = event->requestor;
@@ -1406,32 +1392,32 @@
   if(event->target == xaTargets)  /*  Return a list of all supported targets */
   {
       /* TARGETS selection request */
-      rprop = EVENT_SelectionRequest_TARGETS( request, event->target, rprop );
+      rprop = EVENT_SelectionRequest_TARGETS( display, request, event->target, rprop );
   }
   else if(event->target == xaMultiple)  /*  rprop contains a list of (target, property) atom pairs */
   {
       /* MULTIPLE selection request */
-      rprop = EVENT_SelectionRequest_MULTIPLE(  hWnd, event );
+      rprop = EVENT_SelectionRequest_MULTIPLE( hWnd, event );
   }
   else if(event->target == XA_STRING)  /* treat CF_TEXT as Unix text */
   {
       /* XA_STRING selection request */
-      rprop = EVENT_SelectionRequest_STRING( request, event->target, rprop );
+      rprop = EVENT_SelectionRequest_STRING( display, request, event->target, rprop );
   }
   else if(event->target == XA_PIXMAP)  /*  Convert DIB's to Pixmaps */
   {
       /* XA_PIXMAP selection request */
-      rprop = EVENT_SelectionRequest_PIXMAP( request, event->target, rprop );
+      rprop = EVENT_SelectionRequest_PIXMAP( display, request, event->target, rprop );
   }
   else if(event->target == XA_BITMAP)  /*  Convert DIB's to 1-bit Pixmaps */
   {
       /* XA_BITMAP selection request - TODO: create a monochrome Pixmap */
-      rprop = EVENT_SelectionRequest_PIXMAP( request, XA_PIXMAP, rprop );
+      rprop = EVENT_SelectionRequest_PIXMAP( display, request, XA_PIXMAP, rprop );
   }
   else if(X11DRV_CLIPBOARD_IsNativeProperty(event->target)) /* <WCF>* */
   {
       /* All <WCF> selection requests */
-      rprop = EVENT_SelectionRequest_WCF( request, event->target, rprop );
+      rprop = EVENT_SelectionRequest_WCF( display, request, event->target, rprop );
   }
   else
       rprop = None;  /* Don't support this format */
@@ -1465,7 +1451,7 @@
  */
 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
 {
-  Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
+  Atom xaClipboard = TSXInternAtom(event->display, "CLIPBOARD", False);
     
   if (event->selection == XA_PRIMARY || event->selection == xaClipboard)
       X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd );
@@ -1536,7 +1522,7 @@
   
   pWnd = WIN_FindWndPtr(hWnd);
   
-  TSXQueryPointer( display, X11DRV_WND_GetXWindow(pWnd), &w_aux_root, &w_aux_child, 
+  TSXQueryPointer( event->display, X11DRV_WND_GetXWindow(pWnd), &w_aux_root, &w_aux_child, 
                    &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
                    (unsigned int*)&aux_long);
   
@@ -1560,7 +1546,7 @@
   
   if( bAccept )
     {
-      TSXGetWindowProperty( display, DefaultRootWindow(display),
+      TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
 			    dndSelection, 0, 65535, FALSE,
 			    AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
 			    &data_length, &aux_long, &p_data);
@@ -1660,7 +1646,7 @@
   }
   WIN_ReleaseWndPtr(pWnd);
 
-  TSXGetWindowProperty( display, DefaultRootWindow(display),
+  TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
 			dndSelection, 0, 65535, FALSE,
 			AnyPropertyType, &u.atom_aux, &u.i,
 			&data_length, &aux_long, &p_data);
@@ -1688,7 +1674,7 @@
     }
     
     if( drop_len && drop_len < 65535 ) {
-      TSXQueryPointer( display, X11DRV_GetXRootWindow(), &u.w_aux, &u.w_aux, 
+      TSXQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
 		       &x, &y, &u.i, &u.i, &u.i);
 
       pDropWnd = WIN_FindWndPtr( hWnd );
@@ -1780,7 +1766,7 @@
 	int            	i;
 	Atom		atom;
       } u; /* unused */
-      TSXGetWindowProperty( display, DefaultRootWindow(display),
+      TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
 			    dndSelection, 0, 65535, FALSE,
 			    AnyPropertyType, &u.atom, &u.i,
 			    &u.l, &u.l, &p_data);
@@ -1803,9 +1789,9 @@
 #if 0
 void EVENT_EnterNotify( HWND hWnd, XCrossingEvent *event )
 {
-  if( !Options.managed && X11DRV_GetXRootWindow() == DefaultRootWindow(display) &&
+  if( !Options.managed && root_window == DefaultRootWindow(event->display) &&
       (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus() )
-    TSXInstallColormap( display, X11DRV_PALETTE_GetColormap() );
+    TSXInstallColormap( event->display, X11DRV_PALETTE_GetColormap() );
 }
 #endif