Added Drag&Drop from KDE app to 16/32 bit Windoze app.
[wine] / windows / event.c
1 /*
2  * X events handling functions
3  * 
4  * Copyright 1993 Alexandre Julliard
5  * 
6  */
7
8 #include <assert.h>
9 #include <ctype.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <sys/time.h>
14 #include <sys/types.h>
15 #include <errno.h>
16 #include <X11/keysym.h>
17 #include "ts_xlib.h"
18 #include "ts_xresource.h"
19 #include "ts_xutil.h"
20 #include <X11/Xatom.h>
21
22 #include "windows.h"
23 #include "winnt.h"
24 #include "gdi.h"
25 #include "heap.h"
26 #include "queue.h"
27 #include "win.h"
28 #include "class.h"
29 #include "clipboard.h"
30 #include "dce.h"
31 #include "message.h"
32 #include "module.h"
33 #include "options.h"
34 #include "queue.h"
35 #include "winpos.h"
36 #include "drive.h"
37 #include "shell.h"
38 #include "keyboard.h"
39 #include "debug.h"
40 #include "dde_proc.h"
41 #include "winsock.h"
42 #include "callback.h"
43
44
45 #define NB_BUTTONS      3     /* Windows can handle 3 buttons */
46
47 #define DndNotDnd       -1    /* OffiX drag&drop */
48 #define DndUnknown      0
49 #define DndRawData      1
50 #define DndFile         2
51 #define DndFiles        3
52 #define DndText         4
53 #define DndDir          5
54 #define DndLink         6
55 #define DndExe          7
56
57 #define DndEND          8
58
59 #define DndURL          128   /* KDE drag&drop */
60
61
62   /* X context to associate a hwnd to an X window */
63 static XContext winContext = 0;
64
65 static INT16  captureHT = HTCLIENT;
66 static HWND32 captureWnd = 0;
67 static BOOL32 InputEnabled = TRUE;
68 static BOOL32 SwappedButtons = FALSE;
69
70 static Atom wmProtocols = None;
71 static Atom wmDeleteWindow = None;
72 static Atom dndProtocol = None;
73 static Atom dndSelection = None;
74
75 /* EVENT_WaitNetEvent() master fd sets */
76
77 static fd_set __event_io_set[3];
78 static int    __event_max_fd = 0;
79 static int    __event_x_connection = 0;
80
81 static const char * const event_names[] =
82 {
83     "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
84     "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
85     "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
86     "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
87     "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
88     "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
89     "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
90     "ClientMessage", "MappingNotify"
91 };
92
93   /* Event handlers */
94 static void EVENT_Key( WND *pWnd, XKeyEvent *event );
95 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event );
96 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event );
97 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event );
98 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event );
99 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event );
100 static void EVENT_Expose( WND *pWnd, XExposeEvent *event );
101 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event );
102 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event );
103 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event);
104 static void EVENT_SelectionNotify( XSelectionEvent *event);
105 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event);
106 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event );
107 static void EVENT_MapNotify( HWND32 hwnd, XMapEvent *event );
108
109 /* Usable only with OLVWM - compile option perhaps?
110 static void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event );
111 */
112
113 static void EVENT_SendMouseEvent( WORD mouseStatus, WORD deltaX, WORD deltaY, 
114                                   WORD buttonCount, DWORD extraInfo );
115
116 /***********************************************************************
117  *           EVENT_Init
118  *
119  * Initialize network IO.
120  */
121 BOOL32 EVENT_Init(void)
122 {
123     int  i;
124     for( i = 0; i < 3; i++ )
125         FD_ZERO( __event_io_set + i );
126
127     __event_max_fd = __event_x_connection = ConnectionNumber(display);
128     FD_SET( __event_x_connection, &__event_io_set[EVENT_IO_READ] );
129     __event_max_fd++;
130     return TRUE;
131 }
132
133 /***********************************************************************
134  *          EVENT_AddIO 
135  */
136 void EVENT_AddIO( int fd, unsigned io_type )
137 {
138     FD_SET( fd, &__event_io_set[io_type] );
139     if( __event_max_fd <= fd ) __event_max_fd = fd + 1;
140 }
141
142 void EVENT_DeleteIO( int fd, unsigned io_type )
143 {
144     FD_CLR( fd, &__event_io_set[io_type] );
145 }
146
147 /***********************************************************************
148  *           EVENT_ProcessEvent
149  *
150  * Process an X event.
151  */
152 void EVENT_ProcessEvent( XEvent *event )
153 {
154     WND *pWnd;
155     
156     if ( TSXFindContext( display, event->xany.window, winContext,
157                          (char **)&pWnd ) != 0) {
158       if ( event->type == ClientMessage) {
159         /* query window (drag&drop event contains only drag window) */
160         Window          root, child;
161         int             root_x, root_y, child_x, child_y;
162         unsigned        u;
163         TSXQueryPointer( display, rootWindow, &root, &child,
164                          &root_x, &root_y, &child_x, &child_y, &u);
165         if (TSXFindContext( display, child, winContext, (char **)&pWnd ) != 0)
166           return;
167       } else {
168         return;  /* Not for a registered window */
169       }
170     }
171
172     TRACE(event, "Got event %s for hwnd %04x\n",
173           event_names[event->type], pWnd->hwndSelf );
174
175     switch(event->type)
176     {
177     case KeyPress:
178     case KeyRelease:
179         if (InputEnabled) EVENT_Key( pWnd, (XKeyEvent*)event );
180         break;
181         
182     case ButtonPress:
183         if (InputEnabled)
184             EVENT_ButtonPress( pWnd, (XButtonEvent*)event );
185         break;
186
187     case ButtonRelease:
188         if (InputEnabled)
189             EVENT_ButtonRelease( pWnd, (XButtonEvent*)event );
190         break;
191
192     case MotionNotify:
193         /* Wine between two fast machines across the overloaded campus
194            ethernet gets very boged down in MotionEvents. The following
195            simply finds the last motion event in the queue and drops
196            the rest. On a good link events are servered before they build
197            up so this doesn't take place. On a slow link this may cause
198            problems if the event order is important. I'm not yet seen
199            of any problems. Jon 7/6/96.
200          */
201         if (InputEnabled)
202         {
203             while (TSXCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
204                                           MotionNotify, event));    
205             EVENT_MotionNotify( pWnd, (XMotionEvent*)event );
206         }
207         break;
208
209     case FocusIn:
210         EVENT_FocusIn( pWnd, (XFocusChangeEvent*)event );
211         break;
212
213     case FocusOut:
214         EVENT_FocusOut( pWnd, (XFocusChangeEvent*)event );
215         break;
216
217     case Expose:
218         EVENT_Expose( pWnd, (XExposeEvent *)event );
219         break;
220
221     case GraphicsExpose:
222         EVENT_GraphicsExpose( pWnd, (XGraphicsExposeEvent *)event );
223         break;
224
225     case ConfigureNotify:
226         EVENT_ConfigureNotify( pWnd, (XConfigureEvent*)event );
227         break;
228
229     case SelectionRequest:
230         EVENT_SelectionRequest( pWnd, (XSelectionRequestEvent *)event );
231         break;
232
233     case SelectionNotify:
234         EVENT_SelectionNotify( (XSelectionEvent *)event );
235         break;
236
237     case SelectionClear:
238         EVENT_SelectionClear( pWnd, (XSelectionClearEvent*) event );
239         break;
240
241     case ClientMessage:
242         EVENT_ClientMessage( pWnd, (XClientMessageEvent *) event );
243         break;
244
245 /*  case EnterNotify:
246  *       EVENT_EnterNotify( pWnd, (XCrossingEvent *) event );
247  *       break;
248  */
249     case NoExpose:
250         break;
251
252     /* We get all these because of StructureNotifyMask. */
253     case UnmapNotify:
254     case CirculateNotify:
255     case CreateNotify:
256     case DestroyNotify:
257     case GravityNotify:
258     case ReparentNotify:
259         break;
260
261     case MapNotify:
262         EVENT_MapNotify( pWnd->hwndSelf, (XMapEvent *)event );
263         break;
264
265     default:    
266         WARN(event, "Unprocessed event %s for hwnd %04x\n",
267                 event_names[event->type], pWnd->hwndSelf );
268         break;
269     }
270 }
271
272
273 /***********************************************************************
274  *           EVENT_RegisterWindow
275  *
276  * Associate an X window to a HWND.
277  */
278 void EVENT_RegisterWindow( WND *pWnd )
279 {
280     if (wmProtocols == None)
281         wmProtocols = TSXInternAtom( display, "WM_PROTOCOLS", True );
282     if (wmDeleteWindow == None)
283         wmDeleteWindow = TSXInternAtom( display, "WM_DELETE_WINDOW", True );
284     if( dndProtocol == None )
285         dndProtocol = TSXInternAtom( display, "DndProtocol" , False );
286     if( dndSelection == None )
287         dndSelection = TSXInternAtom( display, "DndSelection" , False );
288
289     TSXSetWMProtocols( display, pWnd->window, &wmDeleteWindow, 1 );
290
291     if (!winContext) winContext = TSXUniqueContext();
292     TSXSaveContext( display, pWnd->window, winContext, (char *)pWnd );
293 }
294
295 /***********************************************************************
296  *           EVENT_DestroyWindow
297  */
298 void EVENT_DestroyWindow( WND *pWnd )
299 {
300    XEvent xe;
301
302    TSXDeleteContext( display, pWnd->window, winContext );
303    TSXDestroyWindow( display, pWnd->window );
304    while( TSXCheckWindowEvent(display, pWnd->window, NoEventMask, &xe) );
305 }
306
307
308 /***********************************************************************
309  *           IsUserIdle         (USER.333)
310  *
311  * Check if we have pending X events.
312  */
313 BOOL16 WINAPI IsUserIdle(void)
314 {
315     struct timeval timeout = {0, 0};
316     fd_set check_set;
317
318     FD_ZERO(&check_set);
319     FD_SET(__event_x_connection, &check_set);
320     if( select(__event_x_connection + 1, &check_set, NULL, NULL, &timeout) > 0 )
321         return TRUE;
322     return FALSE;
323 }
324
325
326 /***********************************************************************
327  *           EVENT_WaitNetEvent
328  *
329  * Wait for a network event, optionally sleeping until one arrives.
330  * Return TRUE if an event is pending, FALSE on timeout or error
331  * (for instance lost connection with the server).
332  */
333 BOOL32 EVENT_WaitNetEvent( BOOL32 sleep, BOOL32 peek )
334 {
335     XEvent event;
336     LONG maxWait = sleep ? TIMER_GetNextExpiration() : 0;
337     int pending = TSXPending(display);
338
339     /* Wait for an event or a timeout. If maxWait is -1, we have no timeout;
340      * in this case, we fall through directly to the XNextEvent loop.
341      */
342
343     if ((maxWait != -1) && !pending)
344     {
345         int num_pending;
346         struct timeval timeout;
347         fd_set io_set[3];
348
349         memcpy( io_set, __event_io_set, sizeof(io_set) );
350
351         timeout.tv_usec = (maxWait % 1000) * 1000;
352         timeout.tv_sec = maxWait / 1000;
353
354 #ifdef CONFIG_IPC
355         sigsetjmp(env_wait_x, 1);
356         stop_wait_op= CONT;
357             
358         if (DDE_GetRemoteMessage()) {
359             while(DDE_GetRemoteMessage())
360                 ;
361             return TRUE;
362         }
363         stop_wait_op = STOP_WAIT_X;
364         /* The code up to the next "stop_wait_op = CONT" must be reentrant */
365         num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ], 
366                                               &io_set[EVENT_IO_WRITE], 
367                                               &io_set[EVENT_IO_EXCEPT], &timeout );
368         if ( num_pending == 0 )
369         {
370             stop_wait_op = CONT;
371             TIMER_ExpireTimers();
372             return FALSE;
373         }
374         else stop_wait_op = CONT;
375 #else  /* CONFIG_IPC */
376         num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
377                                               &io_set[EVENT_IO_WRITE],
378                                               &io_set[EVENT_IO_EXCEPT], &timeout );
379         if ( num_pending == 0)
380         {
381             /* Timeout or error */
382             TIMER_ExpireTimers();
383             return FALSE;
384         }
385 #endif  /* CONFIG_IPC */
386
387         /*  Winsock asynchronous services */
388
389         if( FD_ISSET( __event_x_connection, &io_set[EVENT_IO_READ]) ) 
390         {
391             num_pending--;
392             if( num_pending )
393                 WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
394         }
395         else /* no X events */
396             return WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
397     }
398     else if(!pending)
399     {                           /* Wait for X11 input. */
400         fd_set set;
401
402         FD_ZERO(&set);
403         FD_SET(__event_x_connection, &set);
404         select(__event_x_connection + 1, &set, 0, 0, 0 );
405     }
406
407     /* Process current X event (and possibly others that occurred in the meantime) */
408
409     EnterCriticalSection(&X11DRV_CritSection);
410     while (XPending( display ))
411     {
412
413 #ifdef CONFIG_IPC
414         if (DDE_GetRemoteMessage())
415         {
416             LeaveCriticalSection(&X11DRV_CritSection);
417             while(DDE_GetRemoteMessage()) ;
418             return TRUE;
419         }
420 #endif  /* CONFIG_IPC */
421
422         XNextEvent( display, &event );
423
424         LeaveCriticalSection(&X11DRV_CritSection);
425         if( peek )
426         {
427           WND*          pWnd;
428           MESSAGEQUEUE* pQ;
429
430
431           /* Check only for those events which can be processed
432            * internally. */
433
434           if( event.type == MotionNotify ||
435               event.type == ButtonPress || event.type == ButtonRelease ||
436               event.type == KeyPress || event.type == KeyRelease ||
437               event.type == SelectionRequest || event.type == SelectionClear ||
438               event.type == ClientMessage )
439           {
440                EVENT_ProcessEvent( &event );
441                continue;
442           }
443
444           if (TSXFindContext( display, ((XAnyEvent *)&event)->window, winContext,
445                             (char **)&pWnd ) || (event.type == NoExpose))
446               continue;
447
448           if( pWnd )
449           {
450             if( (pQ = (MESSAGEQUEUE*)GlobalLock16(pWnd->hmemTaskQ)) )
451             {
452               pQ->flags |= QUEUE_FLAG_XEVENT;
453               PostEvent(pQ->hTask);
454               TSXPutBackEvent(display, &event);
455               break;
456             }
457           }
458         }
459         else EVENT_ProcessEvent( &event );
460         EnterCriticalSection(&X11DRV_CritSection);
461     }
462     LeaveCriticalSection(&X11DRV_CritSection);
463     return TRUE;
464 }
465
466
467 /***********************************************************************
468  *           EVENT_Synchronize
469  *
470  * Synchronize with the X server. Should not be used too often.
471  */
472 void EVENT_Synchronize()
473 {
474     XEvent event;
475
476     /* Use of the X critical section is needed or we have a small
477      * race between XPending() and XNextEvent().
478      */
479     EnterCriticalSection( &X11DRV_CritSection );
480     XSync( display, False );
481     while (XPending( display ))
482     {
483         XNextEvent( display, &event );
484         /* unlock X critsection for EVENT_ProcessEvent() might switch tasks */
485         LeaveCriticalSection( &X11DRV_CritSection );
486         EVENT_ProcessEvent( &event );
487         EnterCriticalSection( &X11DRV_CritSection );
488     }    
489     LeaveCriticalSection( &X11DRV_CritSection );
490 }
491
492 /***********************************************************************
493  *           EVENT_QueryZOrder
494  *
495  * Try to synchronize internal z-order with the window manager's.
496  * Probably a futile endeavor.
497  */
498 static BOOL32 __check_query_condition( WND** pWndA, WND** pWndB )
499 {
500     /* return TRUE if we have at least two managed windows */
501
502     for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
503         if( (*pWndA)->flags & WIN_MANAGED &&
504             (*pWndA)->dwStyle & WS_VISIBLE ) break;
505     if( *pWndA )
506         for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
507             if( (*pWndB)->flags & WIN_MANAGED &&
508                 (*pWndB)->dwStyle & WS_VISIBLE ) break;
509      return ((*pWndB) != NULL);
510 }
511
512 static Window __get_common_ancestor( Window A, Window B,
513                                      Window** children, unsigned* total )
514 {
515     /* find the real root window */
516
517     Window      root, *childrenB;
518     unsigned    totalB;
519
520     do
521     {
522         if( *children ) TSXFree( *children );
523         TSXQueryTree( display, A, &root, &A, children, total );
524         TSXQueryTree( display, B, &root, &B, &childrenB, &totalB );
525         if( childrenB ) TSXFree( childrenB );
526     } while( A != B && A && B );
527     return ( A && B ) ? A : 0 ;
528 }
529
530 static Window __get_top_decoration( Window w, Window ancestor )
531 {
532     Window*     children, root, prev = w, parent = w;
533     unsigned    total;
534
535     do
536     {
537         w = parent;
538         TSXQueryTree( display, w, &root, &parent, &children, &total );
539         if( children ) TSXFree( children );
540     } while( parent && parent != ancestor );
541     TRACE(event, "\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
542     return ( parent ) ? w : 0 ;
543 }
544
545 static unsigned __td_lookup( Window w, Window* list, unsigned max )
546 {
547     unsigned    i;
548     for( i = 0; i < max; i++ ) if( list[i] == w ) break;
549     return i;
550 }
551
552 static BOOL32 EVENT_QueryZOrder( WND* pWndCheck )
553 {
554     BOOL32      bRet = FALSE;
555     HWND32      hwndInsertAfter = HWND_TOP;
556     WND*        pWnd, *pWndZ = WIN_GetDesktop()->child;
557     Window      w, parent, *children = NULL;
558     unsigned    total, check, pos, best;
559
560     if( !__check_query_condition(&pWndZ, &pWnd) ) return TRUE;
561
562     parent = __get_common_ancestor( pWndZ->window, pWnd->window,
563                                       &children, &total );
564     if( parent && children )
565     {
566         w = __get_top_decoration( pWndCheck->window, parent );
567         if( w != children[total - 1] )
568         {
569             check = __td_lookup( w, children, total );
570             best = total;
571             for( pWnd = pWndZ; pWnd; pWnd = pWnd->next )
572             {
573                 if( pWnd != pWndCheck )
574                 {
575                     if( !(pWnd->flags & WIN_MANAGED) ||
576                         !(w = __get_top_decoration( pWnd->window, parent )) )
577                         continue;
578                     pos = __td_lookup( w, children, total );
579                     if( pos < best && pos > check )
580                     {
581                         best = pos;
582                         hwndInsertAfter = pWnd->hwndSelf;
583                     }
584                     if( check - best == 1 ) break;
585                 }
586             }
587             WIN_UnlinkWindow( pWndCheck->hwndSelf );
588             WIN_LinkWindow( pWndCheck->hwndSelf, hwndInsertAfter);
589         }
590     }
591     if( children ) TSXFree( children );
592     return bRet;
593 }
594
595
596 /***********************************************************************
597  *           EVENT_XStateToKeyState
598  *
599  * Translate a X event state (Button1Mask, ShiftMask, etc...) to
600  * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
601  */
602 static WORD EVENT_XStateToKeyState( int state )
603 {
604     int kstate = 0;
605     
606     if (state & Button1Mask) kstate |= MK_LBUTTON;
607     if (state & Button2Mask) kstate |= MK_MBUTTON;
608     if (state & Button3Mask) kstate |= MK_RBUTTON;
609     if (state & ShiftMask)   kstate |= MK_SHIFT;
610     if (state & ControlMask) kstate |= MK_CONTROL;
611     return kstate;
612 }
613
614
615 /***********************************************************************
616  *           EVENT_Expose
617  */
618 static void EVENT_Expose( WND *pWnd, XExposeEvent *event )
619 {
620     RECT32 rect;
621
622     /* Make position relative to client area instead of window */
623     rect.left   = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
624     rect.top    = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
625     rect.right  = rect.left + event->width;
626     rect.bottom = rect.top + event->height;
627
628     PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
629                         RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
630                         (event->count ? 0 : RDW_ERASENOW), 0 );
631 }
632
633
634 /***********************************************************************
635  *           EVENT_GraphicsExpose
636  *
637  * This is needed when scrolling area is partially obscured
638  * by non-Wine X window.
639  */
640 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event )
641 {
642     RECT32 rect;
643
644     /* Make position relative to client area instead of window */
645     rect.left   = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
646     rect.top    = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
647     rect.right  = rect.left + event->width;
648     rect.bottom = rect.top + event->height;
649
650     PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
651                         RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
652                         (event->count ? 0 : RDW_ERASENOW), 0 );
653 }
654
655
656 /***********************************************************************
657  *           EVENT_Key
658  *
659  * Handle a X key event
660  */
661 static void EVENT_Key( WND *pWnd, XKeyEvent *event )
662 {
663     KEYBOARD_HandleEvent( pWnd, event );
664 }
665
666
667 /***********************************************************************
668  *           EVENT_MotionNotify
669  */
670 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event )
671 {
672     hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ), 0L,
673                     pWnd->rectWindow.left + event->x,
674                     pWnd->rectWindow.top + event->y,
675                     event->time - MSG_WineStartTicks, pWnd->hwndSelf );
676
677     EVENT_SendMouseEvent( ME_MOVE, 
678                           pWnd->rectWindow.left + event->x,
679                           pWnd->rectWindow.top + event->y,
680                           0, 0 );
681 }
682
683
684 /***********************************************************************
685  *           EVENT_DummyMotionNotify
686  *
687  * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
688  */
689 void EVENT_DummyMotionNotify(void)
690 {
691     Window root, child;
692     int rootX, rootY, winX, winY;
693     unsigned int state;
694
695     if (TSXQueryPointer( display, rootWindow, &root, &child,
696                        &rootX, &rootY, &winX, &winY, &state ))
697     {
698         hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( state ), 0L,
699                         winX, winY, GetTickCount(), 0 );
700     }
701 }
702
703
704 /***********************************************************************
705  *           EVENT_ButtonPress
706  */
707 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event )
708 {
709     static WORD messages[NB_BUTTONS] = 
710         { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
711     static WORD statusCodes[NB_BUTTONS] = 
712         { ME_LDOWN, 0, ME_RDOWN };
713     int buttonNum = event->button - 1;
714
715     if (buttonNum >= NB_BUTTONS) return;
716     if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
717     MouseButtonsStates[buttonNum] = TRUE;
718     AsyncMouseButtonsStates[buttonNum] = TRUE;
719     hardware_event( messages[buttonNum],
720                     EVENT_XStateToKeyState( event->state ), 0L,
721                     pWnd->rectWindow.left + event->x,
722                     pWnd->rectWindow.top + event->y,
723                     event->time - MSG_WineStartTicks, pWnd->hwndSelf );
724
725     EVENT_SendMouseEvent( statusCodes[buttonNum], 
726                           pWnd->rectWindow.left + event->x,
727                           pWnd->rectWindow.top + event->y,
728                           0, 0 );
729 }
730
731
732 /***********************************************************************
733  *           EVENT_ButtonRelease
734  */
735 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event )
736 {
737     static const WORD messages[NB_BUTTONS] = 
738         { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
739     static WORD statusCodes[NB_BUTTONS] = 
740         { ME_LUP, 0, ME_RUP };
741     int buttonNum = event->button - 1;
742
743     if (buttonNum >= NB_BUTTONS) return;    
744     if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
745     MouseButtonsStates[buttonNum] = FALSE;
746     hardware_event( messages[buttonNum],
747                     EVENT_XStateToKeyState( event->state ), 0L,
748                     pWnd->rectWindow.left + event->x,
749                     pWnd->rectWindow.top + event->y,
750                     event->time - MSG_WineStartTicks, pWnd->hwndSelf );
751
752     EVENT_SendMouseEvent( statusCodes[buttonNum], 
753                           pWnd->rectWindow.left + event->x,
754                           pWnd->rectWindow.top + event->y,
755                           0, 0 );
756 }
757
758
759 /**********************************************************************
760  *              EVENT_FocusIn
761  */
762 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event )
763 {
764     if (Options.managed) EVENT_QueryZOrder( pWnd );
765
766     if (event->detail != NotifyPointer)
767     { 
768         HWND32  hwnd = pWnd->hwndSelf;
769
770         if (hwnd != GetActiveWindow32()) 
771         {
772             WINPOS_ChangeActiveWindow( hwnd, FALSE );
773             KEYBOARD_UpdateState();
774         }
775         if ((hwnd != GetFocus32()) && !IsChild32( hwnd, GetFocus32()))
776             SetFocus32( hwnd );
777     }
778 }
779
780
781 /**********************************************************************
782  *              EVENT_FocusOut
783  *
784  * Note: only top-level override-redirect windows get FocusOut events.
785  */
786 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event )
787 {
788     if (event->detail != NotifyPointer)
789     {
790         HWND32  hwnd = pWnd->hwndSelf;
791
792         if (hwnd == GetActiveWindow32()) 
793             WINPOS_ChangeActiveWindow( 0, FALSE );
794         if ((hwnd == GetFocus32()) || IsChild32( hwnd, GetFocus32()))
795             SetFocus32( 0 );
796     }
797 }
798
799 /**********************************************************************
800  *              EVENT_CheckFocus
801  */
802 BOOL32 EVENT_CheckFocus(void)
803 {
804     WND*   pWnd;
805     Window xW;
806     int    state;
807
808     TSXGetInputFocus(display, &xW, &state);
809     if( xW == None ||
810         TSXFindContext(display, xW, winContext, (char **)&pWnd) ) 
811         return FALSE;
812     return TRUE;
813 }
814
815
816 /**********************************************************************
817  *              EVENT_GetGeometry
818  *
819  * Helper function for ConfigureNotify handling.
820  * Get the new geometry of a window relative to the root window.
821  */
822 static void EVENT_GetGeometry( Window win, int *px, int *py,
823                                unsigned int *pwidth, unsigned int *pheight )
824 {
825     Window root, parent, *children;
826     int xpos, ypos;
827     unsigned int width, height, border, depth, nb_children;
828
829     if (!TSXGetGeometry( display, win, &root, px, py, pwidth, pheight,
830                        &border, &depth )) return;
831     if (win == rootWindow)
832     {
833         *px = *py = 0;
834         return;
835     }
836
837     for (;;)
838     {
839         if (!TSXQueryTree(display, win, &root, &parent, &children, &nb_children))
840             return;
841         TSXFree( children );
842         if (parent == rootWindow) break;
843         win = parent;
844         if (!TSXGetGeometry( display, win, &root, &xpos, &ypos,
845                            &width, &height, &border, &depth )) return;
846         *px += xpos;
847         *py += ypos;
848     }
849 }
850
851
852 /**********************************************************************
853  *              EVENT_ConfigureNotify
854  *
855  * The ConfigureNotify event is only selected on top-level windows
856  * when the -managed flag is used.
857  */
858 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event )
859 {
860     WINDOWPOS32 winpos;
861     RECT32 newWindowRect, newClientRect;
862     HRGN32 hrgnOldPos, hrgnNewPos;
863     Window above = event->above;
864     int x, y;
865     unsigned int width, height;
866
867     assert (pWnd->flags & WIN_MANAGED);
868
869     /* We don't rely on the event geometry info, because it is relative
870      * to parent and not to root, and it may be wrong (XFree sets x,y to 0,0
871      * if the window hasn't moved).
872      */
873     EVENT_GetGeometry( event->window, &x, &y, &width, &height );
874
875     /* Fill WINDOWPOS struct */
876     winpos.flags = SWP_NOACTIVATE | SWP_NOZORDER;
877     winpos.hwnd = pWnd->hwndSelf;
878     winpos.x = x;
879     winpos.y = y;
880     winpos.cx = width;
881     winpos.cy = height;
882
883     /* Check for unchanged attributes */
884     if (winpos.x == pWnd->rectWindow.left && winpos.y == pWnd->rectWindow.top)
885         winpos.flags |= SWP_NOMOVE;
886     if ((winpos.cx == pWnd->rectWindow.right - pWnd->rectWindow.left) &&
887         (winpos.cy == pWnd->rectWindow.bottom - pWnd->rectWindow.top))
888         winpos.flags |= SWP_NOSIZE;
889     else
890     {
891         RECT32 rect = { 0, 0, pWnd->rectWindow.right - pWnd->rectWindow.left,
892                         pWnd->rectWindow.bottom - pWnd->rectWindow.top };
893         DCE_InvalidateDCE( pWnd, &rect );
894     }
895
896     /* Send WM_WINDOWPOSCHANGING */
897     SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)&winpos );
898
899     /* Calculate new position and size */
900     newWindowRect.left = x;
901     newWindowRect.right = x + width;
902     newWindowRect.top = y;
903     newWindowRect.bottom = y + height;
904
905     WINPOS_SendNCCalcSize( winpos.hwnd, TRUE, &newWindowRect,
906                            &pWnd->rectWindow, &pWnd->rectClient,
907                            &winpos, &newClientRect );
908
909     hrgnOldPos = CreateRectRgnIndirect32( &pWnd->rectWindow );
910     hrgnNewPos = CreateRectRgnIndirect32( &newWindowRect );
911     CombineRgn32( hrgnOldPos, hrgnOldPos, hrgnNewPos, RGN_DIFF );
912     DeleteObject32(hrgnOldPos);
913     DeleteObject32(hrgnNewPos);
914  
915     /* Set new size and position */
916     pWnd->rectWindow = newWindowRect;
917     pWnd->rectClient = newClientRect;
918     SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)&winpos );
919
920     if (!IsWindow32( winpos.hwnd )) return;
921     if( above == None )                 /* absolute bottom */
922     {
923         WIN_UnlinkWindow( winpos.hwnd );
924         WIN_LinkWindow( winpos.hwnd, HWND_BOTTOM);
925     }
926     else EVENT_QueryZOrder( pWnd );     /* try to outsmart window manager */
927 }
928
929
930 /***********************************************************************
931  *           EVENT_SelectionRequest
932  */
933 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event )
934 {
935     XSelectionEvent result;
936     Atom            rprop = None;
937     Window          request = event->requestor;
938
939     if(event->target == XA_STRING)
940     {
941         HANDLE16 hText;
942         LPSTR  text;
943         int    size,i,j;
944
945         rprop = event->property;
946
947         if(rprop == None) rprop = event->target;
948
949         if(event->selection!=XA_PRIMARY) rprop = None;
950         else if(!CLIPBOARD_IsPresent(CF_OEMTEXT)) rprop = None;
951         else
952         {
953             /* open to make sure that clipboard is available */
954
955             BOOL32 couldOpen = OpenClipboard32( pWnd->hwndSelf );
956             char* lpstr = 0;
957
958             hText = GetClipboardData16(CF_TEXT);
959             text = GlobalLock16(hText);
960             size = GlobalSize16(hText);
961
962             /* remove carriage returns */
963
964             lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
965             for(i=0,j=0; i < size && text[i]; i++ )
966             {
967                if( text[i] == '\r' && 
968                   (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
969                lpstr[j++] = text[i];
970             }
971             lpstr[j]='\0';
972
973             TSXChangeProperty(display, request, rprop, 
974                             XA_STRING, 8, PropModeReplace, 
975                             lpstr, j);
976             HeapFree( GetProcessHeap(), 0, lpstr );
977
978             /* close only if we opened before */
979
980             if(couldOpen) CloseClipboard32();
981         }
982     }
983
984     if(rprop == None) 
985        TRACE(event,"Request for %s ignored\n", TSXGetAtomName(display,event->target));
986
987     result.type = SelectionNotify;
988     result.display = display;
989     result.requestor = request;
990     result.selection = event->selection;
991     result.property = rprop;
992     result.target = event->target;
993     result.time = event->time;
994     TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
995 }
996
997
998 /***********************************************************************
999  *           EVENT_SelectionNotify
1000  */
1001 static void EVENT_SelectionNotify( XSelectionEvent *event )
1002 {
1003     if (event->selection != XA_PRIMARY) return;
1004
1005     if (event->target != XA_STRING) CLIPBOARD_ReadSelection( 0, None );
1006     else CLIPBOARD_ReadSelection( event->requestor, event->property );
1007
1008     TRACE(clipboard,"\tSelectionNotify done!\n");
1009 }
1010
1011
1012 /***********************************************************************
1013  *           EVENT_SelectionClear
1014  */
1015 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event )
1016 {
1017     if (event->selection != XA_PRIMARY) return;
1018     CLIPBOARD_ReleaseSelection( event->window, pWnd->hwndSelf ); 
1019 }
1020
1021
1022 /**********************************************************************
1023  *           EVENT_DropFromOffix
1024  *
1025  * don't know if it still works (last Changlog is from 96/11/04)
1026  */
1027 static void EVENT_DropFromOffiX( WND *pWnd, XClientMessageEvent *event )
1028 {
1029   unsigned long         data_length;
1030   unsigned long         aux_long;
1031   unsigned char*        p_data = NULL;
1032   union {
1033     Atom                atom_aux;
1034     POINT32     pt_aux;
1035     int         i;
1036   }             u;
1037   int                   x, y;
1038   BOOL16                bAccept;
1039   HGLOBAL16             hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
1040   LPDRAGINFO            lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
1041   SEGPTR                spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
1042   Window                w_aux_root, w_aux_child;
1043   WND*                  pDropWnd;
1044   
1045   if( !lpDragInfo || !spDragInfo ) return;
1046   
1047   TSXQueryPointer( display, pWnd->window, &w_aux_root, &w_aux_child, 
1048                    &x, &y, &u.pt_aux.x, &u.pt_aux.y, (unsigned int*)&aux_long);
1049   
1050   lpDragInfo->hScope = pWnd->hwndSelf;
1051   lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1052   
1053   /* find out drop point and drop window */
1054   if( x < 0 || y < 0 ||
1055       x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1056       y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1057     {   bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1058   else
1059     {
1060       bAccept = DRAG_QueryUpdate( pWnd->hwndSelf, spDragInfo, TRUE );
1061       x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1062     }
1063   pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1064   GlobalFree16( hDragInfo );
1065   
1066   if( bAccept )
1067     {
1068       TSXGetWindowProperty( display, DefaultRootWindow(display),
1069                             dndSelection, 0, 65535, FALSE,
1070                             AnyPropertyType, &u.atom_aux, &u.pt_aux.y,
1071                             &data_length, &aux_long, &p_data);
1072       
1073       if( !aux_long && p_data)  /* don't bother if > 64K */
1074         {
1075           char *p = (char*) p_data;
1076           char *p_drop;
1077           
1078           aux_long = 0; 
1079           while( *p )   /* calculate buffer size */
1080             {
1081               p_drop = p;
1082               if((u.i = *p) != -1 ) 
1083                 u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
1084               if( u.i == -1 ) *p = -1;  /* mark as "bad" */
1085               else
1086                 {
1087                   INT32 len = GetShortPathName32A( p, NULL, 0 );
1088                   if (len) aux_long += len + 1;
1089                   else *p = -1;
1090                 }
1091               p += strlen(p) + 1;
1092             }
1093           if( aux_long && aux_long < 65535 )
1094             {
1095               HDROP16                 hDrop;
1096               LPDROPFILESTRUCT16        lpDrop;
1097               
1098               aux_long += sizeof(DROPFILESTRUCT16) + 1; 
1099               hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
1100               lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop );
1101               
1102               if( lpDrop )
1103                 {
1104                   lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1105                   lpDrop->ptMousePos.x = (INT16)x;
1106                   lpDrop->ptMousePos.y = (INT16)y;
1107                   lpDrop->fInNonClientArea = (BOOL16) 
1108                     ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left)  ||
1109                       y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top)    ||
1110                       x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1111                       y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1112                   p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1113                   p = p_data;
1114                   while(*p)
1115                     {
1116                       if( *p != -1 )    /* use only "good" entries */
1117                         {
1118                           GetShortPathName32A( p, p_drop, 65535 );
1119                           p_drop += strlen( p_drop ) + 1;
1120                         }
1121                       p += strlen(p) + 1;
1122                     }
1123                   *p_drop = '\0';
1124                   PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1125                                  (WPARAM16)hDrop, 0L );
1126                 }
1127             }
1128         }
1129       if( p_data ) TSXFree(p_data);  
1130       
1131     } /* WS_EX_ACCEPTFILES */
1132 }
1133
1134 /**********************************************************************
1135  *           EVENT_DropURLs
1136  *
1137  * drop items are separated by \n 
1138  * each item is prefixed by its mime type
1139  *
1140  * event->data.l[3], event->data.l[4] contains drop x,y position
1141  */
1142 static void EVENT_DropURLs( WND *pWnd, XClientMessageEvent *event )
1143 {
1144   WND           *pDropWnd;
1145   unsigned long data_length;
1146   unsigned long aux_long, drop_len = 0;
1147   unsigned char *p_data = NULL; /* property data */
1148   char          *p_drop = NULL;
1149   char          *p, *next;
1150   int           x, y, drop32 = FALSE ;
1151   union {
1152     Atom        atom_aux;
1153     POINT32     pt_aux;
1154     int         i;
1155     Window      w_aux;
1156   }             u; /* unused */
1157   union {
1158     HDROP16     h16;
1159     HDROP32     h32;
1160   } hDrop;
1161
1162   drop32 = pWnd->flags & WIN_ISWIN32;
1163
1164   if (!(pWnd->dwExStyle & WS_EX_ACCEPTFILES))
1165     return;
1166
1167   TSXGetWindowProperty( display, DefaultRootWindow(display),
1168                         dndSelection, 0, 65535, FALSE,
1169                         AnyPropertyType, &u.atom_aux, &u.i,
1170                         &data_length, &aux_long, &p_data);
1171   if (aux_long)
1172     WARN(event,"property too large, truncated!\n");
1173   TRACE(event,"urls=%s\n", p_data);
1174
1175   if( !aux_long && p_data) {    /* don't bother if > 64K */
1176     /* calculate length */
1177     p = p_data;
1178     next = strchr(p, '\n');
1179     while (p) {
1180       if (next) *next=0;
1181       if (strncmp(p,"file:",5) == 0 ) {
1182         INT32 len = GetShortPathName32A( p+5, NULL, 0 );
1183         if (len) drop_len += len + 1;
1184       }
1185       if (next) { 
1186         *next = '\n'; 
1187         p = next + 1;
1188         next = strchr(p, '\n');
1189       } else {
1190         p = NULL;
1191       }
1192     }
1193     
1194     if( drop_len && drop_len < 65535 ) {
1195       TSXQueryPointer( display, rootWindow, &u.w_aux, &u.w_aux, 
1196                        &x, &y, &u.i, &u.i, &u.i);
1197       pDropWnd = WIN_FindWndPtr( pWnd->hwndSelf );
1198       
1199       if (drop32) {
1200         LPDROPFILESTRUCT32        lpDrop;
1201         drop_len += sizeof(DROPFILESTRUCT32) + 1; 
1202         hDrop.h32 = (HDROP32)GlobalAlloc32( GMEM_SHARE, drop_len );
1203         lpDrop = (LPDROPFILESTRUCT32) GlobalLock32( hDrop.h32 );
1204         
1205         if( lpDrop ) {
1206           lpDrop->lSize = sizeof(DROPFILESTRUCT32);
1207           lpDrop->ptMousePos.x = (INT32)x;
1208           lpDrop->ptMousePos.y = (INT32)y;
1209           lpDrop->fInNonClientArea = (BOOL32) 
1210             ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left)  ||
1211               y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top)    ||
1212               x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1213               y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1214           lpDrop->fWideChar = FALSE;
1215           p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT32);
1216         }
1217       } else {
1218         LPDROPFILESTRUCT16        lpDrop;
1219         drop_len += sizeof(DROPFILESTRUCT16) + 1; 
1220         hDrop.h16 = (HDROP16)GlobalAlloc16( GMEM_SHARE, drop_len );
1221         lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop.h16 );
1222         
1223         if( lpDrop ) {
1224           lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1225           lpDrop->ptMousePos.x = (INT16)x;
1226           lpDrop->ptMousePos.y = (INT16)y;
1227           lpDrop->fInNonClientArea = (BOOL16) 
1228             ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left)  ||
1229               y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top)    ||
1230               x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1231               y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1232           p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1233         }
1234       }
1235       
1236       /* create message content */
1237       if (p_drop) {
1238         p = p_data;
1239         next = strchr(p, '\n');
1240         while (p) {
1241           if (next) *next=0;
1242           if (strncmp(p,"file:",5) == 0 ) {
1243             INT32 len = GetShortPathName32A( p+5, p_drop, 65535 );
1244             if (len) {
1245               TRACE(event, "drop file %s as %s\n", p+5, p_drop);
1246               p_drop += len+1;
1247             } else {
1248               WARN(event, "can't convert file %s to dos name \n", p+5);
1249             }
1250           } else {
1251             WARN(event, "unknown mime type %s\n", p);
1252           }
1253           if (next) { 
1254             *next = '\n'; 
1255             p = next + 1;
1256             next = strchr(p, '\n');
1257           } else {
1258             p = NULL;
1259           }
1260           *p_drop = '\0';
1261         }
1262
1263         if (drop32) {
1264           /* can not use PostMessage32A because it is currently based on 
1265            * PostMessage16 and WPARAM32 would be truncated to WPARAM16
1266            */
1267           GlobalUnlock32(hDrop.h32);
1268           SendMessage32A( pWnd->hwndSelf, WM_DROPFILES,
1269                           (WPARAM32)hDrop.h32, 0L );
1270         } else {
1271           GlobalUnlock16(hDrop.h16);
1272           PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1273                          (WPARAM16)hDrop.h16, 0L );
1274         }
1275       }
1276     }
1277     if( p_data ) TSXFree(p_data);  
1278   }
1279 }
1280
1281 /**********************************************************************
1282  *           EVENT_ClientMessage
1283  */
1284 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event )
1285 {
1286     if (event->message_type != None && event->format == 32) {
1287       if ((event->message_type == wmProtocols) && 
1288           (((Atom) event->data.l[0]) == wmDeleteWindow))
1289         SendMessage16( pWnd->hwndSelf, WM_SYSCOMMAND, SC_CLOSE, 0 );
1290       else if ( event->message_type == dndProtocol &&
1291                 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
1292         EVENT_DropFromOffiX(pWnd, event);
1293       else if ( event->message_type == dndProtocol &&
1294                 event->data.l[0] == DndURL )
1295         EVENT_DropURLs(pWnd, event);
1296       else {
1297 #if 0
1298         /* enable this if you want to see the message */
1299         unsigned char* p_data = NULL;
1300         union {
1301           unsigned long l;
1302           int                   i;
1303           Atom          atom;
1304         } u; /* unused */
1305         TSXGetWindowProperty( display, DefaultRootWindow(display),
1306                               dndSelection, 0, 65535, FALSE,
1307                               AnyPropertyType, &u.atom, &u.i,
1308                               &u.l, &u.l, &p_data);
1309         TRACE(event, "message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1310               event->message_type, event->data.l[0], event->data.l[1], 
1311               event->data.l[2], event->data.l[3], event->data.l[4],
1312               p_data);
1313 #endif
1314         TRACE(event, "unrecognized ClientMessage\n" );
1315       }
1316     }
1317 }
1318
1319 /**********************************************************************
1320  *           EVENT_EnterNotify
1321  *
1322  * Install colormap when Wine window is focused in
1323  * self-managed mode with private colormap
1324  */
1325 /*
1326   void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
1327   {
1328    if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
1329      (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
1330       TSXInstallColormap( display, COLOR_GetColormap() );
1331   }
1332  */ 
1333
1334 /**********************************************************************
1335  *              EVENT_MapNotify
1336  */
1337 void EVENT_MapNotify( HWND32 hWnd, XMapEvent *event )
1338 {
1339     HWND32 hwndFocus = GetFocus32();
1340
1341     if (hwndFocus && IsChild32( hWnd, hwndFocus ))
1342       FOCUS_SetXFocus( (HWND32)hwndFocus );
1343
1344     return;
1345 }
1346
1347 /**********************************************************************
1348  *              EVENT_Capture
1349  * 
1350  * We need this to be able to generate double click messages
1351  * when menu code captures mouse in the window without CS_DBLCLK style.
1352  */
1353 HWND32 EVENT_Capture(HWND32 hwnd, INT16 ht)
1354 {
1355     HWND32 capturePrev = captureWnd;
1356
1357     if (!hwnd)
1358     {
1359         captureWnd = 0L;
1360         captureHT = 0; 
1361     }
1362     else
1363     {
1364         WND* wndPtr = WIN_FindWndPtr( hwnd );
1365         if (wndPtr)
1366         {
1367             TRACE(win, "(0x%04x)\n", hwnd );
1368             captureWnd   = hwnd;
1369             captureHT    = ht;
1370         }
1371     }
1372
1373     if( capturePrev && capturePrev != captureWnd )
1374     {
1375         WND* wndPtr = WIN_FindWndPtr( capturePrev );
1376         if( wndPtr && (wndPtr->flags & WIN_ISWIN32) )
1377             SendMessage32A( capturePrev, WM_CAPTURECHANGED, 0L, hwnd);
1378     }
1379     return capturePrev;
1380 }
1381
1382 /**********************************************************************
1383  *              EVENT_GetCaptureInfo
1384  */
1385 INT16 EVENT_GetCaptureInfo()
1386 {
1387     return captureHT;
1388 }
1389
1390 /**********************************************************************
1391  *              SetCapture16   (USER.18)
1392  */
1393 HWND16 WINAPI SetCapture16( HWND16 hwnd )
1394 {
1395     return (HWND16)EVENT_Capture( hwnd, HTCLIENT );
1396 }
1397
1398
1399 /**********************************************************************
1400  *              SetCapture32   (USER32.464)
1401  */
1402 HWND32 WINAPI SetCapture32( HWND32 hwnd )
1403 {
1404     return EVENT_Capture( hwnd, HTCLIENT );
1405 }
1406
1407
1408 /**********************************************************************
1409  *              ReleaseCapture   (USER.19) (USER32.439)
1410  */
1411 void WINAPI ReleaseCapture(void)
1412 {
1413     TRACE(win, "captureWnd=%04x\n", captureWnd );
1414     if( captureWnd ) EVENT_Capture( 0, 0 );
1415 }
1416
1417
1418 /**********************************************************************
1419  *              GetCapture16   (USER.236)
1420  */
1421 HWND16 WINAPI GetCapture16(void)
1422 {
1423     return captureWnd;
1424 }
1425
1426
1427 /**********************************************************************
1428  *              GetCapture32   (USER32.208)
1429  */
1430 HWND32 WINAPI GetCapture32(void)
1431 {
1432     return captureWnd;
1433 }
1434
1435
1436
1437 /***********************************************************************
1438  * Mouse driver routines:
1439  */
1440
1441 #pragma pack(1)
1442 typedef struct _MOUSEINFO
1443 {
1444     BYTE msExist;
1445     BYTE msRelative;
1446     WORD msNumButtons;
1447     WORD msRate;
1448     WORD msXThreshold;
1449     WORD msYThreshold;
1450     WORD msXRes;
1451     WORD msYRes;
1452     WORD msMouseCommPort;
1453 } MOUSEINFO;
1454 #pragma pack(4)
1455
1456 static SEGPTR MouseEventProc = 0;
1457
1458 /***********************************************************************
1459  *           MouseInquire                       (MOUSE.1)
1460  */
1461
1462 WORD WINAPI MouseInquire(MOUSEINFO *mouseInfo)
1463 {
1464     mouseInfo->msExist = TRUE;
1465     mouseInfo->msRelative = FALSE;
1466     mouseInfo->msNumButtons = 2;
1467     mouseInfo->msRate = 34;  /* the DDK says so ... */
1468     mouseInfo->msXThreshold = 0;
1469     mouseInfo->msYThreshold = 0;
1470     mouseInfo->msXRes = 0;
1471     mouseInfo->msYRes = 0;
1472     mouseInfo->msMouseCommPort = 0;
1473
1474     return sizeof(MOUSEINFO);
1475 }
1476
1477 /***********************************************************************
1478  *           MouseEnable                        (MOUSE.2)
1479  */
1480 VOID WINAPI MouseEnable(SEGPTR eventProc)
1481 {
1482     MouseEventProc = eventProc;
1483 }
1484
1485 /***********************************************************************
1486  *           MouseDisable                       (MOUSE.3)
1487  */
1488 VOID WINAPI MouseDisable(VOID)
1489 {
1490     MouseEventProc = 0;
1491 }
1492
1493 /***********************************************************************
1494  *           EVENT_SendMouseEvent
1495  */
1496 static void EVENT_SendMouseEvent( WORD mouseStatus, WORD deltaX, WORD deltaY, 
1497                                   WORD buttonCount, DWORD extraInfo )
1498 {
1499     CONTEXT context;
1500
1501     if ( !MouseEventProc ) return;
1502
1503     TRACE( keyboard, "(%04X,%d,%d,%d,%ld)\n", mouseStatus, deltaX, deltaY, buttonCount, extraInfo );
1504
1505     mouseStatus |= 0x8000;
1506     deltaX = (((long)deltaX << 16) + screenWidth/2)  / screenWidth;
1507     deltaY = (((long)deltaY << 16) + screenHeight/2) / screenHeight;
1508
1509     memset( &context, 0, sizeof(context) );
1510     CS_reg(&context)  = SELECTOROF( MouseEventProc );
1511     EIP_reg(&context) = OFFSETOF( MouseEventProc );
1512     EAX_reg(&context) = mouseStatus;
1513     EBX_reg(&context) = deltaX;
1514     ECX_reg(&context) = deltaY;
1515     EDX_reg(&context) = buttonCount;
1516     ESI_reg(&context) = LOWORD( extraInfo );
1517     EDI_reg(&context) = HIWORD( extraInfo );
1518
1519     Callbacks->CallRegisterShortProc( &context, 0 );
1520 }
1521
1522
1523
1524
1525 /***********************************************************************
1526  *           GetMouseEventProc   (USER.337)
1527  */
1528 FARPROC16 WINAPI GetMouseEventProc(void)
1529 {
1530     HMODULE16 hmodule = GetModuleHandle16("USER");
1531     return NE_GetEntryPoint( hmodule, NE_GetOrdinal( hmodule, "Mouse_Event" ));
1532 }
1533
1534
1535 /***********************************************************************
1536  *           Mouse_Event   (USER.299)
1537  */
1538 void WINAPI Mouse_Event( CONTEXT *context )
1539 {
1540     /* Register values:
1541      * AX = mouse event
1542      * BX = horizontal displacement if AX & ME_MOVE
1543      * CX = vertical displacement if AX & ME_MOVE
1544      * DX = button state (?)
1545      * SI = mouse event flags (?)
1546      */
1547     Window root, child;
1548     int rootX, rootY, winX, winY;
1549     unsigned int state;
1550
1551     if (AX_reg(context) & ME_MOVE)
1552     {
1553         /* We have to actually move the cursor */
1554         TSXWarpPointer( display, rootWindow, None, 0, 0, 0, 0,
1555                       (short)BX_reg(context), (short)CX_reg(context) );
1556         return;
1557     }
1558     if (!TSXQueryPointer( display, rootWindow, &root, &child,
1559                         &rootX, &rootY, &winX, &winY, &state )) return;
1560     if (AX_reg(context) & ME_LDOWN)
1561         hardware_event( WM_LBUTTONDOWN, EVENT_XStateToKeyState( state ),
1562                         0L, winX, winY, GetTickCount(), 0 );
1563     if (AX_reg(context) & ME_LUP)
1564         hardware_event( WM_LBUTTONUP, EVENT_XStateToKeyState( state ),
1565                         0L, winX, winY, GetTickCount(), 0 );
1566     if (AX_reg(context) & ME_RDOWN)
1567         hardware_event( WM_RBUTTONDOWN, EVENT_XStateToKeyState( state ),
1568                         0L, winX, winY, GetTickCount(), 0 );
1569     if (AX_reg(context) & ME_RUP)
1570         hardware_event( WM_RBUTTONUP, EVENT_XStateToKeyState( state ),
1571                         0L, winX, winY, GetTickCount(), 0 );
1572 }
1573
1574
1575 /**********************************************************************
1576  *                      EnableHardwareInput   (USER.331)
1577  */
1578 BOOL16 WINAPI EnableHardwareInput(BOOL16 bEnable)
1579 {
1580   BOOL16 bOldState = InputEnabled;
1581   FIXME(event,"(%d) - stub\n", bEnable);
1582   InputEnabled = bEnable;
1583   return bOldState;
1584 }
1585
1586
1587 /***********************************************************************
1588  *           SwapMouseButton16   (USER.186)
1589  */
1590 BOOL16 WINAPI SwapMouseButton16( BOOL16 fSwap )
1591 {
1592     BOOL16 ret = SwappedButtons;
1593     SwappedButtons = fSwap;
1594     return ret;
1595 }
1596
1597
1598 /***********************************************************************
1599  *           SwapMouseButton32   (USER32.537)
1600  */
1601 BOOL32 WINAPI SwapMouseButton32( BOOL32 fSwap )
1602 {
1603     BOOL32 ret = SwappedButtons;
1604     SwappedButtons = fSwap;
1605     return ret;
1606 }