Implemented new Wine startup sequence, separating startup into
[wine] / windows / event.c
index 5f3aa3d..1ebe5b0 100644 (file)
 /*
  * X events handling functions
- *
+ * 
  * Copyright 1993 Alexandre Julliard
+ * 
  */
 
-static char Copyright[] = "Copyright  Alexandre Julliard, 1993";
-
-#include <X11/Intrinsic.h>
-#include <X11/StringDefs.h>
-#include <X11/Core.h>
+#include <assert.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <X11/keysym.h>
+#include "ts_xlib.h"
+#include "ts_xresource.h"
+#include "ts_xutil.h"
+#include <X11/Xatom.h>
 
 #include "windows.h"
+#include "winnt.h"
+#include "gdi.h"
+#include "heap.h"
+#include "queue.h"
 #include "win.h"
 #include "class.h"
+#include "clipboard.h"
+#include "dce.h"
+#include "message.h"
+#include "module.h"
+#include "options.h"
+#include "queue.h"
+#include "winpos.h"
+#include "drive.h"
+#include "shell.h"
+#include "keyboard.h"
+#include "debug.h"
+#include "dde_proc.h"
+#include "winsock.h"
+#include "callback.h"
 
 
 #define NB_BUTTONS      3     /* Windows can handle 3 buttons */
-static WORD dblclick_time = 300; /* Max. time for a double click (milliseconds) */
 
-extern Display * XT_display;
+#define DndNotDnd       -1    /* OffiX drag&drop */
+#define DndUnknown      0
+#define DndRawData      1
+#define DndFile         2
+#define DndFiles        3
+#define DndText         4
+#define DndDir          5
+#define DndLink         6
+#define DndExe          7
 
-  /* Event handlers */
-static void EVENT_expose();
-static void EVENT_key();
-static void EVENT_mouse_motion();
-static void EVENT_mouse_button();
-static void EVENT_structure();
-static void EVENT_focus_change();
-static void EVENT_enter_notify();
+#define DndEND          8
 
-  /* X context to associate a hwnd to an X window */
-static XContext winContext = 0;
-
-  /* State variables */
-static HWND captureWnd = 0;
-Window winHasCursor = 0;
-extern HWND hWndFocus;
+#define DndURL          128   /* KDE drag&drop */
 
-/* Keyboard translation tables */
-static int special_key[] =
-{
-    VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0,           /* FF08 */
-    0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0,                      /* FF10 */
-    0, 0, 0, VK_ESCAPE                                          /* FF18 */
-};
-
-static cursor_key[] =
-{
-    VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_PRIOR, 
-                                       VK_NEXT, VK_END          /* FF50 */
-};
-
-static misc_key[] =
-{
-    VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0,  /* FF60 */
-    VK_CANCEL, VK_HELP, VK_CANCEL, VK_MENU                      /* FF68 */
-};
 
-static keypad_key[] =
-{
-    VK_MENU, VK_NUMLOCK,                                        /* FF7E */
-    0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF80 */
-    0, 0, 0, 0, 0, VK_RETURN, 0, 0,                             /* FF88 */
-    0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF90 */
-    0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF98 */
-    0, 0, 0, 0, 0, 0, 0, 0,                                     /* FFA0 */
-    0, 0, VK_MULTIPLY, VK_ADD, VK_SEPARATOR, VK_SUBTRACT, 
-                               VK_DECIMAL, VK_DIVIDE,           /* FFA8 */
-    VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4,
-                            VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, /* FFB0 */
-    VK_NUMPAD8, VK_NUMPAD9                                      /* FFB8 */
-};
-    
-static function_key[] =
-{
-    VK_F1, VK_F2,                                               /* FFBE */
-    VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10,    /* FFC0 */
-    VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16              /* FFC8 */
-};
+  /* X context to associate a hwnd to an X window */
+static XContext winContext = 0;
 
-static modifier_key[] =
-{
-    VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL, VK_CAPITAL,
-                                                0, 0,           /* FFE1 */
-    0, VK_MENU, VK_MENU                                         /* FFE8 */
-};
+static INT16  captureHT = HTCLIENT;
+static HWND32 captureWnd = 0;
+static BOOL32 InputEnabled = TRUE;
+static BOOL32 SwappedButtons = FALSE;
 
-typedef union
-{
-    struct
-    {
-       unsigned long count : 16;
-       unsigned long code : 8;
-       unsigned long extended : 1;
-       unsigned long : 4;
-       unsigned long context : 1;
-       unsigned long previous : 1;
-       unsigned long transition : 1;
-    } lp1;
-    unsigned long lp2;
-} KEYLP;
+static Atom wmProtocols = None;
+static Atom wmDeleteWindow = None;
+static Atom dndProtocol = None;
+static Atom dndSelection = None;
 
-static BOOL KeyDown = FALSE;
+/* EVENT_WaitNetEvent() master fd sets */
 
+static fd_set __event_io_set[3];
+static int    __event_max_fd = 0;
+static int    __event_x_connection = 0;
 
-#ifdef DEBUG_EVENT
-static char *event_names[] =
+static const char * const event_names[] =
 {
     "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
     "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
@@ -116,8 +89,60 @@ static char *event_names[] =
     "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
     "ClientMessage", "MappingNotify"
 };
-#endif
 
