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