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