+  /* Event handlers */
+static void EVENT_Key( WND *pWnd, XKeyEvent *event );
+static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event );
+static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event );
+static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event );
+static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event );
+static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event );
+static void EVENT_Expose( WND *pWnd, XExposeEvent *event );
+static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event );
+static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event );
+static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event);
+static void EVENT_SelectionNotify( XSelectionEvent *event);
+static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event);
+static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event );
+static void EVENT_MapNotify( HWND32 hwnd, XMapEvent *event );
+
+/* Usable only with OLVWM - compile option perhaps?
+static void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event );
+*/
+
+static void EVENT_SendMouseEvent( WORD mouseStatus, WORD deltaX, WORD deltaY, 
+                                  WORD buttonCount, DWORD extraInfo );
+
+/***********************************************************************
+ *           EVENT_Init
+ *
+ * Initialize network IO.
+ */
+BOOL32 EVENT_Init(void)
+{
+    int  i;
+    for( i = 0; i < 3; i++ )
+       FD_ZERO( __event_io_set + i );
+
+    __event_max_fd = __event_x_connection = ConnectionNumber(display);
+    FD_SET( __event_x_connection, &__event_io_set[EVENT_IO_READ] );
+    __event_max_fd++;
+    return TRUE;
+}
+
+/***********************************************************************
+ *          EVENT_AddIO 
+ */
+void EVENT_AddIO( int fd, unsigned io_type )
+{
+    FD_SET( fd, &__event_io_set[io_type] );
+    if( __event_max_fd <= fd ) __event_max_fd = fd + 1;
+}
+
+void EVENT_DeleteIO( int fd, unsigned io_type )
+{
+    FD_CLR( fd, &__event_io_set[io_type] );
+}
 
 /***********************************************************************
  *           EVENT_ProcessEvent
@@ -126,119 +151,445 @@ static char *event_names[] =
  */
 void EVENT_ProcessEvent( XEvent *event )
 {
-    HWND hwnd;
-    XPointer ptr;
-    Boolean cont_dispatch = TRUE;
+    WND *pWnd;
     
-    XFindContext( XT_display, ((XAnyEvent *)event)->window, winContext, &ptr );
-    hwnd = (HWND)ptr & 0xffff;
+    if ( TSXFindContext( display, event->xany.window, winContext,
+                        (char **)&pWnd ) != 0) {
+      if ( event->type == ClientMessage) {
+       /* query window (drag&drop event contains only drag window) */
+       Window          root, child;
+       int             root_x, root_y, child_x, child_y;
+       unsigned        u;
+       TSXQueryPointer( display, rootWindow, &root, &child,
+                        &root_x, &root_y, &child_x, &child_y, &u);
+       if (TSXFindContext( display, child, winContext, (char **)&pWnd ) != 0)
+         return;
+      } else {
+       return;  /* Not for a registered window */
+      }
+    }
 
-#ifdef DEBUG_EVENT
-    printf( "Got event %s for hwnd %d\n", 
-           event_names[event->type], hwnd );
-#endif
+    TRACE(event, "Got event %s for hwnd %04x\n",
+         event_names[event->type], pWnd->hwndSelf );
 
     switch(event->type)
     {
-        case Expose:
-           EVENT_expose( 0, hwnd, event, &cont_dispatch );
-           break;
-
-       case KeyPress:
-       case KeyRelease:
-           EVENT_key( 0, hwnd, event, &cont_dispatch );
-           break;
-
-       case MotionNotify:
-           EVENT_mouse_motion( 0, hwnd, event, &cont_dispatch );
-           break;
-
-       case ButtonPress:
-       case ButtonRelease:
-           EVENT_mouse_button( 0, hwnd, event, &cont_dispatch );
-           break;
-
-       case CirculateNotify:
-       case ConfigureNotify:
-       case MapNotify:
-       case UnmapNotify:
-           EVENT_structure( 0, hwnd, event, &cont_dispatch );
-           break;
-
-       case FocusIn:
-       case FocusOut:
-           EVENT_focus_change( 0, hwnd, event, &cont_dispatch );
-           break;
-
-       case EnterNotify:
-           EVENT_enter_notify( 0, hwnd, event, &cont_dispatch );
-           break;
-
-#ifdef DEBUG_EVENT
-       default:
-           printf( "Unprocessed event %s for hwnd %d\n", 
-                   event_names[event->type], hwnd );
-           break;
-#endif
+    case KeyPress:
+    case KeyRelease:
+        if (InputEnabled) EVENT_Key( pWnd, (XKeyEvent*)event );
+       break;
+       
+    case ButtonPress:
+        if (InputEnabled)
+            EVENT_ButtonPress( pWnd, (XButtonEvent*)event );
+       break;
+
+    case ButtonRelease:
+        if (InputEnabled)
+            EVENT_ButtonRelease( pWnd, (XButtonEvent*)event );
+       break;
+
+    case MotionNotify:
+        /* Wine between two fast machines across the overloaded campus
+          ethernet gets very boged down in MotionEvents. The following
+          simply finds the last motion event in the queue and drops
+          the rest. On a good link events are servered before they build
+          up so this doesn't take place. On a slow link this may cause
+          problems if the event order is important. I'm not yet seen
+          of any problems. Jon 7/6/96.
+        */
+        if (InputEnabled)
+       {
+            while (TSXCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
+                                          MotionNotify, event));    
+            EVENT_MotionNotify( pWnd, (XMotionEvent*)event );
+       }
+       break;
+
+    case FocusIn:
+        EVENT_FocusIn( pWnd, (XFocusChangeEvent*)event );
+       break;
+
+    case FocusOut:
+       EVENT_FocusOut( pWnd, (XFocusChangeEvent*)event );
+       break;
+
+    case Expose:
+       EVENT_Expose( pWnd, (XExposeEvent *)event );
+       break;
+
+    case GraphicsExpose:
+       EVENT_GraphicsExpose( pWnd, (XGraphicsExposeEvent *)event );
+        break;
+
+    case ConfigureNotify:
+       EVENT_ConfigureNotify( pWnd, (XConfigureEvent*)event );
+       break;
+
+    case SelectionRequest:
+       EVENT_SelectionRequest( pWnd, (XSelectionRequestEvent *)event );
+       break;
+
+    case SelectionNotify:
+       EVENT_SelectionNotify( (XSelectionEvent *)event );
+       break;
+
+    case SelectionClear:
+       EVENT_SelectionClear( pWnd, (XSelectionClearEvent*) event );
+       break;
+
+    case ClientMessage:
+       EVENT_ClientMessage( pWnd, (XClientMessageEvent *) event );
+       break;
+
+/*  case EnterNotify:
+ *       EVENT_EnterNotify( pWnd, (XCrossingEvent *) event );
+ *       break;
+ */
+    case NoExpose:
+       break;
+
+    /* We get all these because of StructureNotifyMask. */
+    case UnmapNotify:
+    case CirculateNotify:
+    case CreateNotify:
+    case DestroyNotify:
+    case GravityNotify:
+    case ReparentNotify:
+       break;
+
+    case MapNotify:
+       EVENT_MapNotify( pWnd->hwndSelf, (XMapEvent *)event );
+       break;
+
+    default:    
+       WARN(event, "Unprocessed event %s for hwnd %04x\n",
+               event_names[event->type], pWnd->hwndSelf );
+       break;
     }
 }
 
 
 /***********************************************************************
- *           EVENT_AddHandlers
+ *           EVENT_RegisterWindow
  *
- * Add the event handlers to the given window
- */
-#ifdef USE_XLIB
-void EVENT_AddHandlers( Window w, int hwnd )
-{
-    if (!winContext) winContext = XUniqueContext();
-    XSaveContext( XT_display, w, winContext, (XPointer)hwnd );
-}
-#else
-void EVENT_AddHandlers( Widget w, int hwnd )
-{
-    XtAddEventHandler(w, ExposureMask, FALSE,
-                     EVENT_expose, (XtPointer)hwnd );
-    XtAddEventHandler(w, KeyPressMask | KeyReleaseMask, FALSE, 
-                     EVENT_key, (XtPointer)hwnd );
-    XtAddEventHandler(w, PointerMotionMask, FALSE,
-                     EVENT_mouse_motion, (XtPointer)hwnd );
-    XtAddEventHandler(w, ButtonPressMask | ButtonReleaseMask, FALSE,
-                     EVENT_mouse_button, (XtPointer)hwnd );
-    XtAddEventHandler(w, StructureNotifyMask, FALSE,
-                     EVENT_structure, (XtPointer)hwnd );
-    XtAddEventHandler(w, FocusChangeMask, FALSE,
-                     EVENT_focus_change, (XtPointer)hwnd );
-    XtAddEventHandler(w, EnterWindowMask, FALSE,
-                     EVENT_enter_notify, (XtPointer)hwnd );
+ * Associate an X window to a HWND.
+ */
+void EVENT_RegisterWindow( WND *pWnd )
+{
+    if (wmProtocols == None)
+        wmProtocols = TSXInternAtom( display, "WM_PROTOCOLS", True );
+    if (wmDeleteWindow == None)
+        wmDeleteWindow = TSXInternAtom( display, "WM_DELETE_WINDOW", True );
+    if( dndProtocol == None )
+       dndProtocol = TSXInternAtom( display, "DndProtocol" , False );
+    if( dndSelection == None )
+       dndSelection = TSXInternAtom( display, "DndSelection" , False );
+
+    TSXSetWMProtocols( display, pWnd->window, &wmDeleteWindow, 1 );
+
+    if (!winContext) winContext = TSXUniqueContext();
+    TSXSaveContext( display, pWnd->window, winContext, (char *)pWnd );
+}
+
+/***********************************************************************
+ *           EVENT_DestroyWindow
+ */
+void EVENT_DestroyWindow( WND *pWnd )
+{
+   XEvent xe;
+
+   TSXDeleteContext( display, pWnd->window, winContext );
+   TSXDestroyWindow( display, pWnd->window );
+   while( TSXCheckWindowEvent(display, pWnd->window, NoEventMask, &xe) );
 }
-#endif
 
 
 /***********************************************************************
- *           EVENT_RemoveHandlers
+ *           IsUserIdle                (USER.333)
  *
- * Remove the event handlers of the given window
- */
-void EVENT_RemoveHandlers( Widget w, int hwnd )
-{
-#ifndef USE_XLIB
-    XtRemoveEventHandler(w, ExposureMask, FALSE,
-                        EVENT_expose, (XtPointer)hwnd );
-    XtRemoveEventHandler(w, KeyPressMask | KeyReleaseMask, FALSE, 
-                        EVENT_key, (XtPointer)hwnd );
-    XtRemoveEventHandler(w, PointerMotionMask, FALSE,
-                        EVENT_mouse_motion, (XtPointer)hwnd );
-    XtRemoveEventHandler(w, ButtonPressMask | ButtonReleaseMask, FALSE,
-                        EVENT_mouse_button, (XtPointer)hwnd );
-    XtRemoveEventHandler(w, StructureNotifyMask, FALSE,
-                        EVENT_structure, (XtPointer)hwnd );
-    XtRemoveEventHandler(w, FocusChangeMask, FALSE,
-                        EVENT_focus_change, (XtPointer)hwnd );
-    XtRemoveEventHandler(w, EnterWindowMask, FALSE,
-                        EVENT_enter_notify, (XtPointer)hwnd );
-#endif
+ * Check if we have pending X events.
+ */
+BOOL16 WINAPI IsUserIdle(void)
+{
+    struct timeval timeout = {0, 0};
+    fd_set check_set;
+
+    FD_ZERO(&check_set);
+    FD_SET(__event_x_connection, &check_set);
+    if( select(__event_x_connection + 1, &check_set, NULL, NULL, &timeout) > 0 )
+       return TRUE;
+    return FALSE;
+}
+
+
+/***********************************************************************
+ *           EVENT_WaitNetEvent
+ *
+ * Wait for a network event, optionally sleeping until one arrives.
+ * Return TRUE if an event is pending, FALSE on timeout or error
+ * (for instance lost connection with the server).
+ */
+BOOL32 EVENT_WaitNetEvent( BOOL32 sleep, BOOL32 peek )
+{
+    XEvent event;
+    LONG maxWait = sleep ? TIMER_GetNextExpiration() : 0;
+    int pending = TSXPending(display);
+
+    /* Wait for an event or a timeout. If maxWait is -1, we have no timeout;
+     * in this case, we fall through directly to the XNextEvent loop.
+     */
+
+    if ((maxWait != -1) && !pending)
+    {
+       int num_pending;
+        struct timeval timeout;
+       fd_set io_set[3];
+
+       memcpy( io_set, __event_io_set, sizeof(io_set) );
+
+       timeout.tv_usec = (maxWait % 1000) * 1000;
+       timeout.tv_sec = maxWait / 1000;
+
+#ifdef CONFIG_IPC
+       sigsetjmp(env_wait_x, 1);
+       stop_wait_op= CONT;
+           
+       if (DDE_GetRemoteMessage()) {
+           while(DDE_GetRemoteMessage())
+               ;
+           return TRUE;
+       }
+       stop_wait_op = STOP_WAIT_X;
+       /* The code up to the next "stop_wait_op = CONT" must be reentrant */
+       num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ], 
+                                             &io_set[EVENT_IO_WRITE], 
+                                             &io_set[EVENT_IO_EXCEPT], &timeout );
+       if ( num_pending == 0 )
+        {
+           stop_wait_op = CONT;
+            TIMER_ExpireTimers();
+           return FALSE;
+       }
+        else stop_wait_op = CONT;
+#else  /* CONFIG_IPC */
+       num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
+                                             &io_set[EVENT_IO_WRITE],
+                                             &io_set[EVENT_IO_EXCEPT], &timeout );
+       if ( num_pending == 0)
+        {
+            /* Timeout or error */
+            TIMER_ExpireTimers();
+            return FALSE;
+        }
+#endif  /* CONFIG_IPC */
+
+       /*  Winsock asynchronous services */
+
+       if( FD_ISSET( __event_x_connection, &io_set[EVENT_IO_READ]) ) 
+       {
+           num_pending--;
+           if( num_pending )
+               WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
+       }
+       else /* no X events */
+           return WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
+    }
+    else if(!pending)
+    {                          /* Wait for X11 input. */
+       fd_set set;
+
+       FD_ZERO(&set);
+       FD_SET(__event_x_connection, &set);
+       select(__event_x_connection + 1, &set, 0, 0, 0 );
+    }
+
+    /* Process current X event (and possibly others that occurred in the meantime) */
+
+    EnterCriticalSection(&X11DRV_CritSection);
+    while (XPending( display ))
+    {
+
+#ifdef CONFIG_IPC
+        if (DDE_GetRemoteMessage())
+        {
+            LeaveCriticalSection(&X11DRV_CritSection);
+            while(DDE_GetRemoteMessage()) ;
+            return TRUE;
+        }
+#endif  /* CONFIG_IPC */
+
+       XNextEvent( display, &event );
+
+        LeaveCriticalSection(&X11DRV_CritSection);
+        if( peek )
+        {
+         WND*          pWnd;
+         MESSAGEQUEUE* pQ;
+
+
+         /* Check only for those events which can be processed
+          * internally. */
+
+         if( event.type == MotionNotify ||
+             event.type == ButtonPress || event.type == ButtonRelease ||
+             event.type == KeyPress || event.type == KeyRelease ||
+             event.type == SelectionRequest || event.type == SelectionClear ||
+             event.type == ClientMessage )
+         {
+              EVENT_ProcessEvent( &event );
+               continue;
+         }
+
+          if (TSXFindContext( display, ((XAnyEvent *)&event)->window, winContext,
+                            (char **)&pWnd ) || (event.type == NoExpose))
+              continue;
+
+         if( pWnd )
+          {
+            if( (pQ = (MESSAGEQUEUE*)GlobalLock16(pWnd->hmemTaskQ)) )
+            {
+              pQ->flags |= QUEUE_FLAG_XEVENT;
+              PostEvent(pQ->hTask);
+             TSXPutBackEvent(display, &event);
+              break;
+           }
+          }
+        }
+        else EVENT_ProcessEvent( &event );
+        EnterCriticalSection(&X11DRV_CritSection);
+    }
+    LeaveCriticalSection(&X11DRV_CritSection);
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           EVENT_Synchronize
+ *
+ * Synchronize with the X server. Should not be used too often.
+ */
+void EVENT_Synchronize()
+{
+    XEvent event;
+
+    /* Use of the X critical section is needed or we have a small
+     * race between XPending() and XNextEvent().
+     */
+    EnterCriticalSection( &X11DRV_CritSection );
+    XSync( display, False );
+    while (XPending( display ))
+    {
+       XNextEvent( display, &event );
+       /* unlock X critsection for EVENT_ProcessEvent() might switch tasks */
+       LeaveCriticalSection( &X11DRV_CritSection );
+       EVENT_ProcessEvent( &event );
+       EnterCriticalSection( &X11DRV_CritSection );
+    }    
+    LeaveCriticalSection( &X11DRV_CritSection );
+}
+
+/***********************************************************************
+ *           EVENT_QueryZOrder
+ *
+ * Try to synchronize internal z-order with the window manager's.
+ * Probably a futile endeavor.
+ */
+static BOOL32 __check_query_condition( WND** pWndA, WND** pWndB )
+{
+    /* return TRUE if we have at least two managed windows */
+
+    for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
+        if( (*pWndA)->flags & WIN_MANAGED &&
+            (*pWndA)->dwStyle & WS_VISIBLE ) break;
+    if( *pWndA )
+        for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
+            if( (*pWndB)->flags & WIN_MANAGED &&
+                (*pWndB)->dwStyle & WS_VISIBLE ) break;
+     return ((*pWndB) != NULL);
+}
+
+static Window __get_common_ancestor( Window A, Window B,
+                                     Window** children, unsigned* total )
+{
+    /* find the real root window */
+
+    Window      root, *childrenB;
+    unsigned    totalB;
+
+    do
+    {
+        if( *children ) TSXFree( *children );
+        TSXQueryTree( display, A, &root, &A, children, total );
+        TSXQueryTree( display, B, &root, &B, &childrenB, &totalB );
+        if( childrenB ) TSXFree( childrenB );
+    } while( A != B && A && B );
+    return ( A && B ) ? A : 0 ;
+}
+
+static Window __get_top_decoration( Window w, Window ancestor )
+{
+    Window*     children, root, prev = w, parent = w;
+    unsigned    total;
+
+    do
+    {
+        w = parent;
+        TSXQueryTree( display, w, &root, &parent, &children, &total );
+        if( children ) TSXFree( children );
+    } while( parent && parent != ancestor );
+    TRACE(event, "\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
+    return ( parent ) ? w : 0 ;
+}
+
+static unsigned __td_lookup( Window w, Window* list, unsigned max )
+{
+    unsigned    i;
+    for( i = 0; i < max; i++ ) if( list[i] == w ) break;
+    return i;
+}
+
+static BOOL32 EVENT_QueryZOrder( WND* pWndCheck )
+{
+    BOOL32      bRet = FALSE;
+    HWND32      hwndInsertAfter = HWND_TOP;
+    WND*        pWnd, *pWndZ = WIN_GetDesktop()->child;
+    Window      w, parent, *children = NULL;
+    unsigned    total, check, pos, best;
+
+    if( !__check_query_condition(&pWndZ, &pWnd) ) return TRUE;
+
+    parent = __get_common_ancestor( pWndZ->window, pWnd->window,
+                                      &children, &total );
+    if( parent && children )
+    {
+        w = __get_top_decoration( pWndCheck->window, parent );
+        if( w != children[total - 1] )
+        {
+            check = __td_lookup( w, children, total );
+            best = total;
+            for( pWnd = pWndZ; pWnd; pWnd = pWnd->next )
+            {
+                if( pWnd != pWndCheck )
+                {
+                    if( !(pWnd->flags & WIN_MANAGED) ||
+                        !(w = __get_top_decoration( pWnd->window, parent )) )
+                        continue;
+                    pos = __td_lookup( w, children, total );
+                    if( pos < best && pos > check )
+                    {
+                        best = pos;
+                        hwndInsertAfter = pWnd->hwndSelf;
+                    }
+                    if( check - best == 1 ) break;
+                }
+            }
+            WIN_UnlinkWindow( pWndCheck->hwndSelf );
+            WIN_LinkWindow( pWndCheck->hwndSelf, hwndInsertAfter);
+        }
+    }
+    if( children ) TSXFree( children );
+    return bRet;
 }
 
 
@@ -262,415 +613,994 @@ static WORD EVENT_XStateToKeyState( int state )
 
 
 /***********************************************************************
- *           EVENT_expose
+ *           EVENT_Expose
+ */
+static void EVENT_Expose( WND *pWnd, XExposeEvent *event )
+{
+    RECT32 rect;
+
+    /* Make position relative to client area instead of window */
+    rect.left   = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
+    rect.top    = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
+    rect.right  = rect.left + event->width;
+    rect.bottom = rect.top + event->height;
+
+    PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
+                        RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
+                        (event->count ? 0 : RDW_ERASENOW), 0 );
+}
+
+
+/***********************************************************************
+ *           EVENT_GraphicsExpose
  *
- * Handle a X expose event
+ * This is needed when scrolling area is partially obscured
+ * by non-Wine X window.
  */
