On ConfigureNotify, find the first visible window above the current one.
[wine] / windows / x11drv / event.c
1 /*
2  * X11 event driver
3  *
4  * Copyright 1993 Alexandre Julliard
5  *           1999 Noel Borthwick
6  */
7
8 #include "config.h"
9
10 #ifndef X_DISPLAY_MISSING
11
12 #include <X11/Xatom.h>
13 #include <X11/keysym.h>
14 #include "ts_xlib.h"
15 #include "ts_xresource.h"
16 #include "ts_xutil.h"
17
18 #include <assert.h>
19 #include <string.h>
20 #include "callback.h"
21 #include "clipboard.h"
22 #include "dce.h"
23 #include "debugtools.h"
24 #include "drive.h"
25 #include "heap.h"
26 #include "keyboard.h"
27 #include "message.h"
28 #include "mouse.h"
29 #include "options.h"
30 #include "queue.h"
31 #include "shell.h"
32 #include "winpos.h"
33 #include "services.h"
34 #include "file.h"
35 #include "windef.h"
36 #include "x11drv.h"
37
38 DECLARE_DEBUG_CHANNEL(event)
39 DECLARE_DEBUG_CHANNEL(win)
40   
41 /* X context to associate a hwnd to an X window */
42 extern XContext winContext;
43
44 extern Atom wmProtocols;
45 extern Atom wmDeleteWindow;
46 extern Atom dndProtocol;
47 extern Atom dndSelection;
48
49 extern void X11DRV_KEYBOARD_UpdateState(void);
50 extern void X11DRV_KEYBOARD_HandleEvent(WND *pWnd, XKeyEvent *event);
51
52 #define NB_BUTTONS      3     /* Windows can handle 3 buttons */
53
54 #define DndNotDnd       -1    /* OffiX drag&drop */
55 #define DndUnknown      0
56 #define DndRawData      1
57 #define DndFile         2
58 #define DndFiles        3
59 #define DndText         4
60 #define DndDir          5
61 #define DndLink         6
62 #define DndExe          7
63
64 #define DndEND          8
65
66 #define DndURL          128   /* KDE drag&drop */
67
68 /* The last X window which had the focus */
69 static Window glastXFocusWin = 0;
70
71 static const char * const event_names[] =
72 {
73   "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
74   "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
75   "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
76   "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
77   "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
78   "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
79   "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
80   "ClientMessage", "MappingNotify"
81 };
82
83
84 static void CALLBACK EVENT_Flush( ULONG_PTR arg );
85 static void CALLBACK EVENT_ProcessAllEvents( ULONG_PTR arg );
86 static void EVENT_ProcessEvent( XEvent *event );
87
88   /* Event handlers */
89 static void EVENT_Key( HWND hWnd, XKeyEvent *event );
90 static void EVENT_ButtonPress( HWND hWnd, XButtonEvent *event );
91 static void EVENT_ButtonRelease( HWND hWnd, XButtonEvent *event );
92 static void EVENT_MotionNotify( HWND hWnd, XMotionEvent *event );
93 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event );
94 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event );
95 static void EVENT_Expose( HWND hWnd, XExposeEvent *event );
96 static void EVENT_GraphicsExpose( HWND hWnd, XGraphicsExposeEvent *event );
97 static void EVENT_ConfigureNotify( HWND hWnd, XConfigureEvent *event );
98 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple );
99 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event);
100 static void EVENT_PropertyNotify( XPropertyEvent *event );
101 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event );
102 static void EVENT_MapNotify( HWND pWnd, XMapEvent *event );
103 static void EVENT_UnmapNotify( HWND pWnd, XUnmapEvent *event );
104
105 /* Usable only with OLVWM - compile option perhaps?
106 static void EVENT_EnterNotify( HWND hWnd, XCrossingEvent *event );
107 */
108
109 static void EVENT_GetGeometry( Window win, int *px, int *py,
110                                unsigned int *pwidth, unsigned int *pheight );
111
112
113 static BOOL bUserRepaintDisabled = TRUE;
114
115
116 /***********************************************************************
117  *           EVENT_Init
118  */
119 BOOL X11DRV_EVENT_Init(void)
120 {
121     /* Install the X event processing callback */
122     SERVICE_AddObject( FILE_DupUnixHandle( ConnectionNumber(display), 
123                                            GENERIC_READ | SYNCHRONIZE ),
124                        EVENT_ProcessAllEvents, 0 );
125
126     /* Install the XFlush timer callback */
127     if ( Options.synchronous ) 
128         TSXSynchronize( display, True );
129     else
130         SERVICE_AddTimer( 200000L, EVENT_Flush, 0 );
131
132     return TRUE;
133 }
134
135 /***********************************************************************
136  *           EVENT_Flush
137  */
138 static void CALLBACK EVENT_Flush( ULONG_PTR arg )
139 {
140     TSXFlush( display );
141 }
142
143 /***********************************************************************
144  *           EVENT_ProcessAllEvents
145  */
146 static void CALLBACK EVENT_ProcessAllEvents( ULONG_PTR arg )
147 {
148     XEvent event;
149   
150     TRACE_(event)( "called.\n" );
151
152     EnterCriticalSection( &X11DRV_CritSection );
153     while ( XPending( display ) )
154     {
155         XNextEvent( display, &event );
156       
157         LeaveCriticalSection( &X11DRV_CritSection );
158         EVENT_ProcessEvent( &event );
159         EnterCriticalSection( &X11DRV_CritSection );
160     }
161     LeaveCriticalSection( &X11DRV_CritSection );
162 }
163
164 /***********************************************************************
165  *           EVENT_Synchronize
166  *
167  * Synchronize with the X server. Should not be used too often.
168  */
169 void X11DRV_EVENT_Synchronize( void )
170 {
171     TSXSync( display, False );
172     EVENT_ProcessAllEvents( 0 );
173 }
174
175 /***********************************************************************
176  *           EVENT_UserRepaintDisable
177  */
178 void X11DRV_EVENT_UserRepaintDisable( BOOL bDisabled )
179 {
180     bUserRepaintDisabled = bDisabled;
181 }
182
183 /***********************************************************************
184  *           EVENT_ProcessEvent
185  *
186  * Process an X event.
187  */
188 static void EVENT_ProcessEvent( XEvent *event )
189 {
190   HWND hWnd;
191
192   TRACE_(event)( "called.\n" );
193
194   switch (event->type)
195   {
196     case SelectionNotify: /* all of these should be caught by XCheckTypedWindowEvent() */
197          FIXME_(event)("Got SelectionNotify - must not happen!\n");
198          /* fall through */
199
200       /* We get all these because of StructureNotifyMask.
201          This check is placed here to avoid getting error messages below,
202          as X might send some of these even for windows that have already
203          been deleted ... */
204     case CirculateNotify:
205     case CreateNotify:
206     case DestroyNotify:
207     case GravityNotify:
208     case ReparentNotify:
209       return;
210   }
211       
212   if ( TSXFindContext( display, event->xany.window, winContext,
213                        (char **)&hWnd ) != 0) {
214     if ( event->type == ClientMessage) {
215       /* query window (drag&drop event contains only drag window) */
216       Window    root, child;
217       int       root_x, root_y, child_x, child_y;
218       unsigned  u;
219       TSXQueryPointer( display, X11DRV_GetXRootWindow(), &root, &child,
220                        &root_x, &root_y, &child_x, &child_y, &u);
221       if (TSXFindContext( display, child, winContext, (char **)&hWnd ) != 0)
222         return;
223     } else {
224       hWnd = 0;  /* Not for a registered window */
225     }
226   }
227
228   if ( !hWnd && event->xany.window != X11DRV_GetXRootWindow()
229              && event->type != PropertyNotify )
230       ERR_(event)("Got event %s for unknown Window %08lx\n",
231            event_names[event->type], event->xany.window );
232   else
233       TRACE_(event)("Got event %s for hwnd %04x\n",
234              event_names[event->type], hWnd );
235
236   switch(event->type)
237     {
238     case KeyPress:
239     case KeyRelease:
240       EVENT_Key( hWnd, (XKeyEvent*)event );
241       break;
242       
243     case ButtonPress:
244       EVENT_ButtonPress( hWnd, (XButtonEvent*)event );
245       break;
246       
247     case ButtonRelease:
248       EVENT_ButtonRelease( hWnd, (XButtonEvent*)event );
249       break;
250       
251     case MotionNotify:
252       /* Wine between two fast machines across the overloaded campus
253          ethernet gets very boged down in MotionEvents. The following
254          simply finds the last motion event in the queue and drops
255          the rest. On a good link events are servered before they build
256          up so this doesn't take place. On a slow link this may cause
257          problems if the event order is important. I'm not yet seen
258          of any problems. Jon 7/6/96.
259       */
260       while (TSXCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
261                                       MotionNotify, event));    
262       EVENT_MotionNotify( hWnd, (XMotionEvent*)event );
263       break;
264       
265     case FocusIn:
266     {
267       WND *pWndLastFocus = 0;
268       XWindowAttributes win_attr;
269       BOOL bIsDisabled;
270       XFocusChangeEvent *xfocChange = (XFocusChangeEvent*)event;
271
272       if (!hWnd || bUserRepaintDisabled) return;
273
274       bIsDisabled = GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED;
275
276       /* If the window has been disabled and we are in managed mode,
277        * revert the X focus back to the last focus window. This is to disallow
278        * the window manager from switching focus away while the app is
279        * in a modal state.
280        */
281       if ( Options.managed && bIsDisabled && glastXFocusWin)
282       {
283         /* Change focus only if saved focus window is registered and viewable */
284         if ( TSXFindContext( xfocChange->display, glastXFocusWin, winContext,
285                              (char **)&pWndLastFocus ) == 0 )
286         {
287           if ( TSXGetWindowAttributes( display, glastXFocusWin, &win_attr ) &&
288                  (win_attr.map_state == IsViewable) )
289           {
290             TSXSetInputFocus( xfocChange->display, glastXFocusWin, RevertToParent, CurrentTime );
291             EVENT_Synchronize();
292       break;
293           }
294         }
295       }
296        
297       EVENT_FocusIn( hWnd, xfocChange );
298       break;
299     }
300       
301     case FocusOut:
302     {
303       /* Save the last window which had the focus */
304       XFocusChangeEvent *xfocChange = (XFocusChangeEvent*)event;
305       glastXFocusWin = xfocChange->window;
306       if (!hWnd || bUserRepaintDisabled) return;
307       if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED) glastXFocusWin = 0;
308       EVENT_FocusOut( hWnd, (XFocusChangeEvent*)event );
309       break;
310     }
311       
312     case Expose:
313       if (bUserRepaintDisabled) return;
314       EVENT_Expose( hWnd, (XExposeEvent *)event );
315       break;
316       
317     case GraphicsExpose:
318       if (bUserRepaintDisabled) return;
319       EVENT_GraphicsExpose( hWnd, (XGraphicsExposeEvent *)event );
320       break;
321       
322     case ConfigureNotify:
323       if (!hWnd || bUserRepaintDisabled) return;
324       EVENT_ConfigureNotify( hWnd, (XConfigureEvent*)event );
325       break;
326
327     case SelectionRequest:
328       if (!hWnd || bUserRepaintDisabled) return;
329       EVENT_SelectionRequest( hWnd, (XSelectionRequestEvent *)event, FALSE );
330       break;
331
332     case SelectionClear:
333       if (!hWnd || bUserRepaintDisabled) return;
334       EVENT_SelectionClear( hWnd, (XSelectionClearEvent*) event );
335       break;
336       
337     case PropertyNotify:
338       EVENT_PropertyNotify( (XPropertyEvent *)event );
339       break;
340
341     case ClientMessage:
342       if (!hWnd || bUserRepaintDisabled) return;
343       EVENT_ClientMessage( hWnd, (XClientMessageEvent *) event );
344       break;
345
346 #if 0
347     case EnterNotify:
348       EVENT_EnterNotify( hWnd, (XCrossingEvent *) event );
349       break;
350 #endif
351
352     case NoExpose:
353       break;
354       
355     case MapNotify:
356       if (!hWnd || bUserRepaintDisabled) return;
357       EVENT_MapNotify( hWnd, (XMapEvent *)event );
358       break;
359
360     case UnmapNotify:
361       if (!hWnd || bUserRepaintDisabled) return;
362       EVENT_UnmapNotify( hWnd, (XUnmapEvent *)event );
363       break;
364
365     default:    
366       WARN_(event)("Unprocessed event %s for hwnd %04x\n",
367            event_names[event->type], hWnd );
368       break;
369     }
370 }
371
372 /***********************************************************************
373  *           EVENT_QueryZOrder
374  *
375  * Synchronize internal z-order with the window manager's.
376  */
377 static BOOL __check_query_condition( WND** pWndA, WND** pWndB )
378 {
379   /* return TRUE if we have at least two managed windows */
380   
381   for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
382     if( (*pWndA)->flags & WIN_MANAGED &&
383         (*pWndA)->dwStyle & WS_VISIBLE ) break;
384   if( *pWndA )
385     for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
386       if( (*pWndB)->flags & WIN_MANAGED &&
387           (*pWndB)->dwStyle & WS_VISIBLE ) break;
388   return ((*pWndB) != NULL);
389 }
390
391 static Window __get_common_ancestor( Window A, Window B,
392                                      Window** children, unsigned* total )
393 {
394     /* find the real root window */
395   
396     Window      root, *childrenB;
397     unsigned    totalB;
398   
399     do
400     {
401       TSXQueryTree( display, A, &root, &A, children, total );
402       TSXQueryTree( display, B, &root, &B, &childrenB, &totalB );
403       if( childrenB ) TSXFree( childrenB );
404       if( *children ) TSXFree( *children ), *children = NULL;
405     } while( A != B && A && B );
406
407     if( A && B )
408     {
409         TSXQueryTree( display, A, &root, &B, children, total );
410         return A;
411     }
412     return 0 ;
413 }
414
415 static Window __get_top_decoration( Window w, Window ancestor )
416 {
417   Window*     children, root, prev = w, parent = w;
418   unsigned    total;
419   
420   do
421     {
422       w = parent;
423       TSXQueryTree( display, w, &root, &parent, &children, &total );
424       if( children ) TSXFree( children );
425     } while( parent && parent != ancestor );
426   TRACE_(event)("\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
427   return ( parent ) ? w : 0 ;
428 }
429
430 static unsigned __td_lookup( Window w, Window* list, unsigned max )
431 {
432   unsigned    i;
433   for( i = max - 1; i >= 0; i-- ) if( list[i] == w ) break;
434   return i;
435 }
436
437 static HWND EVENT_QueryZOrder( HWND hWndCheck)
438 {
439   HWND      hwndInsertAfter = HWND_TOP;
440   WND      *pWndCheck = WIN_FindWndPtr(hWndCheck);
441   WND      *pDesktop = WIN_GetDesktop();
442   WND      *pWnd, *pWndZ = WIN_LockWndPtr(pDesktop->child);
443   Window      w, parent, *children = NULL;
444   unsigned    total, check, pos, best;
445   
446   if( !__check_query_condition(&pWndZ, &pWnd) )
447   {
448       WIN_ReleaseWndPtr(pWndCheck);
449       WIN_ReleaseWndPtr(pDesktop->child);
450       WIN_ReleaseDesktop();
451       return hwndInsertAfter;
452   }
453   WIN_LockWndPtr(pWndZ);
454   WIN_LockWndPtr(pWnd);
455   WIN_ReleaseWndPtr(pDesktop->child);
456   WIN_ReleaseDesktop();
457   
458   parent = __get_common_ancestor( X11DRV_WND_GetXWindow(pWndZ), 
459                                   X11DRV_WND_GetXWindow(pWnd),
460                                   &children, &total );
461   if( parent && children )
462   {
463       /* w is the ancestor if pWndCheck that is a direct descendant of 'parent' */
464
465       w = __get_top_decoration( X11DRV_WND_GetXWindow(pWndCheck), parent );
466
467       if( w != children[total-1] ) /* check if at the top */
468       {
469           /* X child at index 0 is at the bottom, at index total-1 is at the top */
470           check = __td_lookup( w, children, total );
471           best = total;
472
473           for( WIN_UpdateWndPtr(&pWnd,pWndZ); pWnd;WIN_UpdateWndPtr(&pWnd,pWnd->next))
474           {
475               /* go through all windows in Wine z-order... */
476
477               if( pWnd != pWndCheck )
478               {
479                   if( !(pWnd->flags & WIN_MANAGED) ||
480                       !(w = __get_top_decoration( X11DRV_WND_GetXWindow(pWnd), parent )) )
481                     continue;
482                   pos = __td_lookup( w, children, total );
483                   if( pos < best && pos > check )
484                   {
485                       /* find a nearest Wine window precedes 
486                        * pWndCheck in the real z-order... */
487                       best = pos;
488                       hwndInsertAfter = pWnd->hwndSelf;
489                   }
490                   if( best - check == 1 ) break;
491               }
492           }
493       }
494   }
495   if( children ) TSXFree( children );
496   WIN_ReleaseWndPtr(pWnd);
497   WIN_ReleaseWndPtr(pWndZ);
498   WIN_ReleaseWndPtr(pWndCheck);
499   return hwndInsertAfter;
500 }
501
502 /***********************************************************************
503  *           EVENT_XStateToKeyState
504  *
505  * Translate a X event state (Button1Mask, ShiftMask, etc...) to
506  * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
507  */
508 static WORD EVENT_XStateToKeyState( int state )
509 {
510   int kstate = 0;
511   
512   if (state & Button1Mask) kstate |= MK_LBUTTON;
513   if (state & Button2Mask) kstate |= MK_MBUTTON;
514   if (state & Button3Mask) kstate |= MK_RBUTTON;
515   if (state & ShiftMask)   kstate |= MK_SHIFT;
516   if (state & ControlMask) kstate |= MK_CONTROL;
517   return kstate;
518 }
519
520 /***********************************************************************
521  *           X11DRV_EVENT_QueryPointer
522  */
523 BOOL X11DRV_EVENT_QueryPointer(DWORD *posX, DWORD *posY, DWORD *state)
524 {
525   Window root, child;
526   int rootX, rootY, winX, winY;
527   unsigned int xstate;
528   
529   if (!TSXQueryPointer( display, X11DRV_GetXRootWindow(), &root, &child,
530                         &rootX, &rootY, &winX, &winY, &xstate )) 
531     return FALSE;
532   
533   if(posX)
534     *posX  = (DWORD)winX;
535   if(posY)
536     *posY  = (DWORD)winY;
537   if(state)
538     *state = EVENT_XStateToKeyState( xstate );
539   
540   return TRUE;
541 }
542
543 /***********************************************************************
544  *           EVENT_Expose
545  */
546 static void EVENT_Expose( HWND hWnd, XExposeEvent *event )
547 {
548   RECT rect;
549
550   WND *pWnd = WIN_FindWndPtr(hWnd);
551   /* Make position relative to client area instead of window */
552   rect.left   = event->x - (pWnd? (pWnd->rectClient.left - pWnd->rectWindow.left) : 0);
553   rect.top    = event->y - (pWnd? (pWnd->rectClient.top - pWnd->rectWindow.top) : 0);
554   rect.right  = rect.left + event->width;
555   rect.bottom = rect.top + event->height;
556   WIN_ReleaseWndPtr(pWnd);
557  
558   Callout.RedrawWindow( hWnd, &rect, 0,
559                           RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
560                           (event->count ? 0 : RDW_ERASENOW) );
561 }
562
563
564 /***********************************************************************
565  *           EVENT_GraphicsExpose
566  *
567  * This is needed when scrolling area is partially obscured
568  * by non-Wine X window.
569  */
570 static void EVENT_GraphicsExpose( HWND hWnd, XGraphicsExposeEvent *event )
571 {
572   RECT rect;
573   WND *pWnd = WIN_FindWndPtr(hWnd);
574   
575   /* Make position relative to client area instead of window */
576   rect.left   = event->x - (pWnd? (pWnd->rectClient.left - pWnd->rectWindow.left) : 0);
577   rect.top    = event->y - (pWnd? (pWnd->rectClient.top - pWnd->rectWindow.top) : 0);
578   rect.right  = rect.left + event->width;
579   rect.bottom = rect.top + event->height;
580   
581   WIN_ReleaseWndPtr(pWnd);
582   
583   Callout.RedrawWindow( hWnd, &rect, 0,
584                           RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
585                           (event->count ? 0 : RDW_ERASENOW) );
586 }
587
588
589 /***********************************************************************
590  *           EVENT_Key
591  *
592  * Handle a X key event
593  */
594 static void EVENT_Key( HWND hWnd, XKeyEvent *event )
595 {
596     WND *pWnd = WIN_FindWndPtr(hWnd);
597   X11DRV_KEYBOARD_HandleEvent( pWnd, event );
598     WIN_ReleaseWndPtr(pWnd);
599
600 }
601
602
603 /***********************************************************************
604  *           EVENT_MotionNotify
605  */
606 static void EVENT_MotionNotify( HWND hWnd, XMotionEvent *event )
607 {
608   WND *pWnd = WIN_FindWndPtr(hWnd);
609   int xOffset = pWnd? pWnd->rectWindow.left : 0;
610   int yOffset = pWnd? pWnd->rectWindow.top  : 0;
611   WIN_ReleaseWndPtr(pWnd);
612
613   MOUSE_SendEvent( MOUSEEVENTF_MOVE, 
614                    xOffset + event->x, yOffset + event->y,
615                    EVENT_XStateToKeyState( event->state ), 
616                    event->time - MSG_WineStartTicks,
617                    hWnd);
618 }
619
620
621 /***********************************************************************
622  *           EVENT_ButtonPress
623  */
624 static void EVENT_ButtonPress( HWND hWnd, XButtonEvent *event )
625 {
626   static WORD statusCodes[NB_BUTTONS] = 
627   { MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_RIGHTDOWN };
628   int buttonNum = event->button - 1;
629   
630   WND *pWnd = WIN_FindWndPtr(hWnd);
631   int xOffset = pWnd? pWnd->rectWindow.left : 0;
632   int yOffset = pWnd? pWnd->rectWindow.top  : 0;
633   WORD keystate;
634   
635   WIN_ReleaseWndPtr(pWnd);
636
637   if (buttonNum >= NB_BUTTONS) return;
638   
639   /*
640    * Get the compatible keystate
641    */
642   keystate = EVENT_XStateToKeyState( event->state );
643   
644   /*
645    * Make sure that the state of the button that was just 
646    * pressed is "down".
647    */
648   switch (buttonNum)
649   {
650     case 0:
651       keystate |= MK_LBUTTON;
652       break;
653     case 1:
654       keystate |= MK_MBUTTON;
655       break;
656     case 2:
657       keystate |= MK_RBUTTON;
658       break;
659   }
660   
661   MOUSE_SendEvent( statusCodes[buttonNum], 
662                    xOffset + event->x, yOffset + event->y,
663                    keystate, 
664                    event->time - MSG_WineStartTicks,
665                    hWnd);
666 }
667
668
669 /***********************************************************************
670  *           EVENT_ButtonRelease
671  */
672 static void EVENT_ButtonRelease( HWND hWnd, XButtonEvent *event )
673 {
674   static WORD statusCodes[NB_BUTTONS] = 
675   { MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_RIGHTUP };
676   int buttonNum = event->button - 1;
677   WND *pWnd = WIN_FindWndPtr(hWnd);
678   int xOffset = pWnd? pWnd->rectWindow.left : 0;
679   int yOffset = pWnd? pWnd->rectWindow.top  : 0;
680   WORD keystate;
681   
682   WIN_ReleaseWndPtr(pWnd);
683   
684   if (buttonNum >= NB_BUTTONS) return;    
685   
686   /*
687    * Get the compatible keystate
688    */
689   keystate = EVENT_XStateToKeyState( event->state );
690
691   /*
692    * Make sure that the state of the button that was just 
693    * released is "up".
694    */
695   switch (buttonNum)
696   {
697     case 0:
698       keystate &= ~MK_LBUTTON;
699       break;
700     case 1:
701       keystate &= ~MK_MBUTTON;
702       break;
703     case 2:
704       keystate &= ~MK_RBUTTON;
705       break;
706   }
707
708   MOUSE_SendEvent( statusCodes[buttonNum], 
709                    xOffset + event->x, yOffset + event->y,
710                    keystate, 
711                    event->time - MSG_WineStartTicks,
712                    hWnd);
713 }
714
715
716 /**********************************************************************
717  *              EVENT_FocusIn
718  */
719 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event )
720 {
721     if (event->detail != NotifyPointer)
722         if (hWnd != GetForegroundWindow())
723         {
724             SetForegroundWindow( hWnd );
725             X11DRV_KEYBOARD_UpdateState();
726         }
727 }
728
729
730 /**********************************************************************
731  *              EVENT_FocusOut
732  *
733  * Note: only top-level override-redirect windows get FocusOut events.
734  */
735 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event )
736 {
737     if (event->detail != NotifyPointer)
738         if (hWnd == GetForegroundWindow())
739         {
740             WND *pWnd = WIN_FindWndPtr(hWnd);
741
742             if( ((pWnd->dwStyle & WS_POPUP) == WS_POPUP) &&
743                 ((pWnd->dwStyle & WS_POPUPWINDOW) != WS_POPUPWINDOW) )
744                 SendMessageA(hWnd, WM_CLOSE, 0, 0 );
745             else
746             SendMessageA( hWnd, WM_CANCELMODE, 0, 0 );
747             WIN_ReleaseWndPtr(pWnd);
748
749             /* Abey : 6-Oct-99. Check again if the focus out window is the
750                Foreground window, because in most cases the messages sent
751                above must have already changed the foreground window, in which
752                case we don't have to change the foreground window to 0 */
753
754             if (hWnd == GetForegroundWindow())
755                 SetForegroundWindow( 0 );
756         }
757 }
758
759 /**********************************************************************
760  *              X11DRV_EVENT_CheckFocus
761  */
762 BOOL X11DRV_EVENT_CheckFocus(void)
763 {
764   HWND   hWnd;
765   Window xW;
766   int      state;
767   
768   TSXGetInputFocus(display, &xW, &state);
769     if( xW == None ||
770         TSXFindContext(display, xW, winContext, (char **)&hWnd) ) 
771       return FALSE;
772     return TRUE;
773 }
774
775 /**********************************************************************
776  *              EVENT_GetGeometry
777  *
778  * Helper function for ConfigureNotify handling.
779  * Get the new geometry of a window relative to the root window.
780  */
781 static void EVENT_GetGeometry( Window win, int *px, int *py,
782                                unsigned int *pwidth, unsigned int *pheight )
783 {
784     Window root, top;
785     int x, y, width, height, border, depth;
786
787     EnterCriticalSection( &X11DRV_CritSection );
788
789     /* Get the geometry of the window */
790     XGetGeometry( display, win, &root, &x, &y, &width, &height,
791                   &border, &depth );
792
793     /* Translate the window origin to root coordinates */
794     XTranslateCoordinates( display, win, root, 0, 0, &x, &y, &top );
795
796     LeaveCriticalSection( &X11DRV_CritSection );
797
798     *px = x;
799     *py = y;
800     *pwidth = width;
801     *pheight = height;
802 }
803
804 /**********************************************************************
805  *              EVENT_ConfigureNotify
806  *
807  * The ConfigureNotify event is only selected on top-level windows
808  * when the -managed flag is used.
809  */
810 static void EVENT_ConfigureNotify( HWND hWnd, XConfigureEvent *event )
811 {
812     RECT rectWindow;
813     int x, y, flags = 0;
814     unsigned int width, height;
815     HWND newInsertAfter, oldInsertAfter;
816   
817     /* Get geometry and Z-order according to X */
818
819     EVENT_GetGeometry( event->window, &x, &y, &width, &height );
820     newInsertAfter = EVENT_QueryZOrder( hWnd );
821
822     /* Get geometry and Z-order according to Wine */
823
824     /*
825      *  Needs to find the first Visible Window above the current one
826      */
827     oldInsertAfter = hWnd;
828     for (;;)
829     {
830         oldInsertAfter = GetWindow( oldInsertAfter, GW_HWNDPREV );
831         if (!oldInsertAfter)
832         {
833             oldInsertAfter = HWND_TOP;
834             break;
835         }
836         if (GetWindowLongA( oldInsertAfter, GWL_STYLE ) & WS_VISIBLE) break;
837     }
838
839     /* Compare what has changed */
840
841     GetWindowRect( hWnd, &rectWindow );
842     if ( rectWindow.left == x && rectWindow.top == y )
843         flags |= SWP_NOMOVE;
844     else
845         TRACE_(win)( "%04x moving from (%d,%d) to (%d,%d)\n", hWnd, 
846                      rectWindow.left, rectWindow.top, x, y );
847
848     if (    rectWindow.right - rectWindow.left == width
849          && rectWindow.bottom - rectWindow.top == height )
850         flags |= SWP_NOSIZE;
851     else
852         TRACE_(win)( "%04x resizing from (%d,%d) to (%d,%d)\n", hWnd, 
853                      rectWindow.right - rectWindow.left, 
854                      rectWindow.bottom - rectWindow.top, width, height );
855
856     if ( newInsertAfter == oldInsertAfter )
857         flags |= SWP_NOZORDER;
858     else
859         TRACE_(win)( "%04x restacking from after %04x to after %04x\n", hWnd, 
860                      oldInsertAfter, newInsertAfter );
861
862     /* If anything changed, call SetWindowPos */
863
864     if ( flags != (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER) )
865         SetWindowPos( hWnd, newInsertAfter, x, y, width, height, 
866                             flags | SWP_NOACTIVATE | SWP_WINE_NOHOSTMOVE );
867 }
868
869
870 /***********************************************************************
871  *           EVENT_SelectionRequest_TARGETS
872  *  Service a TARGETS selection request event
873  */
874 static Atom EVENT_SelectionRequest_TARGETS( Window requestor, Atom target, Atom rprop )
875 {
876     Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
877     Atom* targets;
878     Atom prop;
879     UINT wFormat;
880     unsigned long cTargets;
881     BOOL bHavePixmap;
882     int xRc;
883
884     TRACE_(event)("Request for %s\n", TSXGetAtomName(display, target));
885     
886     /*
887      * Count the number of items we wish to expose as selection targets.
888      * We include the TARGETS item, and a PIXMAP if we have CF_DIB or CF_BITMAP
889      */
890     cTargets = CountClipboardFormats() + 1;
891     if ( CLIPBOARD_IsPresent(CF_DIB) ||  CLIPBOARD_IsPresent(CF_BITMAP) )
892        cTargets++;
893     
894     /* Allocate temp buffer */
895     targets = (Atom*)HEAP_xalloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
896
897     /* Create TARGETS property list (First item in list is TARGETS itself) */
898
899     for ( targets[0] = xaTargets, cTargets = 1, wFormat = 0, bHavePixmap = FALSE;
900           (wFormat = EnumClipboardFormats( wFormat )); )
901     {
902         if ( (prop = X11DRV_CLIPBOARD_MapFormatToProperty(wFormat)) != None )
903         {
904             /* Scan through what we have so far to avoid duplicates */
905             int i;
906             BOOL bExists;
907             for (i = 0, bExists = FALSE; i < cTargets; i++)
908             {
909                 if (targets[i] == prop)
910                 {
911                     bExists = TRUE;
912                     break;
913                 }
914             }
915             if (!bExists)
916             {
917                 targets[cTargets++] = prop;
918             
919                 /* Add PIXMAP prop for bitmaps additionally */
920                 if ( (wFormat == CF_DIB || wFormat == CF_BITMAP )
921                      && !bHavePixmap )
922                 {
923                     targets[cTargets++] = XA_PIXMAP;
924                     bHavePixmap = TRUE;
925                 }
926             }
927         }
928     }
929
930 #ifdef DEBUG_RUNTIME
931 {
932     int i;
933     for ( i = 0; i < cTargets; i++)
934     {
935         if (targets[i])
936         {
937           char *itemFmtName = TSXGetAtomName(display, targets[i]);
938           TRACE_(event)("\tAtom# %d:  Type %s\n", i, itemFmtName);
939           TSXFree(itemFmtName);
940         }
941     }
942 }
943 #endif
944     
945     /* Update the X property */
946     TRACE_(event)("\tUpdating property %s...", TSXGetAtomName(display, rprop));
947
948     /* We may want to consider setting the type to xaTargets instead,
949      * in case some apps expect this instead of XA_ATOM */
950     xRc = TSXChangeProperty(display, requestor, rprop,
951                             XA_ATOM, 32, PropModeReplace,
952                             (unsigned char *)targets, cTargets);
953     TRACE_(event)("(Rc=%d)\n", xRc);
954     
955     HeapFree( GetProcessHeap(), 0, targets );
956
957     return rprop;
958 }
959
960
961 /***********************************************************************
962  *           EVENT_SelectionRequest_STRING
963  *  Service a STRING selection request event
964  */
965 static Atom EVENT_SelectionRequest_STRING( Window requestor, Atom target, Atom rprop )
966 {
967     HANDLE16 hText;
968     LPSTR  text;
969     int    size,i,j;
970     char* lpstr = 0;
971     char *itemFmtName;
972     int xRc;
973
974     /*
975      * Map the requested X selection property type atom name to a
976      * windows clipboard format ID.
977      */
978     itemFmtName = TSXGetAtomName(display, target);
979     TRACE_(event)("Request for %s (wFormat=%x %s)\n",
980                   itemFmtName, CF_TEXT, CLIPBOARD_GetFormatName(CF_TEXT));
981     TSXFree(itemFmtName);
982
983     if ( !CLIPBOARD_IsPresent(CF_TEXT) )
984     {
985        rprop = None;
986        goto END;
987     }
988
989     hText = GetClipboardData16(CF_TEXT);
990     text = GlobalLock16(hText);
991     size = GlobalSize16(hText);
992     
993     /* remove carriage returns */
994     
995     lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
996     for(i=0,j=0; i < size && text[i]; i++ )
997     {
998         if( text[i] == '\r' && 
999             (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
1000         lpstr[j++] = text[i];
1001     }
1002     lpstr[j]='\0';
1003     
1004     /* Update the X property */
1005     TRACE_(event)("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
1006     xRc = TSXChangeProperty(display, requestor, rprop,
1007                             XA_STRING, 8, PropModeReplace,
1008                             lpstr, j);
1009     TRACE_(event)("(Rc=%d)\n", xRc);
1010
1011     GlobalUnlock16(hText);
1012     HeapFree( GetProcessHeap(), 0, lpstr );
1013
1014 END:
1015     return rprop;
1016 }
1017
1018 /***********************************************************************
1019  *           EVENT_SelectionRequest_PIXMAP
1020  *  Service a PIXMAP selection request event
1021  */
1022 static Atom EVENT_SelectionRequest_PIXMAP( Window requestor, Atom target, Atom rprop )
1023 {
1024     HANDLE hClipData = 0;
1025     Pixmap pixmap = NULL;
1026     UINT   wFormat;
1027     char * itemFmtName;
1028     int xRc;
1029 #if(0)
1030     XSetWindowAttributes win_attr;
1031     XWindowAttributes win_attr_src;
1032 #endif
1033     
1034     /*
1035      * Map the requested X selection property type atom name to a
1036      * windows clipboard format ID.
1037      */
1038     itemFmtName = TSXGetAtomName(display, target);
1039     wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
1040     TRACE_(event)("Request for %s (wFormat=%x %s)\n",
1041                   itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat));
1042     TSXFree(itemFmtName);
1043     
1044     hClipData = GetClipboardData(wFormat);
1045     if ( !hClipData )
1046     {
1047         TRACE_(event)("Could not retrieve a Pixmap compatible format from clipboard!\n");
1048         rprop = None; /* Fail the request */
1049         goto END;
1050     }
1051
1052     if (wFormat == CF_DIB)
1053     {
1054         HWND hwnd = GetOpenClipboardWindow();
1055         HDC hdc = GetDC(hwnd);
1056         
1057         /* For convert from packed DIB to Pixmap */
1058         pixmap = X11DRV_DIB_CreatePixmapFromDIB(hClipData, hdc);
1059         
1060         ReleaseDC(hdc, hwnd);
1061     }
1062     else if (wFormat == CF_BITMAP)
1063     {
1064         HWND hwnd = GetOpenClipboardWindow();
1065         HDC hdc = GetDC(hwnd);
1066         
1067         pixmap = X11DRV_BITMAP_CreatePixmapFromBitmap(hClipData, hdc);
1068
1069         ReleaseDC(hdc, hwnd);
1070     }
1071     else
1072     {
1073         FIXME_(event)("%s to PIXMAP conversion not yet implemented!\n",
1074                       CLIPBOARD_GetFormatName(wFormat));
1075         rprop = None;
1076         goto END;
1077     }
1078
1079     TRACE_(event)("\tUpdating property %s on Window %ld with %s %ld...\n",
1080                   TSXGetAtomName(display, rprop), (long)requestor,
1081                   TSXGetAtomName(display, target),
1082                   pixmap);
1083
1084     /* Store the Pixmap handle in the property */
1085     xRc = TSXChangeProperty(display, requestor, rprop, target, 
1086                             32, PropModeReplace,
1087                             (unsigned char *)&pixmap, 1);
1088     TRACE_(event)("(Rc=%d)\n", xRc);
1089
1090     /* Enable the code below if you want to handle destroying Pixmap resources
1091      * in response to property notify events. Clients like XPaint don't
1092      * appear to be duplicating Pixmaps so they don't like us deleting,
1093      * the resource in response to the property being deleted.
1094      */
1095 #if(0)
1096     /* Express interest in property notify events so that we can delete the
1097      * pixmap when the client deletes the property atom.
1098      */
1099     xRc = TSXGetWindowAttributes(display, requestor, &win_attr_src);
1100     TRACE_(event)("Turning on PropertyChangeEvent notifications from window %ld\n",
1101                  (long)requestor);
1102     win_attr.event_mask = win_attr_src.your_event_mask | PropertyChangeMask;
1103     TSXChangeWindowAttributes(display, requestor, CWEventMask, &win_attr);
1104
1105     /* Register the Pixmap we created with the request property Atom.
1106      * When this property is destroyed we also destroy the Pixmap in
1107      * response to the PropertyNotify event.
1108      */
1109     X11DRV_CLIPBOARD_RegisterPixmapResource( rprop, pixmap );
1110 #endif
1111     
1112 END:
1113     return rprop;
1114 }
1115
1116
1117 /***********************************************************************
1118  *           EVENT_SelectionRequest_WCF
1119  *  Service a Wine Clipboard Format selection request event.
1120  *  For <WCF>* data types we simply copy the data to X without conversion.
1121  */
1122 static Atom EVENT_SelectionRequest_WCF( Window requestor, Atom target, Atom rprop )
1123 {
1124     HANDLE hClipData = 0;
1125     void*  lpClipData;
1126     UINT   wFormat;
1127     char * itemFmtName;
1128     int cBytes;
1129     int xRc;
1130     
1131     /*
1132      * Map the requested X selection property type atom name to a
1133      * windows clipboard format ID.
1134      */
1135     itemFmtName = TSXGetAtomName(display, target);
1136     wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
1137     TRACE_(event)("Request for %s (wFormat=%x %s)\n",
1138                   itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat));
1139     TSXFree(itemFmtName);
1140     
1141     hClipData = GetClipboardData16(wFormat);
1142     
1143     if( hClipData && (lpClipData = GlobalLock16(hClipData)) )
1144     {
1145         cBytes = GlobalSize16(hClipData);
1146         
1147         TRACE_(event)("\tUpdating property %s, %d bytes...\n",
1148                       TSXGetAtomName(display, rprop), cBytes);
1149         
1150         xRc = TSXChangeProperty(display, requestor, rprop,
1151                                 target, 8, PropModeReplace,
1152                                 (unsigned char *)lpClipData, cBytes);
1153         TRACE_(event)("(Rc=%d)\n", xRc);
1154         
1155         GlobalUnlock16(hClipData);
1156     }
1157     else
1158     {
1159         TRACE_(event)("\tCould not retrieve native format!\n");
1160         rprop = None; /* Fail the request */
1161     }
1162     
1163     return rprop;
1164 }
1165
1166
1167 /***********************************************************************
1168  *           EVENT_SelectionRequest_MULTIPLE
1169  *  Service a MULTIPLE selection request event
1170  *  rprop contains a list of (target,property) atom pairs.
1171  *  The first atom names a target and the second names a property.
1172  *  The effect is as if we have received a sequence of SelectionRequest events
1173  *  (one for each atom pair) except that:
1174  *  1. We reply with a SelectionNotify only when all the requested conversions
1175  *  have been performed.
1176  *  2. If we fail to convert the target named by an atom in the MULTIPLE property,
1177  *  we replace the atom in the property by None.
1178  */
1179 static Atom EVENT_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
1180 {
1181     Atom           rprop;
1182     Atom           atype=AnyPropertyType;
1183     int            aformat;
1184     unsigned long  remain;
1185     Atom*          targetPropList=NULL;
1186     unsigned long  cTargetPropList = 0;
1187 /*  Atom           xAtomPair = TSXInternAtom(display, "ATOM_PAIR", False); */
1188     
1189    /* If the specified property is None the requestor is an obsolete client.
1190     * We support these by using the specified target atom as the reply property.
1191     */
1192     rprop = pevent->property;
1193     if( rprop == None ) 
1194         rprop = pevent->target;
1195     if (!rprop)
1196         goto END;
1197
1198     /* Read the MULTIPLE property contents. This should contain a list of
1199      * (target,property) atom pairs.
1200      */
1201     if(TSXGetWindowProperty(display, pevent->requestor, rprop,
1202                             0, 0x3FFF, False, AnyPropertyType, &atype, &aformat,
1203                             &cTargetPropList, &remain, (unsigned char**)&targetPropList) != Success)
1204         TRACE_(event)("\tCouldn't read MULTIPLE property\n");
1205     else
1206     {
1207        TRACE_(event)("\tType %s,Format %d,nItems %ld, Remain %ld\n",
1208                      TSXGetAtomName(display,atype),aformat,cTargetPropList,remain);
1209
1210        /*
1211         * Make sure we got what we expect.
1212         * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
1213         * in a MULTIPLE selection request should be of type ATOM_PAIR.
1214         * However some X apps(such as XPaint) are not compliant with this and return
1215         * a user defined atom in atype when XGetWindowProperty is called.
1216         * The data *is* an atom pair but is not denoted as such.
1217         */
1218        if(aformat == 32 /* atype == xAtomPair */ )
1219        {
1220           int i;
1221           
1222           /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
1223            * for each (target,property) pair */
1224
1225           for (i = 0; i < cTargetPropList; i+=2)
1226           {
1227               char *targetName = TSXGetAtomName(display, targetPropList[i]);
1228               char *propName = TSXGetAtomName(display, targetPropList[i+1]);
1229               XSelectionRequestEvent event;
1230
1231               TRACE_(event)("MULTIPLE(%d): Target='%s' Prop='%s'\n", i/2, targetName, propName);
1232               TSXFree(targetName);
1233               TSXFree(propName);
1234               
1235               /* We must have a non "None" property to service a MULTIPLE target atom */
1236               if ( !targetPropList[i+1] )
1237               {
1238                   TRACE_(event)("\tMULTIPLE(%d): Skipping target with empty property!", i);
1239                   continue;
1240               }
1241               
1242               /* Set up an XSelectionRequestEvent for this (target,property) pair */
1243               memcpy( &event, pevent, sizeof(XSelectionRequestEvent) );
1244               event.target = targetPropList[i];
1245               event.property = targetPropList[i+1];
1246                   
1247               /* Fire a SelectionRequest, informing the handler that we are processing
1248                * a MULTIPLE selection request event.
1249                */
1250               EVENT_SelectionRequest( hWnd, &event, TRUE );
1251           }
1252        }
1253
1254        /* Free the list of targets/properties */
1255        TSXFree(targetPropList);
1256     }
1257
1258 END:
1259     return rprop;
1260 }
1261
1262
1263 /***********************************************************************
1264  *           EVENT_SelectionRequest
1265  *  Process an event selection request event.
1266  *  The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
1267  *  recursively while servicing a "MULTIPLE" selection target.
1268  *
1269  *  Note: We only receive this event when WINE owns the X selection
1270  */
1271 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
1272 {
1273   XSelectionEvent result;
1274   Atom            rprop = None;
1275   Window          request = event->requestor;
1276   BOOL            couldOpen = FALSE;
1277   Atom            xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
1278   Atom            xaTargets = TSXInternAtom(display, "TARGETS", False);
1279   Atom            xaMultiple = TSXInternAtom(display, "MULTIPLE", False);
1280
1281   /*
1282    * We can only handle the selection request if :
1283    * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
1284    * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
1285    * since this has been already done.
1286    */
1287   if ( !bIsMultiple )
1288   {
1289     if ( ( (event->selection != XA_PRIMARY) && (event->selection != xaClipboard) )
1290         || !(couldOpen = OpenClipboard(hWnd)) )
1291        goto END;
1292   }
1293
1294   /* If the specified property is None the requestor is an obsolete client.
1295    * We support these by using the specified target atom as the reply property.
1296    */
1297   rprop = event->property;
1298   if( rprop == None ) 
1299       rprop = event->target;
1300   
1301   if(event->target == xaTargets)  /*  Return a list of all supported targets */
1302   {
1303       /* TARGETS selection request */
1304       rprop = EVENT_SelectionRequest_TARGETS( request, event->target, rprop );
1305   }
1306   else if(event->target == xaMultiple)  /*  rprop contains a list of (target, property) atom pairs */
1307   {
1308       /* MULTIPLE selection request */
1309       rprop = EVENT_SelectionRequest_MULTIPLE(  hWnd, event );
1310   }
1311   else if(event->target == XA_STRING)  /* treat CF_TEXT as Unix text */
1312   {
1313       /* XA_STRING selection request */
1314       rprop = EVENT_SelectionRequest_STRING( request, event->target, rprop );
1315   }
1316   else if(event->target == XA_PIXMAP)  /*  Convert DIB's to Pixmaps */
1317   {
1318       /* XA_PIXMAP selection request */
1319       rprop = EVENT_SelectionRequest_PIXMAP( request, event->target, rprop );
1320   }
1321   else if(event->target == XA_BITMAP)  /*  Convert DIB's to 1-bit Pixmaps */
1322   {
1323       /* XA_BITMAP selection request - TODO: create a monochrome Pixmap */
1324       rprop = EVENT_SelectionRequest_PIXMAP( request, XA_PIXMAP, rprop );
1325   }
1326   else if(X11DRV_CLIPBOARD_IsNativeProperty(event->target)) /* <WCF>* */
1327   {
1328       /* All <WCF> selection requests */
1329       rprop = EVENT_SelectionRequest_WCF( request, event->target, rprop );
1330   }
1331   else
1332       rprop = None;  /* Don't support this format */
1333
1334 END:
1335   /* close clipboard only if we opened before */
1336   if(couldOpen) CloseClipboard();
1337   
1338   if( rprop == None) 
1339       TRACE_(event)("\tRequest ignored\n");
1340
1341   /* reply to sender 
1342    * SelectionNotify should be sent only at the end of a MULTIPLE request
1343    */
1344   if ( !bIsMultiple )
1345   {
1346     result.type = SelectionNotify;
1347     result.display = display;
1348     result.requestor = request;
1349     result.selection = event->selection;
1350     result.property = rprop;
1351     result.target = event->target;
1352     result.time = event->time;
1353     TRACE_(event)("Sending SelectionNotify event...\n");
1354     TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
1355   }
1356 }
1357
1358 /***********************************************************************
1359  *           EVENT_SelectionClear
1360  */
1361 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
1362 {
1363   Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
1364     
1365   if (event->selection == XA_PRIMARY || event->selection == xaClipboard)
1366       X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd );
1367 }
1368
1369 /***********************************************************************
1370  *           EVENT_PropertyNotify
1371  *   We use this to release resources like Pixmaps when a selection
1372  *   client no longer needs them.
1373  */
1374 static void EVENT_PropertyNotify( XPropertyEvent *event )
1375 {
1376   /* Check if we have any resources to free */
1377   TRACE_(event)("Received PropertyNotify event: ");
1378
1379   switch(event->state)
1380   {
1381     case PropertyDelete:
1382     {
1383       TRACE_(event)("\tPropertyDelete for atom %s on window %ld\n",
1384                     TSXGetAtomName(event->display, event->atom), (long)event->window);
1385       
1386       if (X11DRV_CLIPBOARD_IsSelectionowner())
1387           X11DRV_CLIPBOARD_FreeResources( event->atom );
1388       break;
1389     }
1390
1391     case PropertyNewValue:
1392     {
1393       TRACE_(event)("\tPropertyNewValue for atom %s on window %ld\n\n",
1394                     TSXGetAtomName(event->display, event->atom), (long)event->window);
1395       break;
1396     }
1397     
1398     default:
1399       break;
1400   }
1401 }
1402
1403 /**********************************************************************
1404  *           EVENT_DropFromOffix
1405  *
1406  * don't know if it still works (last Changlog is from 96/11/04)
1407  */
1408 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1409 {
1410   unsigned long         data_length;
1411   unsigned long         aux_long;
1412   unsigned char*        p_data = NULL;
1413   union {
1414     Atom                atom_aux;
1415     struct {
1416       int x;
1417       int y;
1418     } pt_aux;
1419     int         i;
1420   }             u;
1421   int                   x, y;
1422   BOOL16                bAccept;
1423   HGLOBAL16             hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
1424   LPDRAGINFO            lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
1425   SEGPTR                spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
1426   Window                w_aux_root, w_aux_child;
1427   WND*                  pDropWnd;
1428   WND*                  pWnd;
1429   
1430   if( !lpDragInfo || !spDragInfo ) return;
1431   
1432   pWnd = WIN_FindWndPtr(hWnd);
1433   
1434   TSXQueryPointer( display, X11DRV_WND_GetXWindow(pWnd), &w_aux_root, &w_aux_child, 
1435                    &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
1436                    (unsigned int*)&aux_long);
1437   
1438   lpDragInfo->hScope = hWnd;
1439   lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1440   
1441   /* find out drop point and drop window */
1442   if( x < 0 || y < 0 ||
1443       x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1444       y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1445     {   bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1446   else
1447     {
1448       bAccept = DRAG_QueryUpdate( hWnd, spDragInfo, TRUE );
1449       x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1450     }
1451   pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1452   WIN_ReleaseWndPtr(pWnd);
1453   
1454   GlobalFree16( hDragInfo );
1455   
1456   if( bAccept )
1457     {
1458       TSXGetWindowProperty( display, DefaultRootWindow(display),
1459                             dndSelection, 0, 65535, FALSE,
1460                             AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
1461                             &data_length, &aux_long, &p_data);
1462       
1463       if( !aux_long && p_data)  /* don't bother if > 64K */
1464         {
1465           char *p = (char*) p_data;
1466           char *p_drop;
1467           
1468           aux_long = 0; 
1469           while( *p )   /* calculate buffer size */
1470             {
1471               p_drop = p;
1472               if((u.i = *p) != -1 ) 
1473                 u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
1474               if( u.i == -1 ) *p = -1;  /* mark as "bad" */
1475               else
1476                 {
1477                   INT len = GetShortPathNameA( p, NULL, 0 );
1478                   if (len) aux_long += len + 1;
1479                   else *p = -1;
1480                 }
1481               p += strlen(p) + 1;
1482             }
1483           if( aux_long && aux_long < 65535 )
1484             {
1485               HDROP16                 hDrop;
1486               LPDROPFILESTRUCT16        lpDrop;
1487               
1488               aux_long += sizeof(DROPFILESTRUCT16) + 1; 
1489               hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
1490               lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop );
1491               
1492               if( lpDrop )
1493                 {
1494                   lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1495                   lpDrop->ptMousePos.x = (INT16)x;
1496                   lpDrop->ptMousePos.y = (INT16)y;
1497                   lpDrop->fInNonClientArea = (BOOL16) 
1498                     ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left)  ||
1499                       y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top)    ||
1500                       x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1501                       y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1502                   p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1503                   p = p_data;
1504                   while(*p)
1505                     {
1506                       if( *p != -1 )    /* use only "good" entries */
1507                         {
1508                           GetShortPathNameA( p, p_drop, 65535 );
1509                           p_drop += strlen( p_drop ) + 1;
1510                         }
1511                       p += strlen(p) + 1;
1512                     }
1513                   *p_drop = '\0';
1514                   PostMessage16( hWnd, WM_DROPFILES,
1515                                  (WPARAM16)hDrop, 0L );
1516                 }
1517             }
1518         }
1519       if( p_data ) TSXFree(p_data);  
1520       
1521     } /* WS_EX_ACCEPTFILES */
1522
1523   WIN_ReleaseWndPtr(pDropWnd);
1524 }
1525
1526 /**********************************************************************
1527  *           EVENT_DropURLs
1528  *
1529  * drop items are separated by \n 
1530  * each item is prefixed by its mime type
1531  *
1532  * event->data.l[3], event->data.l[4] contains drop x,y position
1533  */
1534 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1535 {
1536   WND           *pDropWnd;
1537   WND           *pWnd;
1538   unsigned long data_length;
1539   unsigned long aux_long, drop_len = 0;
1540   unsigned char *p_data = NULL; /* property data */
1541   char          *p_drop = NULL;
1542   char          *p, *next;
1543   int           x, y, drop32 = FALSE ;
1544   union {
1545     Atom        atom_aux;
1546     int         i;
1547     Window      w_aux;
1548   }             u; /* unused */
1549   union {
1550     HDROP16     h16;
1551     HDROP     h32;
1552   } hDrop;
1553
1554   pWnd = WIN_FindWndPtr(hWnd);
1555   drop32 = pWnd->flags & WIN_ISWIN32;
1556
1557   if (!(pWnd->dwExStyle & WS_EX_ACCEPTFILES))
1558   {
1559     WIN_ReleaseWndPtr(pWnd);
1560     return;
1561   }
1562   WIN_ReleaseWndPtr(pWnd);
1563
1564   TSXGetWindowProperty( display, DefaultRootWindow(display),
1565                         dndSelection, 0, 65535, FALSE,
1566                         AnyPropertyType, &u.atom_aux, &u.i,
1567                         &data_length, &aux_long, &p_data);
1568   if (aux_long)
1569     WARN_(event)("property too large, truncated!\n");
1570   TRACE_(event)("urls=%s\n", p_data);
1571
1572   if( !aux_long && p_data) {    /* don't bother if > 64K */
1573     /* calculate length */
1574     p = p_data;
1575     next = strchr(p, '\n');
1576     while (p) {
1577       if (next) *next=0;
1578       if (strncmp(p,"file:",5) == 0 ) {
1579         INT len = GetShortPathNameA( p+5, NULL, 0 );
1580         if (len) drop_len += len + 1;
1581       }
1582       if (next) { 
1583         *next = '\n'; 
1584         p = next + 1;
1585         next = strchr(p, '\n');
1586       } else {
1587         p = NULL;
1588       }
1589     }
1590     
1591     if( drop_len && drop_len < 65535 ) {
1592       TSXQueryPointer( display, X11DRV_GetXRootWindow(), &u.w_aux, &u.w_aux, 
1593                        &x, &y, &u.i, &u.i, &u.i);
1594
1595       pDropWnd = WIN_FindWndPtr( hWnd );
1596       
1597       if (drop32) {
1598         LPDROPFILESTRUCT        lpDrop;
1599         drop_len += sizeof(DROPFILESTRUCT) + 1; 
1600         hDrop.h32 = (HDROP)GlobalAlloc( GMEM_SHARE, drop_len );
1601         lpDrop = (LPDROPFILESTRUCT) GlobalLock( hDrop.h32 );
1602         
1603         if( lpDrop ) {
1604           lpDrop->lSize = sizeof(DROPFILESTRUCT);
1605           lpDrop->ptMousePos.x = (INT)x;
1606           lpDrop->ptMousePos.y = (INT)y;
1607           lpDrop->fInNonClientArea = (BOOL) 
1608             ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left)  ||
1609               y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top)    ||
1610               x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1611               y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1612           lpDrop->fWideChar = FALSE;
1613           p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT);
1614         }
1615       } else {
1616         LPDROPFILESTRUCT16        lpDrop;
1617         drop_len += sizeof(DROPFILESTRUCT16) + 1; 
1618         hDrop.h16 = (HDROP16)GlobalAlloc16( GMEM_SHARE, drop_len );
1619         lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop.h16 );
1620         
1621         if( lpDrop ) {
1622           lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1623           lpDrop->ptMousePos.x = (INT16)x;
1624           lpDrop->ptMousePos.y = (INT16)y;
1625           lpDrop->fInNonClientArea = (BOOL16) 
1626             ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left)  ||
1627               y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top)    ||
1628               x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1629               y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1630           p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1631         }
1632       }
1633       
1634       /* create message content */
1635       if (p_drop) {
1636         p = p_data;
1637         next = strchr(p, '\n');
1638         while (p) {
1639           if (next) *next=0;
1640           if (strncmp(p,"file:",5) == 0 ) {
1641             INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1642             if (len) {
1643               TRACE_(event)("drop file %s as %s\n", p+5, p_drop);
1644               p_drop += len+1;
1645             } else {
1646               WARN_(event)("can't convert file %s to dos name \n", p+5);
1647             }
1648           } else {
1649             WARN_(event)("unknown mime type %s\n", p);
1650           }
1651           if (next) { 
1652             *next = '\n'; 
1653             p = next + 1;
1654             next = strchr(p, '\n');
1655           } else {
1656             p = NULL;
1657           }
1658           *p_drop = '\0';
1659         }
1660
1661         if (drop32) {
1662           /* can not use PostMessage32A because it is currently based on 
1663            * PostMessage16 and WPARAM32 would be truncated to WPARAM16
1664            */
1665           GlobalUnlock(hDrop.h32);
1666           SendMessageA( hWnd, WM_DROPFILES,
1667                           (WPARAM)hDrop.h32, 0L );
1668         } else {
1669           GlobalUnlock16(hDrop.h16);
1670           PostMessage16( hWnd, WM_DROPFILES,
1671                          (WPARAM16)hDrop.h16, 0L );
1672         }
1673       }
1674       WIN_ReleaseWndPtr(pDropWnd);
1675     }
1676     if( p_data ) TSXFree(p_data);  
1677   }
1678 }
1679
1680 /**********************************************************************
1681  *           EVENT_ClientMessage
1682  */
1683 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
1684 {
1685   if (event->message_type != None && event->format == 32) {
1686     if ((event->message_type == wmProtocols) && 
1687         (((Atom) event->data.l[0]) == wmDeleteWindow))
1688     {
1689       /* Ignore the delete window request if the window has been disabled
1690        * and we are in managed mode. This is to disallow applications from
1691        * being closed by the window manager while in a modal state.
1692        */
1693       BOOL bIsDisabled;
1694       bIsDisabled = GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED;
1695
1696       if ( !Options.managed || !bIsDisabled )
1697       PostMessage16( hWnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
1698     }
1699     else if ( event->message_type == dndProtocol &&
1700               (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
1701       EVENT_DropFromOffiX(hWnd, event);
1702     else if ( event->message_type == dndProtocol &&
1703               event->data.l[0] == DndURL )
1704       EVENT_DropURLs(hWnd, event);
1705     else {
1706 #if 0
1707       /* enable this if you want to see the message */
1708       unsigned char* p_data = NULL;
1709       union {
1710         unsigned long   l;
1711         int             i;
1712         Atom            atom;
1713       } u; /* unused */
1714       TSXGetWindowProperty( display, DefaultRootWindow(display),
1715                             dndSelection, 0, 65535, FALSE,
1716                             AnyPropertyType, &u.atom, &u.i,
1717                             &u.l, &u.l, &p_data);
1718       TRACE_(event)("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1719             event->message_type, event->data.l[0], event->data.l[1], 
1720             event->data.l[2], event->data.l[3], event->data.l[4],
1721             p_data);
1722 #endif
1723       TRACE_(event)("unrecognized ClientMessage\n" );
1724     }
1725   }
1726 }
1727
1728 /**********************************************************************
1729  *           EVENT_EnterNotify
1730  *
1731  * Install colormap when Wine window is focused in
1732  * self-managed mode with private colormap
1733  */
1734 #if 0
1735 void EVENT_EnterNotify( HWND hWnd, XCrossingEvent *event )
1736 {
1737   if( !Options.managed && X11DRV_GetXRootWindow() == DefaultRootWindow(display) &&
1738       (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus() )
1739     TSXInstallColormap( display, X11DRV_PALETTE_GetColormap() );
1740 }
1741 #endif
1742
1743 /**********************************************************************
1744  *              EVENT_MapNotify
1745  */
1746 void EVENT_MapNotify( HWND hWnd, XMapEvent *event )
1747 {
1748   HWND hwndFocus = GetFocus();
1749   WND *wndFocus = WIN_FindWndPtr(hwndFocus);
1750   WND *pWnd = WIN_FindWndPtr(hWnd);
1751   if (pWnd->flags & WIN_MANAGED)
1752   {
1753       pWnd->dwStyle &= ~WS_MINIMIZE;
1754       ShowOwnedPopups(hWnd,TRUE);
1755   }
1756   WIN_ReleaseWndPtr(pWnd);
1757
1758   if (hwndFocus && IsChild( hWnd, hwndFocus ))
1759       X11DRV_WND_SetFocus(wndFocus);
1760
1761   WIN_ReleaseWndPtr(wndFocus);
1762   
1763   return;
1764 }
1765
1766
1767 /**********************************************************************
1768  *              EVENT_MapNotify
1769  */
1770 void EVENT_UnmapNotify( HWND hWnd, XUnmapEvent *event )
1771 {
1772   WND *pWnd = WIN_FindWndPtr(hWnd);
1773   if (pWnd->flags & WIN_MANAGED)
1774   {
1775       EndMenu();
1776       if( pWnd->dwStyle & WS_VISIBLE )
1777       {
1778           pWnd->dwStyle |= WS_MINIMIZE;
1779           ShowOwnedPopups(hWnd,FALSE);
1780       }
1781   }
1782   WIN_ReleaseWndPtr(pWnd);
1783 }
1784
1785
1786 #endif /* !defined(X_DISPLAY_MISSING) */