Release 970616
[wine] / windows / event.c
1 /*
2  * X events handling functions
3  * 
4  * Copyright 1993 Alexandre Julliard
5  * 
6  */
7
8 #include <ctype.h>
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <sys/time.h>
14 #include <sys/types.h>
15 #include <errno.h>
16 #include <X11/keysym.h>
17 #include <X11/Xlib.h>
18 #include <X11/Xresource.h>
19 #include <X11/Xutil.h>
20 #include <X11/Xatom.h>
21
22 #include "windows.h"
23 #include "winnt.h"
24 #include "gdi.h"
25 #include "heap.h"
26 #include "queue.h"
27 #include "win.h"
28 #include "class.h"
29 #include "clipboard.h"
30 #include "message.h"
31 #include "module.h"
32 #include "options.h"
33 #include "queue.h"
34 #include "winpos.h"
35 #include "drive.h"
36 #include "shell.h"
37 #include "xmalloc.h"
38 #include "keyboard.h"
39 #include "stddebug.h"
40 #include "debug.h"
41 #include "dde_proc.h"
42
43
44 #define NB_BUTTONS      3     /* Windows can handle 3 buttons */
45
46 #define DndNotDnd       -1    /* OffiX drag&drop */
47 #define DndUnknown      0
48 #define DndRawData      1
49 #define DndFile         2
50 #define DndFiles        3
51 #define DndText         4
52 #define DndDir          5
53 #define DndLink         6
54 #define DndExe          7
55
56 #define DndEND          8
57
58   /* X context to associate a hwnd to an X window */
59 static XContext winContext = 0;
60
61 static INT16  captureHT = HTCLIENT;
62 static HWND32 captureWnd = 0;
63 static BOOL32 InputEnabled = TRUE;
64 static BOOL32 SwappedButtons = FALSE;
65
66 static Atom wmProtocols = None;
67 static Atom wmDeleteWindow = None;
68 static Atom dndProtocol = None;
69 static Atom dndSelection = None;
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   /* Event handlers */
84 static void EVENT_Key( XKeyEvent *event );
85 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event );
86 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event );
87 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event );
88 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event );
89 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event );
90 static void EVENT_Expose( WND *pWnd, XExposeEvent *event );
91 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event );
92 static void EVENT_ConfigureNotify( HWND32 hwnd, XConfigureEvent *event );
93 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event);
94 static void EVENT_SelectionNotify( XSelectionEvent *event);
95 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event);
96 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event );
97 static void EVENT_MapNotify( HWND32 hwnd, XMapEvent *event );
98
99 /* Usable only with OLVWM - compile option perhaps?
100 static void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event );
101 */
102
103 extern void FOCUS_SetXFocus( HWND32 );
104 extern BOOL16 DRAG_QueryUpdate( HWND16, SEGPTR, BOOL32 );
105
106 /***********************************************************************
107  *           EVENT_ProcessEvent
108  *
109  * Process an X event.
110  */
111 void EVENT_ProcessEvent( XEvent *event )
112 {
113     WND *pWnd;
114     
115     if (XFindContext( display, event->xany.window, winContext,
116                       (char **)&pWnd ) != 0)
117         return;  /* Not for a registered window */
118
119     dprintf_event( stddeb, "Got event %s for hwnd %04x\n",
120                    event_names[event->type], pWnd->hwndSelf );
121
122     switch(event->type)
123     {
124     case KeyPress:
125     case KeyRelease:
126         if (InputEnabled)
127             EVENT_Key( (XKeyEvent*)event );
128         break;
129         
130     case ButtonPress:
131         if (InputEnabled)
132             EVENT_ButtonPress( pWnd, (XButtonEvent*)event );
133         break;
134
135     case ButtonRelease:
136         if (InputEnabled)
137             EVENT_ButtonRelease( pWnd, (XButtonEvent*)event );
138         break;
139
140     case MotionNotify:
141         /* Wine between two fast machines across the overloaded campus
142            ethernet gets very boged down in MotionEvents. The following
143            simply finds the last motion event in the queue and drops
144            the rest. On a good link events are servered before they build
145            up so this doesn't take place. On a slow link this may cause
146            problems if the event order is important. I'm not yet seen
147            of any problems. Jon 7/6/96.
148          */
149         if (InputEnabled)
150         {
151             while (XCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
152                                           MotionNotify, event));    
153             EVENT_MotionNotify( pWnd, (XMotionEvent*)event );
154         }
155         break;
156
157     case FocusIn:
158         EVENT_FocusIn( pWnd, (XFocusChangeEvent*)event );
159         break;
160
161     case FocusOut:
162         EVENT_FocusOut( pWnd, (XFocusChangeEvent*)event );
163         break;
164
165     case Expose:
166         EVENT_Expose( pWnd, (XExposeEvent *)event );
167         break;
168
169     case GraphicsExpose:
170         EVENT_GraphicsExpose( pWnd, (XGraphicsExposeEvent *)event );
171         break;
172
173     case ConfigureNotify:
174         EVENT_ConfigureNotify( pWnd->hwndSelf, (XConfigureEvent*)event );
175         break;
176
177     case SelectionRequest:
178         EVENT_SelectionRequest( pWnd, (XSelectionRequestEvent *)event );
179         break;
180
181     case SelectionNotify:
182         EVENT_SelectionNotify( (XSelectionEvent *)event );
183         break;
184
185     case SelectionClear:
186         EVENT_SelectionClear( pWnd, (XSelectionClearEvent*) event );
187         break;
188
189     case ClientMessage:
190         EVENT_ClientMessage( pWnd, (XClientMessageEvent *) event );
191         break;
192
193 /*  case EnterNotify:
194  *       EVENT_EnterNotify( pWnd, (XCrossingEvent *) event );
195  *       break;
196  */
197     case NoExpose:
198         break;
199
200     /* We get all these because of StructureNotifyMask. */
201     case UnmapNotify:
202     case CirculateNotify:
203     case CreateNotify:
204     case DestroyNotify:
205     case GravityNotify:
206     case ReparentNotify:
207         break;
208
209     case MapNotify:
210         EVENT_MapNotify( pWnd->hwndSelf, (XMapEvent *)event );
211         break;
212
213     default:    
214         dprintf_event(stddeb, "Unprocessed event %s for hwnd %04x\n",
215                 event_names[event->type], pWnd->hwndSelf );
216         break;
217     }
218 }
219
220
221 /***********************************************************************
222  *           EVENT_RegisterWindow
223  *
224  * Associate an X window to a HWND.
225  */
226 void EVENT_RegisterWindow( WND *pWnd )
227 {
228     if (wmProtocols == None)
229         wmProtocols = XInternAtom( display, "WM_PROTOCOLS", True );
230     if (wmDeleteWindow == None)
231         wmDeleteWindow = XInternAtom( display, "WM_DELETE_WINDOW", True );
232     if( dndProtocol == None )
233         dndProtocol = XInternAtom( display, "DndProtocol" , False );
234     if( dndSelection == None )
235         dndSelection = XInternAtom( display, "DndSelection" , False );
236
237     XSetWMProtocols( display, pWnd->window, &wmDeleteWindow, 1 );
238
239     if (!winContext) winContext = XUniqueContext();
240     XSaveContext( display, pWnd->window, winContext, (char *)pWnd );
241 }
242
243 /***********************************************************************
244  *           EVENT_DestroyWindow
245  */
246 void EVENT_DestroyWindow( WND *pWnd )
247 {
248    XEvent xe;
249
250    XDeleteContext( display, pWnd->window, winContext );
251    XDestroyWindow( display, pWnd->window );
252    while( XCheckWindowEvent(display, pWnd->window, NoEventMask, &xe) );
253 }
254
255 /***********************************************************************
256  *           EVENT_WaitXEvent
257  *
258  * Wait for an X event, optionally sleeping until one arrives.
259  * Return TRUE if an event is pending, FALSE on timeout or error
260  * (for instance lost connection with the server).
261  */
262 BOOL32 EVENT_WaitXEvent( BOOL32 sleep, BOOL32 peek )
263 {
264     XEvent event;
265     LONG maxWait = sleep ? TIMER_GetNextExpiration() : 0;
266
267     /* Wait for an event or a timeout. If maxWait is -1, we have no timeout;
268      * in this case, we fall through directly to the XNextEvent loop.
269      */
270
271     if ((maxWait != -1) && !XPending(display))
272     {
273         fd_set read_set;
274         struct timeval timeout;
275         int fd = ConnectionNumber(display);
276
277         FD_ZERO( &read_set );
278         FD_SET( fd, &read_set );
279
280         timeout.tv_usec = (maxWait % 1000) * 1000;
281         timeout.tv_sec = maxWait / 1000;
282
283 #ifdef CONFIG_IPC
284         sigsetjmp(env_wait_x, 1);
285         stop_wait_op= CONT;
286             
287         if (DDE_GetRemoteMessage()) {
288             while(DDE_GetRemoteMessage())
289                 ;
290             return TRUE;
291         }
292         stop_wait_op = STOP_WAIT_X;
293         /* The code up to the next "stop_wait_op = CONT" must be reentrant */
294         if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1 &&
295             !XPending(display))
296         {
297             stop_wait_op = CONT;
298             TIMER_ExpireTimers();
299             return FALSE;
300         }
301         else stop_wait_op = CONT;
302 #else  /* CONFIG_IPC */
303         if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1)
304         {
305             /* Timeout or error */
306             TIMER_ExpireTimers();
307             return FALSE;
308         }
309 #endif  /* CONFIG_IPC */
310
311     }
312
313     /* Process the event (and possibly others that occurred in the meantime) */
314
315     do
316     {
317
318 #ifdef CONFIG_IPC
319         if (DDE_GetRemoteMessage())
320         {
321             while(DDE_GetRemoteMessage()) ;
322             return TRUE;
323         }
324 #endif  /* CONFIG_IPC */
325
326         XNextEvent( display, &event );
327
328         if( peek )
329         {
330           WND*          pWnd;
331           MESSAGEQUEUE* pQ;
332
333           if (XFindContext( display, ((XAnyEvent *)&event)->window, winContext,
334                             (char **)&pWnd ) || (event.type == NoExpose))
335               continue;
336
337           /* Check only for those events which can be processed
338            * internally. */
339
340           if( event.type == MotionNotify ||
341               event.type == ButtonPress || event.type == ButtonRelease ||
342               event.type == KeyPress || event.type == KeyRelease ||
343               event.type == SelectionRequest || event.type == SelectionClear )
344           {
345                EVENT_ProcessEvent( &event );
346                continue;
347           }
348
349           if( pWnd )
350             if( (pQ = (MESSAGEQUEUE*)GlobalLock16(pWnd->hmemTaskQ)) )
351             {
352               pQ->flags |= QUEUE_FLAG_XEVENT;
353               PostEvent(pQ->hTask);
354               XPutBackEvent(display, &event);
355               break;
356             }
357         }
358         else
359           EVENT_ProcessEvent( &event );
360     }
361     while (XPending( display ));
362     return TRUE;
363 }
364
365
366 /***********************************************************************
367  *           EVENT_Synchronize
368  *
369  * Synchronize with the X server. Should not be used too often.
370  */
371 void EVENT_Synchronize()
372 {
373     XEvent event;
374
375     XSync( display, False );
376     while (XPending( display ))
377     {
378         XNextEvent( display, &event );
379         EVENT_ProcessEvent( &event );
380     }    
381 }
382
383 /***********************************************************************
384  *           EVENT_QueryZOrder
385  *
386  * Try to synchronize internal z-order with the window manager's.
387  */
388 static BOOL32 __check_query_condition( WND** pWndA, WND** pWndB )
389 {
390     /* return TRUE if we have at least two managed windows */
391
392     for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
393         if( (*pWndA)->flags & WIN_MANAGED &&
394             (*pWndA)->dwStyle & WS_VISIBLE ) break;
395     if( *pWndA )
396         for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
397             if( (*pWndB)->flags & WIN_MANAGED &&
398                 (*pWndB)->dwStyle & WS_VISIBLE ) break;
399      return ((*pWndB) != NULL);
400 }
401
402 static Window __get_common_ancestor( Window A, Window B,
403                                      Window** children, unsigned* total )
404 {
405     /* find the real root window */
406
407     Window      root, *childrenB;
408     unsigned    totalB;
409
410     do
411     {
412         if( *children ) XFree( *children );
413         XQueryTree( display, A, &root, &A, children, total );
414         XQueryTree( display, B, &root, &B, &childrenB, &totalB );
415         if( childrenB ) XFree( childrenB );
416     } while( A != B && A && B );
417     return ( A && B ) ? A : 0 ;
418 }
419
420 static Window __get_top_decoration( Window w, Window ancestor )
421 {
422     Window*     children, root, prev = w, parent = w;
423     unsigned    total;
424
425     do
426     {
427         w = parent;
428         XQueryTree( display, w, &root, &parent, &children, &total );
429         if( children ) XFree( children );
430     } while( parent && parent != ancestor );
431     dprintf_event( stddeb, "\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
432     return ( parent ) ? w : 0 ;
433 }
434
435 static unsigned __td_lookup( Window w, Window* list, unsigned max )
436 {
437     unsigned    i;
438     for( i = 0; i < max; i++ ) if( list[i] == w ) break;
439     return i;
440 }
441
442 static BOOL32 EVENT_QueryZOrder( WND* pWndCheck )
443 {
444     BOOL32      bRet = FALSE;
445     HWND32      hwndInsertAfter = HWND_TOP;
446     WND*        pWnd, *pWndZ = WIN_GetDesktop()->child;
447     Window      w, parent, *children = NULL;
448     unsigned    total, check, pos, best;
449
450     if( !__check_query_condition(&pWndZ, &pWnd) ) return TRUE;
451
452     parent = __get_common_ancestor( pWndZ->window, pWnd->window,
453                                       &children, &total );
454     if( parent )
455     {
456         w = __get_top_decoration( pWndCheck->window, parent );
457         if( w != children[total - 1] )
458         {
459             check = __td_lookup( w, children, total );
460             best = total;
461             for( pWnd = pWndZ; pWnd; pWnd = pWnd->next )
462             {
463                 if( pWnd != pWndCheck )
464                 {
465                     if( !(pWnd->flags & WIN_MANAGED) ||
466                         !(w = __get_top_decoration( pWnd->window, parent )) )
467                         continue;
468                     pos = __td_lookup( w, children, total );
469                     if( pos < best && pos > check )
470                     {
471                         best = pos;
472                         hwndInsertAfter = pWnd->hwndSelf;
473                     }
474                     if( check - best == 1 ) break;
475                 }
476             }
477             WIN_UnlinkWindow( pWndCheck->hwndSelf );
478             WIN_LinkWindow( pWndCheck->hwndSelf, hwndInsertAfter);
479         }
480     }
481     if( children ) XFree( children );
482     return bRet;
483 }
484
485
486 /***********************************************************************
487  *           EVENT_XStateToKeyState
488  *
489  * Translate a X event state (Button1Mask, ShiftMask, etc...) to
490  * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
491  */
492 static WORD EVENT_XStateToKeyState( int state )
493 {
494     int kstate = 0;
495     
496     if (state & Button1Mask) kstate |= MK_LBUTTON;
497     if (state & Button2Mask) kstate |= MK_MBUTTON;
498     if (state & Button3Mask) kstate |= MK_RBUTTON;
499     if (state & ShiftMask)   kstate |= MK_SHIFT;
500     if (state & ControlMask) kstate |= MK_CONTROL;
501     return kstate;
502 }
503
504
505 /***********************************************************************
506  *           EVENT_Expose
507  */
508 static void EVENT_Expose( WND *pWnd, XExposeEvent *event )
509 {
510     RECT32 rect;
511
512     /* Make position relative to client area instead of window */
513     rect.left   = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
514     rect.top    = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
515     rect.right  = rect.left + event->width;
516     rect.bottom = rect.top + event->height;
517
518     PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
519                         RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
520                         (event->count ? 0 : RDW_ERASENOW), 0 );
521 }
522
523
524 /***********************************************************************
525  *           EVENT_GraphicsExpose
526  *
527  * This is needed when scrolling area is partially obscured
528  * by non-Wine X window.
529  */
530 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event )
531 {
532     RECT32 rect;
533
534     /* Make position relative to client area instead of window */
535     rect.left   = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
536     rect.top    = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
537     rect.right  = rect.left + event->width;
538     rect.bottom = rect.top + event->height;
539
540     PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
541                         RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
542                         (event->count ? 0 : RDW_ERASENOW), 0 );
543 }
544
545
546 /***********************************************************************
547  *           EVENT_Key
548  *
549  * Handle a X key event
550  */
551 static void EVENT_Key( XKeyEvent *event )
552 {
553     KEYBOARD_HandleEvent( event );
554 }
555
556
557 /***********************************************************************
558  *           EVENT_MotionNotify
559  */
560 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event )
561 {
562     hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ), 0L,
563                     event->x_root - desktopX, event->y_root - desktopY,
564                     event->time - MSG_WineStartTicks, (DWORD)pWnd->hwndSelf );
565 }
566
567
568 /***********************************************************************
569  *           EVENT_DummyMotionNotify
570  *
571  * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
572  */
573 void EVENT_DummyMotionNotify(void)
574 {
575     Window root, child;
576     int rootX, rootY, childX, childY;
577     unsigned int state;
578
579     if (XQueryPointer( display, rootWindow, &root, &child,
580                        &rootX, &rootY, &childX, &childY, &state ))
581     {
582         hardware_event(WM_MOUSEMOVE, EVENT_XStateToKeyState( state ), 0L,
583                        rootX - desktopX, rootY - desktopY, GetTickCount(), 0 );
584     }
585 }
586
587
588 /***********************************************************************
589  *           EVENT_ButtonPress
590  */
591 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event )
592 {
593     static WORD messages[NB_BUTTONS] = 
594         { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
595     int buttonNum = event->button - 1;
596
597     if (buttonNum >= NB_BUTTONS) return;
598     if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
599     MouseButtonsStates[buttonNum] = 0x8000;
600     AsyncMouseButtonsStates[buttonNum] = 0x8000;
601     hardware_event( messages[buttonNum],
602                     EVENT_XStateToKeyState( event->state ), 0L,
603                     event->x_root - desktopX, event->y_root - desktopY,
604                     event->time - MSG_WineStartTicks, (DWORD)pWnd->hwndSelf );
605 }
606
607
608 /***********************************************************************
609  *           EVENT_ButtonRelease
610  */
611 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event )
612 {
613     static const WORD messages[NB_BUTTONS] = 
614         { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
615     int buttonNum = event->button - 1;
616
617     if (buttonNum >= NB_BUTTONS) return;    
618     if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
619     MouseButtonsStates[buttonNum] = FALSE;
620     hardware_event( messages[buttonNum],
621                     EVENT_XStateToKeyState( event->state ), 0L,
622                     event->x_root - desktopX, event->y_root - desktopY,
623                     event->time - MSG_WineStartTicks, (DWORD)pWnd->hwndSelf );
624 }
625
626
627 /**********************************************************************
628  *              EVENT_FocusIn
629  */
630 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event )
631 {
632     if (Options.managed) EVENT_QueryZOrder( pWnd );
633
634     if (event->detail != NotifyPointer)
635     { 
636         HWND32  hwnd = pWnd->hwndSelf;
637
638         if (hwnd != GetActiveWindow32()) 
639             WINPOS_ChangeActiveWindow( hwnd, FALSE );
640         if ((hwnd != GetFocus32()) && !IsChild32( hwnd, GetFocus32()))
641             SetFocus32( hwnd );
642     }
643 }
644
645
646 /**********************************************************************
647  *              EVENT_FocusOut
648  *
649  * Note: only top-level override-redirect windows get FocusOut events.
650  */
651 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event )
652 {
653     if (event->detail != NotifyPointer)
654     {
655         HWND32  hwnd = pWnd->hwndSelf;
656
657         if (hwnd == GetActiveWindow32()) 
658             WINPOS_ChangeActiveWindow( 0, FALSE );
659         if ((hwnd == GetFocus32()) || IsChild32( hwnd, GetFocus32()))
660             SetFocus32( 0 );
661     }
662 }
663
664 /**********************************************************************
665  *              EVENT_CheckFocus
666  */
667 BOOL32 EVENT_CheckFocus(void)
668 {
669     WND*   pWnd;
670     Window xW;
671     int    state;
672
673     XGetInputFocus(display, &xW, &state);
674     if( xW == None ||
675         XFindContext(display, xW, winContext, (char **)&pWnd) ) 
676         return FALSE;
677     return TRUE;
678 }
679
680 /**********************************************************************
681  *              EVENT_ConfigureNotify
682  *
683  * The ConfigureNotify event is only selected on the desktop window
684  * and on top-level windows when the -managed flag is used.
685  */
686 static void EVENT_ConfigureNotify( HWND32 hwnd, XConfigureEvent *event )
687 {
688     /* FIXME: with -desktop xxx we get this event _before_ desktop 
689      * window structure is created. WIN_GetDesktop() check is a hack.
690      */
691
692     if ( !WIN_GetDesktop() || hwnd == GetDesktopWindow32())
693     {
694         desktopX = event->x;
695         desktopY = event->y;
696     }
697     else
698     {
699         WND *wndPtr = WIN_FindWndPtr( hwnd );
700         WINDOWPOS16 *winpos;
701         RECT16 newWindowRect, newClientRect;
702         HRGN32 hrgnOldPos, hrgnNewPos;
703         Window above = event->above;
704
705         if (!wndPtr || !(wndPtr->flags & WIN_MANAGED) ||
706             !(winpos = SEGPTR_NEW(WINDOWPOS16))) return;
707
708         /* Fill WINDOWPOS struct */
709         winpos->flags = SWP_NOACTIVATE | SWP_NOZORDER;
710         winpos->hwnd = hwnd;
711         winpos->x = event->x;
712         winpos->y = event->y;
713         winpos->cx = event->width;
714         winpos->cy = event->height;
715
716         /* Check for unchanged attributes */
717         if(winpos->x == wndPtr->rectWindow.left &&
718            winpos->y == wndPtr->rectWindow.top)
719             winpos->flags |= SWP_NOMOVE;
720         if(winpos->cx == wndPtr->rectWindow.right - wndPtr->rectWindow.left &&
721            winpos->cy == wndPtr->rectWindow.bottom - wndPtr->rectWindow.top)
722             winpos->flags |= SWP_NOSIZE;
723
724         /* Send WM_WINDOWPOSCHANGING */
725         SendMessage16(hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)SEGPTR_GET(winpos));
726
727         /* Calculate new position and size */
728         newWindowRect.left = event->x;
729         newWindowRect.right = event->x + event->width;
730         newWindowRect.top = event->y;
731         newWindowRect.bottom = event->y + event->height;
732
733         WINPOS_SendNCCalcSize( winpos->hwnd, TRUE, &newWindowRect,
734                                &wndPtr->rectWindow, &wndPtr->rectClient,
735                                SEGPTR_GET(winpos), &newClientRect );
736
737         hrgnOldPos = CreateRectRgnIndirect16( &wndPtr->rectWindow );
738         hrgnNewPos = CreateRectRgnIndirect16( &newWindowRect );
739         CombineRgn32( hrgnOldPos, hrgnOldPos, hrgnNewPos, RGN_DIFF );
740  
741         /* Set new size and position */
742         wndPtr->rectWindow = newWindowRect;
743         wndPtr->rectClient = newClientRect;
744         SendMessage16( hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)SEGPTR_GET(winpos));
745
746         SEGPTR_FREE(winpos);
747
748         if( IsWindow32( hwnd ) )
749             if( above == None )                 /* absolute bottom */
750             {
751                 WIN_UnlinkWindow( hwnd );
752                 WIN_LinkWindow( hwnd, HWND_BOTTOM);
753             }
754             else EVENT_QueryZOrder( wndPtr );   /* try to outsmart window manager */
755
756         DeleteObject32(hrgnOldPos);
757         DeleteObject32(hrgnNewPos);
758     }
759 }
760
761
762 /***********************************************************************
763  *           EVENT_SelectionRequest
764  */
765 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event )
766 {
767     XSelectionEvent result;
768     Atom            rprop = None;
769     Window          request = event->requestor;
770
771     if(event->target == XA_STRING)
772     {
773         HANDLE16 hText;
774         LPSTR  text;
775         int    size,i,j;
776
777         rprop = event->property;
778
779         if(rprop == None) rprop = event->target;
780
781         if(event->selection!=XA_PRIMARY) rprop = None;
782         else if(!CLIPBOARD_IsPresent(CF_OEMTEXT)) rprop = None;
783         else
784         {
785             /* open to make sure that clipboard is available */
786
787             BOOL32 couldOpen = OpenClipboard32( pWnd->hwndSelf );
788             char* lpstr = 0;
789
790             hText = GetClipboardData16(CF_TEXT);
791             text = GlobalLock16(hText);
792             size = GlobalSize16(hText);
793
794             /* remove carriage returns */
795
796             lpstr = (char*)xmalloc(size--);
797             for(i=0,j=0; i < size && text[i]; i++ )
798             {
799                if( text[i] == '\r' && 
800                   (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
801                lpstr[j++] = text[i];
802             }
803             lpstr[j]='\0';
804
805             XChangeProperty(display, request, rprop, 
806                             XA_STRING, 8, PropModeReplace, 
807                             lpstr, j);
808             free(lpstr);
809
810             /* close only if we opened before */
811
812             if(couldOpen) CloseClipboard32();
813         }
814     }
815
816     if(rprop == None) 
817        dprintf_event(stddeb,"Request for %s ignored\n", XGetAtomName(display,event->target));
818
819     result.type = SelectionNotify;
820     result.display = display;
821     result.requestor = request;
822     result.selection = event->selection;
823     result.property = rprop;
824     result.target = event->target;
825     result.time = event->time;
826     XSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
827 }
828
829
830 /***********************************************************************
831  *           EVENT_SelectionNotify
832  */
833 static void EVENT_SelectionNotify( XSelectionEvent *event )
834 {
835     if (event->selection != XA_PRIMARY) return;
836
837     if (event->target != XA_STRING) CLIPBOARD_ReadSelection( 0, None );
838     else CLIPBOARD_ReadSelection( event->requestor, event->property );
839
840     dprintf_clipboard(stddeb,"\tSelectionNotify done!\n");
841 }
842
843
844 /***********************************************************************
845  *           EVENT_SelectionClear
846  */
847 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event )
848 {
849     if (event->selection != XA_PRIMARY) return;
850     CLIPBOARD_ReleaseSelection( event->window, pWnd->hwndSelf ); 
851 }
852
853
854 /**********************************************************************
855  *           EVENT_ClientMessage
856  */
857 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event )
858 {
859     if (event->message_type != None && event->format == 32)
860     {
861        if ((event->message_type == wmProtocols) && 
862            (((Atom) event->data.l[0]) == wmDeleteWindow))
863           SendMessage16( pWnd->hwndSelf, WM_SYSCOMMAND, SC_CLOSE, 0 );
864        else if ( event->message_type == dndProtocol &&
865                 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
866        {
867           unsigned long         data_length;
868           unsigned long         aux_long;
869           unsigned char*        p_data = NULL;
870           union {
871                    Atom         atom_aux;
872                    POINT32      pt_aux;
873                    int          i;
874                 }               u;
875           int                   x, y;
876           BOOL16                bAccept;
877           HGLOBAL16             hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
878           LPDRAGINFO            lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
879           SEGPTR                spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
880           Window                w_aux_root, w_aux_child;
881           WND*                  pDropWnd;
882           
883           if( !lpDragInfo || !spDragInfo ) return;
884
885           XQueryPointer( display, pWnd->window, &w_aux_root, &w_aux_child, 
886                  &x, &y, &u.pt_aux.x, &u.pt_aux.y, (unsigned int*)&aux_long);
887
888           lpDragInfo->hScope = pWnd->hwndSelf;
889           lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
890
891           /* find out drop point and drop window */
892           if( x < 0 || y < 0 ||
893               x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
894               y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
895           {   bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
896           else
897           {
898               bAccept = DRAG_QueryUpdate( pWnd->hwndSelf, spDragInfo, TRUE );
899               x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
900           }
901           pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
902           GlobalFree16( hDragInfo );
903
904           if( bAccept )
905           {
906               XGetWindowProperty( display, DefaultRootWindow(display),
907                               dndSelection, 0, 65535, FALSE,
908                               AnyPropertyType, &u.atom_aux, &u.pt_aux.y,
909                              &data_length, &aux_long, &p_data);
910
911               if( !aux_long && p_data)  /* don't bother if > 64K */
912               {
913                 char *p = (char*) p_data;
914                 char *p_drop;
915
916                 aux_long = 0; 
917                 while( *p )     /* calculate buffer size */
918                 {
919                   p_drop = p;
920                   if((u.i = *p) != -1 ) 
921                       u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
922                   if( u.i == -1 ) *p = -1;      /* mark as "bad" */
923                   else
924                   {
925                       INT32 len = GetShortPathName32A( p, NULL, 0 );
926                       if (len) aux_long += len + 1;
927                       else *p = -1;
928                   }
929                   p += strlen(p) + 1;
930                 }
931                 if( aux_long && aux_long < 65535 )
932                 {
933                   HDROP16                 hDrop;
934                   LPDROPFILESTRUCT        lpDrop;
935
936                   aux_long += sizeof(DROPFILESTRUCT) + 1; 
937                   hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
938                   lpDrop = (LPDROPFILESTRUCT) GlobalLock16( hDrop );
939
940                   if( lpDrop )
941                   {
942                     lpDrop->wSize = sizeof(DROPFILESTRUCT);
943                     lpDrop->ptMousePos.x = (INT16)x;
944                     lpDrop->ptMousePos.y = (INT16)y;
945                     lpDrop->fInNonClientArea = (BOOL16) 
946                         ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left)  ||
947                           y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top)    ||
948                           x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
949                           y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
950                     p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT);
951                     p = p_data;
952                     while(*p)
953                     {
954                       if( *p != -1 )    /* use only "good" entries */
955                       {
956                           GetShortPathName32A( p, p_drop, 65535 );
957                           p_drop += strlen( p_drop ) + 1;
958                       }
959                       p += strlen(p) + 1;
960                     }
961                     *p_drop = '\0';
962                     PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
963                                    (WPARAM16)hDrop, 0L );
964                   }
965                 }
966               }
967               if( p_data ) XFree(p_data);  
968
969           } /* WS_EX_ACCEPTFILES */
970        } /* dndProtocol */
971        else
972           dprintf_event( stddeb, "unrecognized ClientMessage\n" );
973     }
974 }
975
976 /**********************************************************************
977  *           EVENT_EnterNotify
978  *
979  * Install colormap when Wine window is focused in
980  * self-managed mode with private colormap
981  */
982 /*
983   void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
984   {
985    if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
986      (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
987       XInstallColormap( display, COLOR_GetColormap() );
988   }
989  */ 
990
991 /**********************************************************************
992  *              EVENT_MapNotify
993  */
994 void EVENT_MapNotify( HWND32 hWnd, XMapEvent *event )
995 {
996     HWND32 hwndFocus = GetFocus32();
997
998     if (hwndFocus && IsChild32( hWnd, hwndFocus ))
999       FOCUS_SetXFocus( (HWND32)hwndFocus );
1000
1001     return;
1002 }
1003
1004 /**********************************************************************
1005  *              EVENT_Capture
1006  * 
1007  * We need this to be able to generate double click messages
1008  * when menu code captures mouse in the window without CS_DBLCLK style.
1009  */
1010 HWND32 EVENT_Capture(HWND32 hwnd, INT16 ht)
1011 {
1012     Window win;
1013     HWND32 capturePrev = captureWnd;
1014
1015     if (!hwnd)
1016     {
1017         XUngrabPointer(display, CurrentTime );
1018         captureWnd = NULL; captureHT = 0; 
1019     }
1020     else if ((win = WIN_GetXWindow( hwnd )))
1021     {
1022         WND* wndPtr = WIN_FindWndPtr( hwnd );
1023
1024         if ( wndPtr && 
1025              (XGrabPointer(display, win, False, 
1026                            ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
1027                            GrabModeAsync, GrabModeAsync,
1028                            None, None, CurrentTime ) == GrabSuccess) )
1029         {
1030             dprintf_win(stddeb, "SetCapture(0x%04x)\n", hwnd );
1031             captureWnd   = hwnd;
1032             captureHT    = ht;
1033         }
1034     }
1035
1036     if( capturePrev && capturePrev != captureWnd )
1037     {
1038         WND* wndPtr = WIN_FindWndPtr( capturePrev );
1039         if( wndPtr && (wndPtr->flags & WIN_ISWIN32) )
1040             SendMessage32A( capturePrev, WM_CAPTURECHANGED, 0L, hwnd);
1041     }
1042     return capturePrev;
1043 }
1044
1045 /**********************************************************************
1046  *              EVENT_GetCaptureInfo
1047  */
1048 INT16 EVENT_GetCaptureInfo()
1049 {
1050     return captureHT;
1051 }
1052
1053 /**********************************************************************
1054  *              SetCapture16   (USER.18)
1055  */
1056 HWND16 SetCapture16( HWND16 hwnd )
1057 {
1058     return (HWND16)EVENT_Capture( hwnd, HTCLIENT );
1059 }
1060
1061
1062 /**********************************************************************
1063  *              SetCapture32   (USER32.463)
1064  */
1065 HWND32 SetCapture32( HWND32 hwnd )
1066 {
1067     return EVENT_Capture( hwnd, HTCLIENT );
1068 }
1069
1070
1071 /**********************************************************************
1072  *              ReleaseCapture   (USER.19) (USER32.438)
1073  */
1074 void ReleaseCapture(void)
1075 {
1076     dprintf_win(stddeb, "ReleaseCapture() [%04x]\n", captureWnd );
1077     if( captureWnd ) EVENT_Capture( 0, 0 );
1078 }
1079
1080
1081 /**********************************************************************
1082  *              GetCapture16   (USER.236)
1083  */
1084 HWND16 GetCapture16(void)
1085 {
1086     return captureWnd;
1087 }
1088
1089
1090 /**********************************************************************
1091  *              GetCapture32   (USER32.207)
1092  */
1093 HWND32 GetCapture32(void)
1094 {
1095     return captureWnd;
1096 }
1097
1098
1099 /***********************************************************************
1100  *           GetMouseEventProc   (USER.337)
1101  */
1102 FARPROC16 GetMouseEventProc(void)
1103 {
1104     HMODULE16 hmodule = GetModuleHandle16("USER");
1105     return MODULE_GetEntryPoint( hmodule,
1106                                  MODULE_GetOrdinal( hmodule, "Mouse_Event" ) );
1107 }
1108
1109
1110 /***********************************************************************
1111  *           Mouse_Event   (USER.299)
1112  */
1113 void Mouse_Event( CONTEXT *context )
1114 {
1115     /* Register values:
1116      * AX = mouse event
1117      * BX = horizontal displacement if AX & ME_MOVE
1118      * CX = vertical displacement if AX & ME_MOVE
1119      * DX = button state (?)
1120      * SI = mouse event flags (?)
1121      */
1122     Window root, child;
1123     int rootX, rootY, childX, childY;
1124     unsigned int state;
1125
1126     if (AX_reg(context) & ME_MOVE)
1127     {
1128         /* We have to actually move the cursor */
1129         XWarpPointer( display, rootWindow, None, 0, 0, 0, 0,
1130                       (short)BX_reg(context), (short)CX_reg(context) );
1131         return;
1132     }
1133     if (!XQueryPointer( display, rootWindow, &root, &child,
1134                         &rootX, &rootY, &childX, &childY, &state )) return;
1135     if (AX_reg(context) & ME_LDOWN)
1136         hardware_event( WM_LBUTTONDOWN, EVENT_XStateToKeyState( state ), 0L,
1137                         rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
1138     if (AX_reg(context) & ME_LUP)
1139         hardware_event( WM_LBUTTONUP, EVENT_XStateToKeyState( state ), 0L,
1140                         rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
1141     if (AX_reg(context) & ME_RDOWN)
1142         hardware_event( WM_RBUTTONDOWN, EVENT_XStateToKeyState( state ), 0L,
1143                         rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
1144     if (AX_reg(context) & ME_RUP)
1145         hardware_event( WM_RBUTTONUP, EVENT_XStateToKeyState( state ), 0L,
1146                         rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
1147 }
1148
1149
1150 /**********************************************************************
1151  *                      EnableHardwareInput   (USER.331)
1152  */
1153 BOOL16 EnableHardwareInput(BOOL16 bEnable)
1154 {
1155   BOOL16 bOldState = InputEnabled;
1156   dprintf_event(stdnimp,"EnableHardwareInput(%d);\n", bEnable);
1157   InputEnabled = bEnable;
1158   return bOldState;
1159 }
1160
1161
1162 /***********************************************************************
1163  *           SwapMouseButton16   (USER.186)
1164  */
1165 BOOL16 SwapMouseButton16( BOOL16 fSwap )
1166 {
1167     BOOL16 ret = SwappedButtons;
1168     SwappedButtons = fSwap;
1169     return ret;
1170 }
1171
1172
1173 /***********************************************************************
1174  *           SwapMouseButton32   (USER32.536)
1175  */
1176 BOOL32 SwapMouseButton32( BOOL32 fSwap )
1177 {
1178     BOOL32 ret = SwappedButtons;
1179     SwappedButtons = fSwap;
1180     return ret;
1181 }