-static void EVENT_expose( Widget w, int hwnd, XExposeEvent *event,
-                         Boolean *cont_dispatch )
+static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event )
 {
-    RECT rect;
-    WND * wndPtr = WIN_FindWndPtr( hwnd );
-    if (!wndPtr) return;
-      /* Make position relative to client area instead of window */
-    rect.left = event->x - (wndPtr->rectClient.left - wndPtr->rectWindow.left);
-    rect.top  = event->y - (wndPtr->rectClient.top - wndPtr->rectWindow.top);
+    RECT32 rect;
+
+    /* Make position relative to client area instead of window */
+    rect.left   = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
+    rect.top    = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
     rect.right  = rect.left + event->width;
     rect.bottom = rect.top + event->height;
-    winHasCursor = event->window;
-    
-    InvalidateRect( hwnd, &rect, TRUE );
+
+    PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
+                        RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
+                        (event->count ? 0 : RDW_ERASENOW), 0 );
 }
 
 
 /***********************************************************************
- *           EVENT_key
+ *           EVENT_Key
  *
  * Handle a X key event
  */
-static void EVENT_key( Widget w, int hwnd, XKeyEvent *event,
-                      Boolean *cont_dispatch )
-{
-    MSG msg;
-    char Str[24]; 
-    XComposeStatus cs; 
-    KeySym keysym;
-    WORD xkey, vkey, key_type, key;
-    KEYLP keylp;
-    BOOL extended = FALSE;
-    WND * wndPtr = WIN_FindWndPtr( hwnd );
-    int count = XLookupString(event, Str, 1, &keysym, &cs);
-    Str[count] = '\0';
-#ifdef DEBUG_KEY
-    printf("WM_KEY??? : keysym=%lX, count=%u / %X / '%s'\n", 
-          keysym, count, Str[0], Str);
-#endif
+static void EVENT_Key( WND *pWnd, XKeyEvent *event )
+{
+    KEYBOARD_HandleEvent( pWnd, event );
+}
 
-    xkey = LOWORD(keysym);
-    key_type = HIBYTE(xkey);
-    key = LOBYTE(xkey);
-#ifdef DEBUG_KEY
-    printf("            key_type=%X, key=%X\n", key_type, key);
-#endif
 
-      /* Position must be relative to client area */
-    event->x -= wndPtr->rectClient.left - wndPtr->rectWindow.left;
-    event->y -= wndPtr->rectClient.top - wndPtr->rectWindow.top;
+/***********************************************************************
+ *           EVENT_MotionNotify
+ */
+static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event )
+{
+    hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ), 0L,
+                    pWnd->rectWindow.left + event->x,
+                    pWnd->rectWindow.top + event->y,
+                    event->time - MSG_WineStartTicks, pWnd->hwndSelf );
+
+    EVENT_SendMouseEvent( ME_MOVE, 
+                          pWnd->rectWindow.left + event->x,
+                          pWnd->rectWindow.top + event->y,
+                          0, 0 );
+}
+
 
-    if (key_type == 0xFF)                          /* non-character key */
+/***********************************************************************
+ *           EVENT_DummyMotionNotify
+ *
+ * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
+ */
+void EVENT_DummyMotionNotify(void)
+{
+    Window root, child;
+    int rootX, rootY, winX, winY;
+    unsigned int state;
+
+    if (TSXQueryPointer( display, rootWindow, &root, &child,
+                       &rootX, &rootY, &winX, &winY, &state ))
     {
-       if (key >= 0x08 && key <= 0x1B)            /* special key */
-           vkey = special_key[key - 0x08];
-       else if (key >= 0x50 && key <= 0x57)       /* cursor key */
-           vkey = cursor_key[key - 0x50];
-       else if (key >= 0x60 && key <= 0x6B)       /* miscellaneous key */
-           vkey = misc_key[key - 0x60];
-       else if (key >= 0x7E && key <= 0xB9)       /* keypad key */
-       {
-           vkey = keypad_key[key - 0x7E];
-           extended = TRUE;
-       }
-       else if (key >= 0xBE && key <= 0xCD)       /* function key */
-       {
-           vkey = function_key[key - 0xBE];
-           extended = TRUE;
-       }
-       else if (key >= 0xE1 && key <= 0xEA)       /* modifier key */
-           vkey = modifier_key[key - 0xE1];
-       else if (key == 0xFF)                      /* DEL key */
-           vkey = VK_DELETE;
+        hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( state ), 0L,
+                        winX, winY, GetTickCount(), 0 );
+    }
+}
+
+
+/***********************************************************************
+ *           EVENT_ButtonPress
+ */
+static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event )
+{
+    static WORD messages[NB_BUTTONS] = 
+        { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
+    static WORD statusCodes[NB_BUTTONS] = 
+        { ME_LDOWN, 0, ME_RDOWN };
+    int buttonNum = event->button - 1;
+
+    if (buttonNum >= NB_BUTTONS) return;
+    if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
+    MouseButtonsStates[buttonNum] = TRUE;
+    AsyncMouseButtonsStates[buttonNum] = TRUE;
+    hardware_event( messages[buttonNum],
+                   EVENT_XStateToKeyState( event->state ), 0L,
+                    pWnd->rectWindow.left + event->x,
+                    pWnd->rectWindow.top + event->y,
+                   event->time - MSG_WineStartTicks, pWnd->hwndSelf );
+
+    EVENT_SendMouseEvent( statusCodes[buttonNum], 
+                          pWnd->rectWindow.left + event->x,
+                          pWnd->rectWindow.top + event->y,
+                          0, 0 );
+}
+
+
+/***********************************************************************
+ *           EVENT_ButtonRelease
+ */
+static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event )
+{
+    static const WORD messages[NB_BUTTONS] = 
+        { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
+    static WORD statusCodes[NB_BUTTONS] = 
+        { ME_LUP, 0, ME_RUP };
+    int buttonNum = event->button - 1;
+
+    if (buttonNum >= NB_BUTTONS) return;    
+    if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
+    MouseButtonsStates[buttonNum] = FALSE;
+    hardware_event( messages[buttonNum],
+                   EVENT_XStateToKeyState( event->state ), 0L,
+                    pWnd->rectWindow.left + event->x,
+                    pWnd->rectWindow.top + event->y,
+                   event->time - MSG_WineStartTicks, pWnd->hwndSelf );
+
+    EVENT_SendMouseEvent( statusCodes[buttonNum], 
+                          pWnd->rectWindow.left + event->x,
+                          pWnd->rectWindow.top + event->y,
+                          0, 0 );
+}
+
+
+/**********************************************************************
+ *              EVENT_FocusIn
+ */
+static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event )
+{
+    if (Options.managed) EVENT_QueryZOrder( pWnd );
+
+    if (event->detail != NotifyPointer)
+    { 
+       HWND32  hwnd = pWnd->hwndSelf;
+
+       if (hwnd != GetActiveWindow32()) 
+        {
+           WINPOS_ChangeActiveWindow( hwnd, FALSE );
+           KEYBOARD_UpdateState();
+        }
+       if ((hwnd != GetFocus32()) && !IsChild32( hwnd, GetFocus32()))
+            SetFocus32( hwnd );
     }
-    else if (key_type == 0)                        /* character key */
+}
+
+
+/**********************************************************************
+ *              EVENT_FocusOut
+ *
+ * Note: only top-level override-redirect windows get FocusOut events.
+ */
+static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event )
+{
+    if (event->detail != NotifyPointer)
     {
-       if (key >= 0x61 && key <= 0x7A)
-           vkey = key - 0x20;                 /* convert lower to uppercase */
-       else
-           vkey = key;
+       HWND32  hwnd = pWnd->hwndSelf;
+
+       if (hwnd == GetActiveWindow32()) 
+           WINPOS_ChangeActiveWindow( 0, FALSE );
+       if ((hwnd == GetFocus32()) || IsChild32( hwnd, GetFocus32()))
+           SetFocus32( 0 );
     }
+}
+
+/**********************************************************************
+ *              EVENT_CheckFocus
+ */
+BOOL32 EVENT_CheckFocus(void)
+{
+    WND*   pWnd;
+    Window xW;
+    int           state;
+
+    TSXGetInputFocus(display, &xW, &state);
+    if( xW == None ||
+        TSXFindContext(display, xW, winContext, (char **)&pWnd) ) 
+        return FALSE;
+    return TRUE;
+}
+
+
+/**********************************************************************
+ *              EVENT_GetGeometry
+ *
+ * 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,
+                               unsigned int *pwidth, unsigned int *pheight )
+{
+    Window root, parent, *children;
+    int xpos, ypos;
+    unsigned int width, height, border, depth, nb_children;
 
-    if (event->type == KeyPress)
+    if (!TSXGetGeometry( display, win, &root, px, py, pwidth, pheight,
+                       &border, &depth )) return;
+    if (win == rootWindow)
     {
-       msg.hwnd    = hwnd;
-       msg.message = WM_KEYDOWN;
-       msg.wParam  = vkey;
-       keylp.lp1.count = 1;
-       keylp.lp1.code = LOBYTE(event->keycode);
-       keylp.lp1.extended = (extended ? 1 : 0);
-       keylp.lp1.context = (event->state & Mod1Mask ? 1 : 0);
-       keylp.lp1.previous = (KeyDown ? 0 : 1);
-       keylp.lp1.transition = 0;
-       msg.lParam  = keylp.lp2;
-#ifdef DEBUG_KEY
-       printf("            wParam=%X, lParam=%lX\n", msg.wParam, msg.lParam);
-#endif
-       msg.time = event->time;
-       msg.pt.x = event->x & 0xffff;
-       msg.pt.y = event->y & 0xffff;
-    
-       hardware_event( hwnd, WM_KEYDOWN, vkey, keylp.lp2,
-                       event->x & 0xffff, event->y & 0xffff, event->time, 0 );
-       KeyDown = TRUE;
-
-       /* The key translation ought to take place in TranslateMessage().
-        * However, there is no way of passing the required information 
-        * in a Windows message, so TranslateMessage does not currently
-        * do anything and the translation is done here.
-        */
-       if (count == 1)                /* key has an ASCII representation */
-       {
-           msg.hwnd    = hwnd;
-           msg.message = WM_CHAR;
-           msg.wParam  = (WORD)Str[0];
-           msg.lParam  = keylp.lp2;
-#ifdef DEBUG_KEY
-       printf("WM_CHAR :   wParam=%X\n", msg.wParam);
-#endif
-           msg.time = event->time;
-           msg.pt.x = event->x & 0xffff;
-           msg.pt.y = event->y & 0xffff;
-           PostMessage( hwnd, WM_CHAR, (WORD)Str[0], keylp.lp2 );
-       }
+        *px = *py = 0;
+        return;
     }
-    else
+
+    for (;;)
     {
-       msg.hwnd    = hwnd;
-       msg.message = WM_KEYUP;
-       msg.wParam  = vkey;
-       keylp.lp1.count = 1;
-       keylp.lp1.code = LOBYTE(event->keycode);
-       keylp.lp1.extended = (extended ? 1 : 0);
-       keylp.lp1.context = (event->state & Mod1Mask ? 1 : 0);
-       keylp.lp1.previous = 1;
-       keylp.lp1.transition = 1;
-       msg.lParam  = keylp.lp2;
-#ifdef DEBUG_KEY
-       printf("            wParam=%X, lParam=%lX\n", msg.wParam, msg.lParam);
-#endif
-       msg.time = event->time;
-       msg.pt.x = event->x & 0xffff;
-       msg.pt.y = event->y & 0xffff;
-    
-       hardware_event( hwnd, WM_KEYUP, vkey, keylp.lp2,
-                       event->x & 0xffff, event->y & 0xffff, event->time, 0 );
-       KeyDown = FALSE;
+        if (!TSXQueryTree(display, win, &root, &parent, &children, &nb_children))
+            return;
+        TSXFree( children );
+        if (parent == rootWindow) break;
+        win = parent;
+        if (!TSXGetGeometry( display, win, &root, &xpos, &ypos,
+                           &width, &height, &border, &depth )) return;
+        *px += xpos;
+        *py += ypos;
     }
 }
 
 
-/***********************************************************************
- *           EVENT_mouse_motion
+/**********************************************************************
+ *              EVENT_ConfigureNotify
  *
- * Handle a X mouse motion event
+ * The ConfigureNotify event is only selected on top-level windows
+ * when the -managed flag is used.
  */
-static void EVENT_mouse_motion( Widget w, int hwnd, XMotionEvent *event, 
-                               Boolean *cont_dispatch )
+static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event )
 {
-    WND * wndPtr = WIN_FindWndPtr( hwnd );
-    if (!wndPtr) return;
+    WINDOWPOS32 winpos;
+    RECT32 newWindowRect, newClientRect;
+    HRGN32 hrgnOldPos, hrgnNewPos;
+    Window above = event->above;
+    int x, y;
+    unsigned int width, height;
+
+    assert (pWnd->flags & WIN_MANAGED);
+
+    /* We don't rely on the event geometry info, because it is relative
+     * to parent and not to root, and it may be wrong (XFree sets x,y to 0,0
+     * if the window hasn't moved).
+     */
+    EVENT_GetGeometry( event->window, &x, &y, &width, &height );
+
+    /* Fill WINDOWPOS struct */
+    winpos.flags = SWP_NOACTIVATE | SWP_NOZORDER;
+    winpos.hwnd = pWnd->hwndSelf;
+    winpos.x = x;
+    winpos.y = y;
+    winpos.cx = width;
+    winpos.cy = height;
+
+    /* Check for unchanged attributes */
+    if (winpos.x == pWnd->rectWindow.left && winpos.y == pWnd->rectWindow.top)
+        winpos.flags |= SWP_NOMOVE;
+    if ((winpos.cx == pWnd->rectWindow.right - pWnd->rectWindow.left) &&
+        (winpos.cy == pWnd->rectWindow.bottom - pWnd->rectWindow.top))
+        winpos.flags |= SWP_NOSIZE;
+    else
+    {
+        RECT32 rect = { 0, 0, pWnd->rectWindow.right - pWnd->rectWindow.left,
+                        pWnd->rectWindow.bottom - pWnd->rectWindow.top };
+        DCE_InvalidateDCE( pWnd, &rect );
+    }
 
-      /* Position must be relative to client area */
-    event->x -= wndPtr->rectClient.left - wndPtr->rectWindow.left;
-    event->y -= wndPtr->rectClient.top - wndPtr->rectWindow.top;
+    /* Send WM_WINDOWPOSCHANGING */
+    SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)&winpos );
 
-    hardware_event( hwnd, WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ),
-                   (event->x & 0xffff) | (event->y << 16),
-                   event->x & 0xffff, event->y & 0xffff,
-                   event->time, 0 );               
+    /* Calculate new position and size */
+    newWindowRect.left = x;
+    newWindowRect.right = x + width;
+    newWindowRect.top = y;
+    newWindowRect.bottom = y + height;
+
+    WINPOS_SendNCCalcSize( winpos.hwnd, TRUE, &newWindowRect,
+                           &pWnd->rectWindow, &pWnd->rectClient,
+                           &winpos, &newClientRect );
+
+    hrgnOldPos = CreateRectRgnIndirect32( &pWnd->rectWindow );
+    hrgnNewPos = CreateRectRgnIndirect32( &newWindowRect );
+    CombineRgn32( hrgnOldPos, hrgnOldPos, hrgnNewPos, RGN_DIFF );
+    DeleteObject32(hrgnOldPos);
+    DeleteObject32(hrgnNewPos);
+    /* Set new size and position */
+    pWnd->rectWindow = newWindowRect;
+    pWnd->rectClient = newClientRect;
+    SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)&winpos );
+
+    if (!IsWindow32( winpos.hwnd )) return;
+    if( above == None )                        /* absolute bottom */
+    {
+        WIN_UnlinkWindow( winpos.hwnd );
+        WIN_LinkWindow( winpos.hwnd, HWND_BOTTOM);
+    }
+    else EVENT_QueryZOrder( pWnd );    /* try to outsmart window manager */
 }
 
 
 /***********************************************************************
- *           EVENT_mouse_button
- *
- * Handle a X mouse button event
+ *           EVENT_SelectionRequest
  */
-static void EVENT_mouse_button( Widget w, int hwnd, XButtonEvent *event,
-                               Boolean *cont_dispatch )
+static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event )
 {
-    static WORD messages[3][NB_BUTTONS] = 
+    XSelectionEvent result;
+    Atom           rprop = None;
+    Window         request = event->requestor;
+
+    if(event->target == XA_STRING)
     {
-       { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN },
-       { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP },
-        { WM_LBUTTONDBLCLK, WM_MBUTTONDBLCLK, WM_RBUTTONDBLCLK }
-    };
-    static unsigned long lastClickTime[NB_BUTTONS] = { 0, 0, 0 };
-        
-    int buttonNum, prevTime, type;
-
-    WND * wndPtr = WIN_FindWndPtr( hwnd );
-    if (!wndPtr) return;
-
-      /* Position must be relative to client area */
-    event->x -= wndPtr->rectClient.left - wndPtr->rectWindow.left;
-    event->y -= wndPtr->rectClient.top - wndPtr->rectWindow.top;
-
-    buttonNum = event->button-1;
-    if (buttonNum >= NB_BUTTONS) return;
-    if (event->type == ButtonRelease) type = 1;
-    else
-    {  /* Check if double-click */
-       prevTime = lastClickTime[buttonNum];
-       lastClickTime[buttonNum] = event->time;
-       if (event->time - prevTime < dblclick_time)
+       HANDLE16 hText;
+       LPSTR  text;
+       int    size,i,j;
+
+        rprop = event->property;
+
+       if(rprop == None) rprop = event->target;
+
+        if(event->selection!=XA_PRIMARY) rprop = None;
+        else if(!CLIPBOARD_IsPresent(CF_OEMTEXT)) rprop = None;
+       else
        {
-           WND * wndPtr;
-           CLASS * classPtr;
-           if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return;
-           if (!(classPtr = CLASS_FindClassPtr( wndPtr->hClass ))) return;
-           type = (classPtr->wc.style & CS_DBLCLKS) ? 2 : 0;
+            /* open to make sure that clipboard is available */
+
+           BOOL32 couldOpen = OpenClipboard32( pWnd->hwndSelf );
+           char* lpstr = 0;
+
+           hText = GetClipboardData16(CF_TEXT);
+           text = GlobalLock16(hText);
+           size = GlobalSize16(hText);
+
+           /* remove carriage returns */
+
+           lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
+           for(i=0,j=0; i < size && text[i]; i++ )
+           {
+              if( text[i] == '\r' && 
+                 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
+              lpstr[j++] = text[i];
+           }
+           lpstr[j]='\0';
+
+           TSXChangeProperty(display, request, rprop, 
+                           XA_STRING, 8, PropModeReplace, 
+                           lpstr, j);
+           HeapFree( GetProcessHeap(), 0, lpstr );
+
+           /* close only if we opened before */
+
+           if(couldOpen) CloseClipboard32();
        }
-       else type = 0;
-    }  
-    
-    winHasCursor = event->window;
+    }
 
-    hardware_event( hwnd, messages[type][buttonNum],
-                   EVENT_XStateToKeyState( event->state ),
-                   (event->x & 0xffff) | (event->y << 16),
-                   event->x & 0xffff, event->y & 0xffff,
-                   event->time, 0 );               
+    if(rprop == None) 
+       TRACE(event,"Request for %s ignored\n", TSXGetAtomName(display,event->target));
+
+    result.type = SelectionNotify;
+    result.display = display;
+    result.requestor = request;
+    result.selection = event->selection;
+    result.property = rprop;
+    result.target = event->target;
+    result.time = event->time;
+    TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
 }
 
 
 /***********************************************************************
- *           EVENT_structure
- *
- * Handle a X StructureNotify event
+ *           EVENT_SelectionNotify
  */
-static void EVENT_structure( Widget w, int hwnd, XEvent *event, 
-                            Boolean *cont_dispatch )
+static void EVENT_SelectionNotify( XSelectionEvent *event )
 {
-    MSG msg;
-    
-    msg.hwnd = hwnd;
-    msg.time = GetTickCount();
-    msg.pt.x = 0;
-    msg.pt.y = 0;
+    if (event->selection != XA_PRIMARY) return;
 
-    switch(event->type)
-    {
-      case ConfigureNotify:
-       {
-           HANDLE handle;
-           NCCALCSIZE_PARAMS *params;      
-           XConfigureEvent * evt = (XConfigureEvent *)event;
-           WND * wndPtr = WIN_FindWndPtr( hwnd );
-           if (!wndPtr) return;
-           wndPtr->rectWindow.left   = evt->x;
-           wndPtr->rectWindow.top    = evt->y;
-           wndPtr->rectWindow.right  = evt->x + evt->width;
-           wndPtr->rectWindow.bottom = evt->y + evt->height;
-
-             /* Send WM_NCCALCSIZE message */
-           handle = GlobalAlloc( GMEM_MOVEABLE, sizeof(*params) );
-           params = (NCCALCSIZE_PARAMS *)GlobalLock( handle );
-           params->rgrc[0] = wndPtr->rectWindow;
-           params->lppos   = NULL;  /* Should be WINDOWPOS struct */
-           SendMessage( hwnd, WM_NCCALCSIZE, FALSE, params );
-           wndPtr->rectClient = params->rgrc[0];
-           PostMessage( hwnd, WM_MOVE, 0,
-                            MAKELONG( wndPtr->rectClient.left,
-                                      wndPtr->rectClient.top ));
-           PostMessage( hwnd, WM_SIZE, SIZE_RESTORED,
-                  MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
-                           wndPtr->rectClient.bottom-wndPtr->rectClient.top));
-           GlobalUnlock( handle );
-           GlobalFree( handle );
-       }
-       break;
-       
-    }    
+    if (event->target != XA_STRING) CLIPBOARD_ReadSelection( 0, None );
+    else CLIPBOARD_ReadSelection( event->requestor, event->property );
+
+    TRACE(clipboard,"\tSelectionNotify done!\n");
+}
+
+
+/***********************************************************************
+ *           EVENT_SelectionClear
+ */
+static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event )
+{
+    if (event->selection != XA_PRIMARY) return;
+    CLIPBOARD_ReleaseSelection( event->window, pWnd->hwndSelf ); 
 }
 
 
 /**********************************************************************
- *              EVENT_focus_change
+ *           EVENT_DropFromOffix
  *
- * Handle an X FocusChange event
+ * don't know if it still works (last Changlog is from 96/11/04)
  */
-static void EVENT_focus_change( Widget w, int hwnd, XEvent *event, 
-                              Boolean *cont_dispatch )
+static void EVENT_DropFromOffiX( WND *pWnd, XClientMessageEvent *event )
 {
-    switch(event->type)
+  unsigned long                data_length;
+  unsigned long                aux_long;
+  unsigned char*       p_data = NULL;
+  union {
+    Atom               atom_aux;
+    POINT32    pt_aux;
+    int                i;
+  }            u;
+  int                  x, y;
+  BOOL16               bAccept;
+  HGLOBAL16            hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
+  LPDRAGINFO            lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
+  SEGPTR               spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
+  Window               w_aux_root, w_aux_child;
+  WND*                 pDropWnd;
+  
+  if( !lpDragInfo || !spDragInfo ) return;
+  
+  TSXQueryPointer( display, pWnd->window, &w_aux_root, &w_aux_child, 
+                  &x, &y, &u.pt_aux.x, &u.pt_aux.y, (unsigned int*)&aux_long);
+  
+  lpDragInfo->hScope = pWnd->hwndSelf;
+  lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
+  
+  /* find out drop point and drop window */
+  if( x < 0 || y < 0 ||
+      x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
+      y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
+    {   bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
+  else
     {
-      case FocusIn:
+      bAccept = DRAG_QueryUpdate( pWnd->hwndSelf, spDragInfo, TRUE );
+      x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
+    }
+  pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
+  GlobalFree16( hDragInfo );
+  
+  if( bAccept )
+    {
+      TSXGetWindowProperty( display, DefaultRootWindow(display),
+                           dndSelection, 0, 65535, FALSE,
+                           AnyPropertyType, &u.atom_aux, &u.pt_aux.y,
+                           &data_length, &aux_long, &p_data);
+      
+      if( !aux_long && p_data) /* don't bother if > 64K */
        {
-           PostMessage( hwnd, WM_SETFOCUS, hwnd, 0 );
-           hWndFocus = hwnd;
+         char *p = (char*) p_data;
+         char *p_drop;
+         
+         aux_long = 0; 
+         while( *p )   /* calculate buffer size */
+           {
+             p_drop = p;
+             if((u.i = *p) != -1 ) 
+               u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
+             if( u.i == -1 ) *p = -1;  /* mark as "bad" */
+             else
+               {
+                 INT32 len = GetShortPathName32A( p, NULL, 0 );
+                 if (len) aux_long += len + 1;
+                 else *p = -1;
+               }
+             p += strlen(p) + 1;
+           }
+         if( aux_long && aux_long < 65535 )
+           {
+             HDROP16                 hDrop;
+             LPDROPFILESTRUCT16        lpDrop;
+             
+             aux_long += sizeof(DROPFILESTRUCT16) + 1; 
+             hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
+             lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop );
+             
+             if( lpDrop )
+               {
+                 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
+                 lpDrop->ptMousePos.x = (INT16)x;
+                 lpDrop->ptMousePos.y = (INT16)y;
+                 lpDrop->fInNonClientArea = (BOOL16) 
+                   ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left)  ||
+                     y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top)    ||
+                     x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
+                     y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
+                 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
+                 p = p_data;
+                 while(*p)
+                   {
+                     if( *p != -1 )    /* use only "good" entries */
+                       {
+                          GetShortPathName32A( p, p_drop, 65535 );
+                          p_drop += strlen( p_drop ) + 1;
+                       }
+                     p += strlen(p) + 1;
+                   }
+                 *p_drop = '\0';
+                 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
+                                (WPARAM16)hDrop, 0L );
+               }
+           }
        }
-       break;
+      if( p_data ) TSXFree(p_data);  
+      
+    } /* WS_EX_ACCEPTFILES */
+}
+
+/**********************************************************************
+ *           EVENT_DropURLs
+ *
+ * drop items are separated by \n 
+ * each item is prefixed by its mime type
+ *
+ * event->data.l[3], event->data.l[4] contains drop x,y position
+ */
+static void EVENT_DropURLs( WND *pWnd, XClientMessageEvent *event )
+{
+  WND           *pDropWnd;
+  unsigned long        data_length;
+  unsigned long        aux_long, drop_len = 0;
+  unsigned char        *p_data = NULL; /* property data */
+  char         *p_drop = NULL;
+  char          *p, *next;
+  int          x, y, drop32 = FALSE ;
+  union {
+    Atom       atom_aux;
+    POINT32    pt_aux;
+    int         i;
+    Window      w_aux;
+  }            u; /* unused */
+  union {
+    HDROP16     h16;
+    HDROP32     h32;
+  } hDrop;
+
+  drop32 = pWnd->flags & WIN_ISWIN32;
+
+  if (!(pWnd->dwExStyle & WS_EX_ACCEPTFILES))
+    return;
+
+  TSXGetWindowProperty( display, DefaultRootWindow(display),
+                       dndSelection, 0, 65535, FALSE,
+                       AnyPropertyType, &u.atom_aux, &u.i,
+                       &data_length, &aux_long, &p_data);
+  if (aux_long)
+    WARN(event,"property too large, truncated!\n");
+  TRACE(event,"urls=%s\n", p_data);
+
+  if( !aux_long && p_data) {   /* don't bother if > 64K */
+    /* calculate length */
+    p = p_data;
+    next = strchr(p, '\n');
+    while (p) {
+      if (next) *next=0;
+      if (strncmp(p,"file:",5) == 0 ) {
+       INT32 len = GetShortPathName32A( p+5, NULL, 0 );
+       if (len) drop_len += len + 1;
+      }
+      if (next) { 
+       *next = '\n'; 
+       p = next + 1;
+       next = strchr(p, '\n');
+      } else {
+       p = NULL;
+      }
+    }
+    
+    if( drop_len && drop_len < 65535 ) {
+      TSXQueryPointer( display, rootWindow, &u.w_aux, &u.w_aux, 
+                      &x, &y, &u.i, &u.i, &u.i);
+      pDropWnd = WIN_FindWndPtr( pWnd->hwndSelf );
+      
+      if (drop32) {
+       LPDROPFILESTRUCT32        lpDrop;
+       drop_len += sizeof(DROPFILESTRUCT32) + 1; 
+       hDrop.h32 = (HDROP32)GlobalAlloc32( GMEM_SHARE, drop_len );
+       lpDrop = (LPDROPFILESTRUCT32) GlobalLock32( hDrop.h32 );
        
-      case FocusOut:
-       {
-           if (hWndFocus)
-           {
-               PostMessage( hwnd, WM_KILLFOCUS, hwnd, 0 );
-               hWndFocus = 0;
+       if( lpDrop ) {
+         lpDrop->lSize = sizeof(DROPFILESTRUCT32);
+         lpDrop->ptMousePos.x = (INT32)x;
+         lpDrop->ptMousePos.y = (INT32)y;
+         lpDrop->fInNonClientArea = (BOOL32) 
+           ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left)  ||
+             y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top)    ||
+             x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
+             y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
+         lpDrop->fWideChar = FALSE;
+         p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT32);
+       }
+      } else {
+       LPDROPFILESTRUCT16        lpDrop;
+       drop_len += sizeof(DROPFILESTRUCT16) + 1; 
+       hDrop.h16 = (HDROP16)GlobalAlloc16( GMEM_SHARE, drop_len );
+       lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop.h16 );
+       
+       if( lpDrop ) {
+         lpDrop->wSize = sizeof(DROPFILESTRUCT16);
+         lpDrop->ptMousePos.x = (INT16)x;
+         lpDrop->ptMousePos.y = (INT16)y;
+         lpDrop->fInNonClientArea = (BOOL16) 
+           ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left)  ||
+             y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top)    ||
+             x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
+             y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
+         p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
+       }
+      }
+      
+      /* create message content */
+      if (p_drop) {
+       p = p_data;
+       next = strchr(p, '\n');
+       while (p) {
+         if (next) *next=0;
+         if (strncmp(p,"file:",5) == 0 ) {
+           INT32 len = GetShortPathName32A( p+5, p_drop, 65535 );
+           if (len) {
+             TRACE(event, "drop file %s as %s\n", p+5, p_drop);
+             p_drop += len+1;
+           } else {
+             WARN(event, "can't convert file %s to dos name \n", p+5);
            }
+         } else {
+           WARN(event, "unknown mime type %s\n", p);
+         }
+         if (next) { 
+           *next = '\n'; 
+           p = next + 1;
+           next = strchr(p, '\n');
+         } else {
+           p = NULL;
+         }
+         *p_drop = '\0';
        }
-    }    
+
+       if (drop32) {
+         /* can not use PostMessage32A because it is currently based on 
+          * PostMessage16 and WPARAM32 would be truncated to WPARAM16
+          */
+         GlobalUnlock32(hDrop.h32);
+         SendMessage32A( pWnd->hwndSelf, WM_DROPFILES,
+                         (WPARAM32)hDrop.h32, 0L );
+       } else {
+         GlobalUnlock16(hDrop.h16);
+         PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
+                        (WPARAM16)hDrop.h16, 0L );
+       }
+      }
+    }
+    if( p_data ) TSXFree(p_data);  
+  }
 }
 
+/**********************************************************************
+ *           EVENT_ClientMessage
+ */
+static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event )
+{
+    if (event->message_type != None && event->format == 32) {
+      if ((event->message_type == wmProtocols) && 
+         (((Atom) event->data.l[0]) == wmDeleteWindow))
+       SendMessage16( pWnd->hwndSelf, WM_SYSCOMMAND, SC_CLOSE, 0 );
+      else if ( event->message_type == dndProtocol &&
+               (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
+       EVENT_DropFromOffiX(pWnd, event);
+      else if ( event->message_type == dndProtocol &&
+               event->data.l[0] == DndURL )
+       EVENT_DropURLs(pWnd, event);
+      else {
+#if 0
+       /* enable this if you want to see the message */
+       unsigned char* p_data = NULL;
+       union {
+         unsigned long l;
+         int                   i;
+         Atom          atom;
+       } u; /* unused */
+       TSXGetWindowProperty( display, DefaultRootWindow(display),
+                             dndSelection, 0, 65535, FALSE,
+                             AnyPropertyType, &u.atom, &u.i,
+                             &u.l, &u.l, &p_data);
+       TRACE(event, "message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
+             event->message_type, event->data.l[0], event->data.l[1], 
+             event->data.l[2], event->data.l[3], event->data.l[4],
+             p_data);
+#endif
+       TRACE(event, "unrecognized ClientMessage\n" );
+      }
+    }
+}
 
 /**********************************************************************
- *              EVENT_enter_notify
+ *           EVENT_EnterNotify
  *
- * Handle an X EnterNotify event
+ * Install colormap when Wine window is focused in
+ * self-managed mode with private colormap
+ */
+/*
+  void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
+  {
+   if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
+     (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
+      TSXInstallColormap( display, COLOR_GetColormap() );
+  }
+ */ 
+
+/**********************************************************************
+ *             EVENT_MapNotify
  */
-static void EVENT_enter_notify( Widget w, int hwnd, XCrossingEvent *event, 
-                              Boolean *cont_dispatch )
+void EVENT_MapNotify( HWND32 hWnd, XMapEvent *event )
 {
-    if (captureWnd != 0) return;
+    HWND32 hwndFocus = GetFocus32();
 
-    winHasCursor = event->window;
+    if (hwndFocus && IsChild32( hWnd, hwndFocus ))
+      FOCUS_SetXFocus( (HWND32)hwndFocus );
 
-    switch(event->type)
-    {
-      case EnterNotify:
-       PostMessage( hwnd, WM_SETCURSOR, hwnd, 0 );
-       break;
-    }    
+    return;
 }
 
-
 /**********************************************************************
- *             SetCapture      (USER.18)
+ *              EVENT_Capture
+ * 
+ * We need this to be able to generate double click messages
+ * when menu code captures mouse in the window without CS_DBLCLK style.
  */
-HWND SetCapture(HWND wnd)
+HWND32 EVENT_Capture(HWND32 hwnd, INT16 ht)
 {
-    int rv;
-    HWND old_capture_wnd = captureWnd;
-    WND *wnd_p = WIN_FindWndPtr(wnd);
-    if (wnd_p == NULL)
-       return 0;
-    
-#ifdef USE_XLIB
-    rv = XGrabPointer(XT_display, wnd_p->window, False, 
-                     ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
-                     GrabModeAsync, GrabModeSync, None, None, CurrentTime);
-#else
-    rv = XtGrabPointer(wnd_p->winWidget, False, 
-                      ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
-                      GrabModeAsync, GrabModeSync, None, None, CurrentTime);
-#endif
+    HWND32 capturePrev = captureWnd;
 
-    if (rv == GrabSuccess)
+    if (!hwnd)
     {
-       captureWnd = wnd;
-       return old_capture_wnd;
+        captureWnd = 0L;
+        captureHT = 0; 
     }
     else
-       return 0;
+    {
+       WND* wndPtr = WIN_FindWndPtr( hwnd );
+        if (wndPtr)
+       {
+            TRACE(win, "(0x%04x)\n", hwnd );
+            captureWnd   = hwnd;
+           captureHT    = ht;
+        }
+    }
+
+    if( capturePrev && capturePrev != captureWnd )
+    {
+       WND* wndPtr = WIN_FindWndPtr( capturePrev );
+        if( wndPtr && (wndPtr->flags & WIN_ISWIN32) )
+            SendMessage32A( capturePrev, WM_CAPTURECHANGED, 0L, hwnd);
+    }
+    return capturePrev;
 }
 
 /**********************************************************************
- *             ReleaseCapture  (USER.19)
+ *              EVENT_GetCaptureInfo
  */
-void ReleaseCapture()
+INT16 EVENT_GetCaptureInfo()
 {
-    WND *wnd_p;
-    
-    if (captureWnd == 0)
-       return;
-    
-    wnd_p = WIN_FindWndPtr(captureWnd);
-    if (wnd_p == NULL)
-       return;
-    
-#ifdef USE_XLIB
-    XUngrabPointer( XT_display, CurrentTime );
-#else
-    XtUngrabPointer(wnd_p->winWidget, CurrentTime);
-#endif
+    return captureHT;
+}
+
+/**********************************************************************
+ *             SetCapture16   (USER.18)
+ */
+HWND16 WINAPI SetCapture16( HWND16 hwnd )
+{
+    return (HWND16)EVENT_Capture( hwnd, HTCLIENT );
+}
 
-    captureWnd = 0;
+
+/**********************************************************************
+ *             SetCapture32   (USER32.464)
+ */
+HWND32 WINAPI SetCapture32( HWND32 hwnd )
+{
+    return EVENT_Capture( hwnd, HTCLIENT );
 }
 
+
 /**********************************************************************
- *             GetCapture      (USER.236)
+ *             ReleaseCapture   (USER.19) (USER32.439)
  */
-HWND GetCapture()
+void WINAPI ReleaseCapture(void)
+{
+    TRACE(win, "captureWnd=%04x\n", captureWnd );
+    if( captureWnd ) EVENT_Capture( 0, 0 );
+}
+
+
+/**********************************************************************
+ *             GetCapture16   (USER.236)
+ */
+HWND16 WINAPI GetCapture16(void)
 {
     return captureWnd;
 }
+
+
 /**********************************************************************
- *             SetDoubleClickTime  (USER.20)
+ *             GetCapture32   (USER32.208)
  */
-void SetDoubleClickTime (WORD interval)
+HWND32 WINAPI GetCapture32(void)
 {
-       if (interval == 0)
-               dblclick_time = 500;
-       else
-               dblclick_time = interval;
-}              
+    return captureWnd;
+}
+
+
+
+/***********************************************************************
+ * Mouse driver routines:
+ */
+
+#pragma pack(1)
+typedef struct _MOUSEINFO
+{
+    BYTE msExist;
+    BYTE msRelative;
+    WORD msNumButtons;
+    WORD msRate;
+    WORD msXThreshold;
+    WORD msYThreshold;
+    WORD msXRes;
+    WORD msYRes;
+    WORD msMouseCommPort;
+} MOUSEINFO;
+#pragma pack(4)
+
+static SEGPTR MouseEventProc = 0;
+
+/***********************************************************************
+ *           MouseInquire                       (MOUSE.1)
+ */
+
+WORD WINAPI MouseInquire(MOUSEINFO *mouseInfo)
+{
+    mouseInfo->msExist = TRUE;
+    mouseInfo->msRelative = FALSE;
+    mouseInfo->msNumButtons = 2;
+    mouseInfo->msRate = 34;  /* the DDK says so ... */
+    mouseInfo->msXThreshold = 0;
+    mouseInfo->msYThreshold = 0;
+    mouseInfo->msXRes = 0;
+    mouseInfo->msYRes = 0;
+    mouseInfo->msMouseCommPort = 0;
+
+    return sizeof(MOUSEINFO);
+}
+
+/***********************************************************************
+ *           MouseEnable                        (MOUSE.2)
+ */
+VOID WINAPI MouseEnable(SEGPTR eventProc)
+{
+    MouseEventProc = eventProc;
+}
+
+/***********************************************************************
+ *           MouseDisable                       (MOUSE.3)
+ */
+VOID WINAPI MouseDisable(VOID)
+{
+    MouseEventProc = 0;
+}
+
+/***********************************************************************
+ *           EVENT_SendMouseEvent
+ */
+static void EVENT_SendMouseEvent( WORD mouseStatus, WORD deltaX, WORD deltaY, 
+                                  WORD buttonCount, DWORD extraInfo )
+{
+    CONTEXT context;
+
+    if ( !MouseEventProc ) return;
+
+    TRACE( keyboard, "(%04X,%d,%d,%d,%ld)\n", mouseStatus, deltaX, deltaY, buttonCount, extraInfo );
+
+    mouseStatus |= 0x8000;
+    deltaX = (((long)deltaX << 16) + screenWidth/2)  / screenWidth;
+    deltaY = (((long)deltaY << 16) + screenHeight/2) / screenHeight;
+
+    memset( &context, 0, sizeof(context) );
+    CS_reg(&context)  = SELECTOROF( MouseEventProc );
+    EIP_reg(&context) = OFFSETOF( MouseEventProc );
+    EAX_reg(&context) = mouseStatus;
+    EBX_reg(&context) = deltaX;
+    ECX_reg(&context) = deltaY;
+    EDX_reg(&context) = buttonCount;
+    ESI_reg(&context) = LOWORD( extraInfo );
+    EDI_reg(&context) = HIWORD( extraInfo );
+
+    Callbacks->CallRegisterShortProc( &context, 0 );
+}
+
+
+
+
+/***********************************************************************
+ *           GetMouseEventProc   (USER.337)
+ */
+FARPROC16 WINAPI GetMouseEventProc(void)
+{
+    HMODULE16 hmodule = GetModuleHandle16("USER");
+    return NE_GetEntryPoint( hmodule, NE_GetOrdinal( hmodule, "Mouse_Event" ));
+}
+
+
+/***********************************************************************
+ *           Mouse_Event   (USER.299)
+ */
+void WINAPI Mouse_Event( CONTEXT *context )
+{
+    /* Register values:
+     * AX = mouse event
+     * BX = horizontal displacement if AX & ME_MOVE
+     * CX = vertical displacement if AX & ME_MOVE
+     * DX = button state (?)
+     * SI = mouse event flags (?)
+     */
+    Window root, child;
+    int rootX, rootY, winX, winY;
+    unsigned int state;
+
+    if (AX_reg(context) & ME_MOVE)
+    {
+        /* We have to actually move the cursor */
+        TSXWarpPointer( display, rootWindow, None, 0, 0, 0, 0,
+                      (short)BX_reg(context), (short)CX_reg(context) );
+        return;
+    }
+    if (!TSXQueryPointer( display, rootWindow, &root, &child,
+                        &rootX, &rootY, &winX, &winY, &state )) return;
+    if (AX_reg(context) & ME_LDOWN)
+        hardware_event( WM_LBUTTONDOWN, EVENT_XStateToKeyState( state ),
+                        0L, winX, winY, GetTickCount(), 0 );
+    if (AX_reg(context) & ME_LUP)
+        hardware_event( WM_LBUTTONUP, EVENT_XStateToKeyState( state ),
+                        0L, winX, winY, GetTickCount(), 0 );
+    if (AX_reg(context) & ME_RDOWN)
+        hardware_event( WM_RBUTTONDOWN, EVENT_XStateToKeyState( state ),
+                        0L, winX, winY, GetTickCount(), 0 );
+    if (AX_reg(context) & ME_RUP)
+        hardware_event( WM_RBUTTONUP, EVENT_XStateToKeyState( state ),
+                        0L, winX, winY, GetTickCount(), 0 );
+}
+
 
 /**********************************************************************
- *             GetDoubleClickTime  (USER.21)
+ *                     EnableHardwareInput   (USER.331)
  */
-WORD GetDoubleClickTime ()
+BOOL16 WINAPI EnableHardwareInput(BOOL16 bEnable)
 {
-       return ((WORD)dblclick_time);
-}              
+  BOOL16 bOldState = InputEnabled;
+  FIXME(event,"(%d) - stub\n", bEnable);
+  InputEnabled = bEnable;
+  return bOldState;
+}
 
 
+/***********************************************************************
+ *          SwapMouseButton16   (USER.186)
+ */
+BOOL16 WINAPI SwapMouseButton16( BOOL16 fSwap )
+{
+    BOOL16 ret = SwappedButtons;
+    SwappedButtons = fSwap;
+    return ret;
+}
+
+
+/***********************************************************************
+ *          SwapMouseButton32   (USER32.537)
+ */
+BOOL32 WINAPI SwapMouseButton32( BOOL32 fSwap )
+{
+    BOOL32 ret = SwappedButtons;
+    SwappedButtons = fSwap;
+    return ret;
+}