Release 960928
[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 "gdi.h"
24 #include "heap.h"
25 #include "queue.h"
26 #include "win.h"
27 #include "class.h"
28 #include "clipboard.h"
29 #include "debugger.h"
30 #include "message.h"
31 #include "module.h"
32 #include "options.h"
33 #include "queue.h"
34 #include "winpos.h"
35 #include "registers.h"
36 #include "xmalloc.h"
37 #include "stddebug.h"
38 #include "debug.h"
39 #include "dde_proc.h"
40
41 #define NB_BUTTONS      3     /* Windows can handle 3 buttons */
42
43   /* X context to associate a hwnd to an X window */
44 static XContext winContext = 0;
45
46   /* State variables */
47 BOOL MouseButtonsStates[NB_BUTTONS];
48 BOOL AsyncMouseButtonsStates[NB_BUTTONS];
49 BYTE KeyStateTable[256];
50 BYTE AsyncKeyStateTable[256];
51
52
53        WPARAM   lastEventChar = 0; /* this will have to be changed once
54                                     * ToAscii starts working */
55
56 static HWND32 captureWnd = 0;
57 static BOOL32 InputEnabled = TRUE;
58
59 /* Keyboard translation tables */
60 static const int special_key[] =
61 {
62     VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0,           /* FF08 */
63     0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0,                      /* FF10 */
64     0, 0, 0, VK_ESCAPE                                          /* FF18 */
65 };
66
67 static const int cursor_key[] =
68 {
69     VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_PRIOR, 
70                                        VK_NEXT, VK_END          /* FF50 */
71 };
72
73 static const int misc_key[] =
74 {
75     VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0,  /* FF60 */
76     VK_CANCEL, VK_HELP, VK_CANCEL, VK_MENU                      /* FF68 */
77 };
78
79 static const int keypad_key[] =
80 {
81     VK_MENU, VK_NUMLOCK,                                        /* FF7E */
82     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF80 */
83     0, 0, 0, 0, 0, VK_RETURN, 0, 0,                             /* FF88 */
84     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF90 */
85     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF98 */
86     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FFA0 */
87     0, 0, VK_MULTIPLY, VK_ADD, VK_SEPARATOR, VK_SUBTRACT, 
88                                VK_DECIMAL, VK_DIVIDE,           /* FFA8 */
89     VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4,
90                             VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, /* FFB0 */
91     VK_NUMPAD8, VK_NUMPAD9                                      /* FFB8 */
92 };
93     
94 static const int function_key[] =
95 {
96     VK_F1, VK_F2,                                               /* FFBE */
97     VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10,    /* FFC0 */
98     VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16              /* FFC8 */
99 };
100
101 static const int modifier_key[] =
102 {
103     VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL, VK_CAPITAL,
104                                                 0, 0,           /* FFE1 */
105     0, VK_MENU, VK_MENU                                         /* FFE8 */
106 };
107
108 typedef union
109 {
110     struct
111     {
112         unsigned long count : 16;
113         unsigned long code : 8;
114         unsigned long extended : 1;
115         unsigned long : 2;
116         unsigned long reserved : 2;
117         unsigned long context : 1;
118         unsigned long previous : 1;
119         unsigned long transition : 1;
120     } lp1;
121     unsigned long lp2;
122 } KEYLP;
123
124 static BOOL KeyDown = FALSE;
125
126 static const char * const event_names[] =
127 {
128     "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
129     "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
130     "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
131     "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
132     "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
133     "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
134     "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
135     "ClientMessage", "MappingNotify"
136 };
137
138   /* Event handlers */
139 static void EVENT_key( XKeyEvent *event );
140 static void EVENT_ButtonPress( XButtonEvent *event );
141 static void EVENT_ButtonRelease( XButtonEvent *event );
142 static void EVENT_MotionNotify( XMotionEvent *event );
143 static void EVENT_FocusIn( HWND hwnd, XFocusChangeEvent *event );
144 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event );
145 static void EVENT_Expose( WND *pWnd, XExposeEvent *event );
146 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event );
147 static void EVENT_ConfigureNotify( HWND hwnd, XConfigureEvent *event );
148 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event);
149 static void EVENT_SelectionNotify( XSelectionEvent *event);
150 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event);
151 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event );
152 static void EVENT_MapNotify( HWND hwnd, XMapEvent *event );
153
154 /* Usable only with OLVWM - compile option perhaps?
155 static void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event );
156 */
157
158 /***********************************************************************
159  *           EVENT_ProcessEvent
160  *
161  * Process an X event.
162  */
163 void EVENT_ProcessEvent( XEvent *event )
164 {
165     WND *pWnd;
166     
167     if (XFindContext( display, ((XAnyEvent *)event)->window, winContext,
168                       (char **)&pWnd ) != 0)
169         return;  /* Not for a registered window */
170
171     dprintf_event( stddeb, "Got event %s for hwnd %04x\n",
172                    event_names[event->type], pWnd->hwndSelf );
173
174     switch(event->type)
175     {
176     case KeyPress:
177     case KeyRelease:
178         if (InputEnabled)
179             EVENT_key( (XKeyEvent*)event );
180         break;
181         
182     case ButtonPress:
183         if (InputEnabled)
184             EVENT_ButtonPress( (XButtonEvent*)event );
185         break;
186
187     case ButtonRelease:
188         if (InputEnabled)
189             EVENT_ButtonRelease( (XButtonEvent*)event );
190         break;
191
192     case MotionNotify:
193         /* Wine between two fast machines across the overloaded campus
194            ethernet gets very boged down in MotionEvents. The following
195            simply finds the last motion event in the queue and drops
196            the rest. On a good link events are servered before they build
197            up so this doesn't take place. On a slow link this may cause
198            problems if the event order is important. I'm not yet seen
199            of any problems. Jon 7/6/96.
200          */
201         if (InputEnabled)
202         {
203             while (XCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
204                                           MotionNotify, event));    
205             EVENT_MotionNotify( (XMotionEvent*)event );
206         }
207         break;
208
209     case FocusIn:
210         EVENT_FocusIn( pWnd->hwndSelf, (XFocusChangeEvent*)event );
211         break;
212
213     case FocusOut:
214         EVENT_FocusOut( pWnd->hwndSelf, (XFocusChangeEvent*)event );
215         break;
216
217     case Expose:
218         EVENT_Expose( pWnd, (XExposeEvent *)event );
219         break;
220
221     case GraphicsExpose:
222         EVENT_GraphicsExpose( pWnd, (XGraphicsExposeEvent *)event );
223         break;
224
225     case ConfigureNotify:
226         EVENT_ConfigureNotify( pWnd->hwndSelf, (XConfigureEvent*)event );
227         break;
228
229     case SelectionRequest:
230         EVENT_SelectionRequest( pWnd, (XSelectionRequestEvent *)event );
231         break;
232
233     case SelectionNotify:
234         EVENT_SelectionNotify( (XSelectionEvent *)event );
235         break;
236
237     case SelectionClear:
238         EVENT_SelectionClear( pWnd, (XSelectionClearEvent*) event );
239         break;
240
241     case ClientMessage:
242         EVENT_ClientMessage( pWnd, (XClientMessageEvent *) event );
243         break;
244
245 /*  case EnterNotify:
246  *       EVENT_EnterNotify( pWnd, (XCrossingEvent *) event );
247  *       break;
248  */
249     case NoExpose:
250         break;
251
252     /* We get all these because of StructureNotifyMask. */
253     case UnmapNotify:
254     case CirculateNotify:
255     case CreateNotify:
256     case DestroyNotify:
257     case GravityNotify:
258     case ReparentNotify:
259         break;
260
261     case MapNotify:
262         EVENT_MapNotify( pWnd->hwndSelf, (XMapEvent *)event );
263         break;
264
265     default:    
266         dprintf_event(stddeb, "Unprocessed event %s for hwnd %04x\n",
267                 event_names[event->type], pWnd->hwndSelf );
268         break;
269     }
270 }
271
272
273 /***********************************************************************
274  *           EVENT_RegisterWindow
275  *
276  * Associate an X window to a HWND.
277  */
278 void EVENT_RegisterWindow( WND *pWnd )
279 {
280     if (!winContext) winContext = XUniqueContext();
281     XSaveContext( display, pWnd->window, winContext, (char *)pWnd );
282 }
283
284
285 /***********************************************************************
286  *           EVENT_WaitXEvent
287  *
288  * Wait for an X event, optionally sleeping until one arrives.
289  * Return TRUE if an event is pending, FALSE on timeout or error
290  * (for instance lost connection with the server).
291  */
292 BOOL32 EVENT_WaitXEvent( BOOL32 sleep, BOOL32 peek )
293 {
294     fd_set read_set;
295     struct timeval timeout;
296     XEvent event;
297     int fd = ConnectionNumber(display);
298
299     if (!XPending(display))
300     {
301         LONG maxWait = sleep ? TIMER_GetNextExpiration() : 0;
302
303         FD_ZERO( &read_set );
304         FD_SET( fd, &read_set );
305
306         timeout.tv_usec = (maxWait % 1000) * 1000;
307         timeout.tv_sec = maxWait / 1000;
308
309 #ifdef CONFIG_IPC
310         sigsetjmp(env_wait_x, 1);
311         stop_wait_op= CONT;
312             
313         if (DDE_GetRemoteMessage()) {
314             while(DDE_GetRemoteMessage())
315                 ;
316             return TRUE;
317         }
318         stop_wait_op = STOP_WAIT_X;
319         /* The code up to the next "stop_wait_op = CONT" must be reentrant */
320         if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1 &&
321             !XPending(display))
322         {
323             stop_wait_op = CONT;
324             TIMER_ExpireTimers();
325             return FALSE;
326         }
327         else stop_wait_op = CONT;
328 #else  /* CONFIG_IPC */
329         if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1)
330         {
331             /* Timeout or error */
332             TIMER_ExpireTimers();
333             return FALSE;
334         }
335 #endif  /* CONFIG_IPC */
336
337     }
338
339     /* Process the event (and possibly others that occurred in the meantime) */
340
341     do
342     {
343
344 #ifdef CONFIG_IPC
345         if (DDE_GetRemoteMessage())
346         {
347             while(DDE_GetRemoteMessage()) ;
348             return TRUE;
349         }
350 #endif  /* CONFIG_IPC */
351
352         XNextEvent( display, &event );
353
354         if( peek )
355         {
356           WND*          pWnd;
357           MESSAGEQUEUE* pQ;
358   
359           if( XFindContext( display, ((XAnyEvent *)&event)->window, winContext, (char **)&pWnd) 
360               || event.type == NoExpose )  
361               continue;
362
363           /* check for the "safe" hardware events */
364
365           if( event.type == MotionNotify ||
366               event.type == ButtonPress || event.type == ButtonRelease ||
367               event.type == KeyPress || event.type == KeyRelease ||
368               event.type == SelectionRequest || event.type == SelectionClear )
369           {
370                EVENT_ProcessEvent( &event );
371                continue;
372           }
373
374           if( pWnd )
375             if( (pQ = (MESSAGEQUEUE*)GlobalLock16(pWnd->hmemTaskQ)) )
376             {
377               pQ->flags |= QUEUE_FLAG_XEVENT;
378               PostEvent(pQ->hTask);
379               XPutBackEvent(display, &event);
380               break;
381             }
382         }
383         else
384           EVENT_ProcessEvent( &event );
385     }
386     while (XPending( display ));
387     return TRUE;
388 }
389
390
391 /***********************************************************************
392  *           EVENT_Synchronize
393  *
394  * Synchronize with the X server. Should not be used too often.
395  */
396 void EVENT_Synchronize()
397 {
398     XEvent event;
399
400     XSync( display, False );
401     while (XPending( display ))
402     {
403         XNextEvent( display, &event );
404         EVENT_ProcessEvent( &event );
405     }    
406 }
407
408
409 /***********************************************************************
410  *           EVENT_XStateToKeyState
411  *
412  * Translate a X event state (Button1Mask, ShiftMask, etc...) to
413  * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
414  */
415 static WORD EVENT_XStateToKeyState( int state )
416 {
417     int kstate = 0;
418     
419     if (state & Button1Mask) kstate |= MK_LBUTTON;
420     if (state & Button2Mask) kstate |= MK_MBUTTON;
421     if (state & Button3Mask) kstate |= MK_RBUTTON;
422     if (state & ShiftMask)   kstate |= MK_SHIFT;
423     if (state & ControlMask) kstate |= MK_CONTROL;
424     return kstate;
425 }
426
427
428 /***********************************************************************
429  *           EVENT_Expose
430  */
431 static void EVENT_Expose( WND *pWnd, XExposeEvent *event )
432 {
433     RECT32 rect;
434
435     /* Make position relative to client area instead of window */
436     rect.left   = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
437     rect.top    = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
438     rect.right  = rect.left + event->width;
439     rect.bottom = rect.top + event->height;
440
441     PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
442                         RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
443                         (event->count ? 0 : RDW_ERASENOW), 0 );
444 }
445
446
447 /***********************************************************************
448  *           EVENT_GraphicsExpose
449  *
450  * This is needed when scrolling area is partially obscured
451  * by non-Wine X window.
452  */
453 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event )
454 {
455     RECT32 rect;
456
457     /* Make position relative to client area instead of window */
458     rect.left   = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
459     rect.top    = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
460     rect.right  = rect.left + event->width;
461     rect.bottom = rect.top + event->height;
462
463     PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
464                         RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
465                         (event->count ? 0 : RDW_ERASENOW), 0 );
466 }
467
468
469 /***********************************************************************
470  *           EVENT_key
471  *
472  * Handle a X key event
473  */
474 static void EVENT_key( XKeyEvent *event )
475 {
476     char Str[24]; 
477     XComposeStatus cs; 
478     KeySym keysym;
479     WORD vkey = 0;
480     WORD xkey, key_type, key;
481     KEYLP keylp;
482     BOOL extended = FALSE;
483
484     int ascii_chars = XLookupString(event, Str, 1, &keysym, &cs);
485
486     Str[ascii_chars] = '\0';
487     dprintf_key(stddeb,"WM_KEY??? : keysym=%lX, ascii chars=%u / %X / '%s'\n", 
488            keysym, ascii_chars, Str[0], Str);
489
490     /* Ctrl-Alt-Return enters the debugger */
491     if ((keysym == XK_Return) && (event->type == KeyPress) &&
492         (event->state & ControlMask) && (event->state & Mod1Mask))
493         DEBUG_EnterDebugger();
494
495     xkey = LOWORD(keysym);
496     key_type = HIBYTE(xkey);
497     key = LOBYTE(xkey);
498     dprintf_key(stddeb,"            key_type=%X, key=%X\n", key_type, key);
499
500     if (key_type == 0xFF)                          /* non-character key */
501     {
502         if (key >= 0x08 && key <= 0x1B)            /* special key */
503             vkey = special_key[key - 0x08];
504         else if (key >= 0x50 && key <= 0x57)       /* cursor key */
505             vkey = cursor_key[key - 0x50];
506         else if (key >= 0x60 && key <= 0x6B)       /* miscellaneous key */
507             vkey = misc_key[key - 0x60];
508         else if (key >= 0x7E && key <= 0xB9)       /* keypad key */
509         {
510             vkey = keypad_key[key - 0x7E];
511             extended = TRUE;
512         }
513         else if (key >= 0xBE && key <= 0xCD)       /* function key */
514         {
515             vkey = function_key[key - 0xBE];
516             extended = TRUE;
517         }
518         else if (key >= 0xE1 && key <= 0xEA)       /* modifier key */
519             vkey = modifier_key[key - 0xE1];
520         else if (key == 0xFF)                      /* DEL key */
521             vkey = VK_DELETE;
522     }
523     else if (key_type == 0)                        /* character key */
524     {
525         if ( isalnum(key) )
526              vkey = toupper(key);                  /* convert lc to uc */
527         else if ( isspace(key) )
528           vkey = key;                              /* XXX approximately */
529         else  
530           switch (key)                             /* the rest... */
531           {
532 #define vkcase(k,val) case k: vkey = val; break;
533 #define vkcase2(k1,k2,val) case k1: case k2: vkey = val; break;
534
535               /* I wish I had a bit-paired keyboard! */
536               vkcase('!','1'); vkcase('@','2'); vkcase('#','3');
537               vkcase('$','4'); vkcase('%','5'); vkcase('^','6');
538               vkcase('&','7'); vkcase('*','8'); vkcase('(','9');
539               vkcase(')','0');
540
541               vkcase2('`','~',0xc0);
542               vkcase2('-','_',0xbd);
543               vkcase2('=','+',0xbb);
544               vkcase2('[','{',0xdb);
545               vkcase2(']','}',0xdd);
546               vkcase2(';',':',0xba);
547               vkcase2('\'','\"',0xde);
548               vkcase2(',','<',0xbc);
549               vkcase2('.','>',0xbe);
550               vkcase2('/','?',0xbf);
551               vkcase2('\\','|',0xdc);
552 #undef vkcase
553 #undef vkcase2
554             default:
555               fprintf( stderr, "Unknown key! Please report!\n" );
556               vkey = 0;                            /* whatever */
557           }
558     }
559
560     if (event->type == KeyPress)
561     {
562         if (!(KeyStateTable[vkey] & 0x80))
563             KeyStateTable[vkey] ^= 0x01;
564         KeyStateTable[vkey] |= 0x80;
565         keylp.lp1.count = 1;
566         keylp.lp1.code = LOBYTE(event->keycode) - 8;
567         keylp.lp1.extended = (extended ? 1 : 0);
568         keylp.lp1.reserved = (ascii_chars ? 1 : 0);
569         keylp.lp1.context = ( (event->state & Mod1Mask) || 
570                                (KeyStateTable[VK_MENU] & 0x80)) ? 1 : 0;
571         keylp.lp1.previous = (KeyDown ? 0 : 1);
572         keylp.lp1.transition = 0;
573         dprintf_key(stddeb,"            wParam=%X, lParam=%lX\n", 
574                     vkey, keylp.lp2 );
575         dprintf_key(stddeb,"            KeyState=%X\n", KeyStateTable[vkey]);
576         hardware_event( KeyStateTable[VK_MENU] & 0x80 ? WM_SYSKEYDOWN : WM_KEYDOWN, 
577                         vkey, keylp.lp2,
578                         event->x_root - desktopX, event->y_root - desktopY,
579                         event->time - MSG_WineStartTicks, 0 );
580         KeyDown = TRUE;
581
582         /* Currently we use reserved field in the scan-code byte to
583          * make it possible for TranslateMessage to recognize character keys
584          * and get them from lastEventChar global variable.
585          *
586          * ToAscii should handle it.
587          */
588
589         if( ascii_chars ) lastEventChar = Str[0];
590     }
591     else
592     {
593         UINT sysKey = KeyStateTable[VK_MENU];
594
595         KeyStateTable[vkey] &= ~0x80; 
596         keylp.lp1.count = 1;
597         keylp.lp1.code = LOBYTE(event->keycode) - 8;
598         keylp.lp1.extended = (extended ? 1 : 0);
599         keylp.lp1.reserved = 0;
600         keylp.lp1.context = (event->state & Mod1Mask ? 1 : 0);
601         keylp.lp1.previous = 1;
602         keylp.lp1.transition = 1;
603         dprintf_key(stddeb,"            wParam=%X, lParam=%lX\n", 
604                     vkey, keylp.lp2 );
605         dprintf_key(stddeb,"            KeyState=%X\n", KeyStateTable[vkey]);
606         hardware_event( sysKey & 0x80 ? WM_SYSKEYUP : WM_KEYUP, 
607                         vkey, keylp.lp2,
608                         event->x_root - desktopX, event->y_root - desktopY,
609                         event->time - MSG_WineStartTicks, 0 );
610         KeyDown = FALSE;
611     }
612 }
613
614
615 /***********************************************************************
616  *           EVENT_MotionNotify
617  */
618 static void EVENT_MotionNotify( XMotionEvent *event )
619 {
620     hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ), 0L,
621                     event->x_root - desktopX, event->y_root - desktopY,
622                     event->time - MSG_WineStartTicks, 0 );
623 }
624
625
626 /***********************************************************************
627  *           EVENT_DummyMotionNotify
628  *
629  * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
630  */
631 void EVENT_DummyMotionNotify(void)
632 {
633     Window root, child;
634     int rootX, rootY, childX, childY;
635     unsigned int state;
636
637     if (XQueryPointer( display, rootWindow, &root, &child,
638                        &rootX, &rootY, &childX, &childY, &state ))
639     {
640         hardware_event(WM_MOUSEMOVE, EVENT_XStateToKeyState( state ), 0L,
641                        rootX - desktopX, rootY - desktopY, GetTickCount(), 0 );
642     }
643 }
644
645
646 /***********************************************************************
647  *           EVENT_ButtonPress
648  */
649 static void EVENT_ButtonPress( XButtonEvent *event )
650 {
651     static WORD messages[NB_BUTTONS] = 
652         { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
653     int buttonNum = event->button - 1;
654
655     if (buttonNum >= NB_BUTTONS) return;
656     MouseButtonsStates[buttonNum] = 0x8000;
657     AsyncMouseButtonsStates[buttonNum] = 0x8000;
658     hardware_event( messages[buttonNum],
659                     EVENT_XStateToKeyState( event->state ), 0L,
660                     event->x_root - desktopX, event->y_root - desktopY,
661                     event->time - MSG_WineStartTicks, 0 );
662 }
663
664
665 /***********************************************************************
666  *           EVENT_ButtonRelease
667  */
668 static void EVENT_ButtonRelease( XButtonEvent *event )
669 {
670     static const WORD messages[NB_BUTTONS] = 
671         { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
672     int buttonNum = event->button - 1;
673
674     if (buttonNum >= NB_BUTTONS) return;    
675     MouseButtonsStates[buttonNum] = FALSE;
676     hardware_event( messages[buttonNum],
677                     EVENT_XStateToKeyState( event->state ), 0L,
678                     event->x_root - desktopX, event->y_root - desktopY,
679                     event->time - MSG_WineStartTicks, 0 );
680 }
681
682
683 /**********************************************************************
684  *              EVENT_FocusIn
685  */
686 static void EVENT_FocusIn (HWND hwnd, XFocusChangeEvent *event )
687 {
688     if (event->detail == NotifyPointer) return;
689     if (hwnd != GetActiveWindow()) WINPOS_ChangeActiveWindow( hwnd, FALSE );
690     if ((hwnd != GetFocus32()) && !IsChild( hwnd, GetFocus32()))
691         SetFocus32( hwnd );
692 }
693
694
695 /**********************************************************************
696  *              EVENT_FocusOut
697  *
698  * Note: only top-level override-redirect windows get FocusOut events.
699  */
700 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event )
701 {
702     if (event->detail == NotifyPointer) return;
703     if (hwnd == GetActiveWindow()) WINPOS_ChangeActiveWindow( 0, FALSE );
704     if ((hwnd == GetFocus32()) || IsChild( hwnd, GetFocus32()))
705         SetFocus32( 0 );
706 }
707
708
709 /**********************************************************************
710  *              EVENT_ConfigureNotify
711  *
712  * The ConfigureNotify event is only selected on the desktop window
713  * and on top-level windows when the -managed flag is used.
714  */
715 static void EVENT_ConfigureNotify( HWND hwnd, XConfigureEvent *event )
716 {
717     /* FIXME: with -desktop xxx we get this event _before_ desktop 
718      * window structure is created. WIN_GetDesktop() check is a hack.
719      */
720
721     if ( !WIN_GetDesktop() || hwnd == GetDesktopWindow32())
722     {
723         desktopX = event->x;
724         desktopY = event->y;
725     }
726     else
727     {
728         WND *wndPtr;
729         WINDOWPOS16 *winpos;
730         RECT16 newWindowRect, newClientRect;
731         HRGN hrgnOldPos, hrgnNewPos;
732
733         if (!(wndPtr = WIN_FindWndPtr( hwnd )) ||
734             !(wndPtr->flags & WIN_MANAGED) )
735             return;
736         
737         if (!(winpos = SEGPTR_NEW(WINDOWPOS16))) return;
738
739 /*      XTranslateCoordinates(display, event->window, rootWindow,
740             event->x, event->y, &event->x, &event->y, &child);
741             */
742
743         /* Fill WINDOWPOS struct */
744         winpos->flags = SWP_NOACTIVATE | SWP_NOZORDER;
745         winpos->hwnd = hwnd;
746         winpos->x = event->x;
747         winpos->y = event->y;
748         winpos->cx = event->width;
749         winpos->cy = event->height;
750
751         /* Check for unchanged attributes */
752         if(winpos->x == wndPtr->rectWindow.left &&
753            winpos->y == wndPtr->rectWindow.top)
754             winpos->flags |= SWP_NOMOVE;
755         if(winpos->cx == wndPtr->rectWindow.right - wndPtr->rectWindow.left &&
756            winpos->cy == wndPtr->rectWindow.bottom - wndPtr->rectWindow.top)
757             winpos->flags |= SWP_NOSIZE;
758
759         /* Send WM_WINDOWPOSCHANGING */
760         SendMessage16(hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)SEGPTR_GET(winpos));
761
762         /* Calculate new position and size */
763         newWindowRect.left = event->x;
764         newWindowRect.right = event->x + event->width;
765         newWindowRect.top = event->y;
766         newWindowRect.bottom = event->y + event->height;
767
768         WINPOS_SendNCCalcSize( winpos->hwnd, TRUE, &newWindowRect,
769                                &wndPtr->rectWindow, &wndPtr->rectClient,
770                                SEGPTR_GET(winpos), &newClientRect );
771
772         hrgnOldPos = CreateRectRgnIndirect16( &wndPtr->rectWindow );
773         hrgnNewPos = CreateRectRgnIndirect16( &newWindowRect );
774         CombineRgn( hrgnOldPos, hrgnOldPos, hrgnNewPos, RGN_DIFF );
775  
776         /* Set new size and position */
777         wndPtr->rectWindow = newWindowRect;
778         wndPtr->rectClient = newClientRect;
779         SendMessage16( hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)SEGPTR_GET(winpos));
780         SEGPTR_FREE(winpos);
781
782         /* full window drag leaves unrepainted garbage without this */
783         PAINT_RedrawWindow( 0, NULL, hrgnOldPos, RDW_INVALIDATE |
784                             RDW_ALLCHILDREN | RDW_ERASE | RDW_ERASENOW,
785                             RDW_C_USEHRGN );
786         DeleteObject(hrgnOldPos);
787         DeleteObject(hrgnNewPos);
788     }
789 }
790
791
792 /***********************************************************************
793  *           EVENT_SelectionRequest
794  */
795 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event )
796 {
797     XSelectionEvent result;
798     Atom            rprop = None;
799     Window          request = event->requestor;
800
801     if(event->target == XA_STRING)
802     {
803         HANDLE hText;
804         LPSTR  text;
805         int    size,i,j;
806
807         rprop = event->property;
808
809         if(rprop == None) rprop = event->target;
810
811         if(event->selection!=XA_PRIMARY) rprop = None;
812         else if(!CLIPBOARD_IsPresent(CF_OEMTEXT)) rprop = None;
813         else
814         {
815             /* open to make sure that clipboard is available */
816
817             BOOL        couldOpen = OpenClipboard( pWnd->hwndSelf );
818             char*       lpstr = 0;
819
820             hText = GetClipboardData(CF_TEXT);
821             text = GlobalLock16(hText);
822             size = GlobalSize16(hText);
823
824             /* remove carriage returns */
825
826             lpstr = (char*)xmalloc(size--);
827             for(i=0,j=0; i < size; i++ )
828             {
829                if( text[i] == '\r' && text[i+1] == '\n' ) continue;
830                lpstr[j++] = text[i];
831                if( text[i] == '\0' ) break;
832             }
833             lpstr[j]='\0';
834
835             XChangeProperty(display, request, rprop, 
836                             XA_STRING, 8, PropModeReplace, 
837                             lpstr, j);
838             free(lpstr);
839
840             /* close only if we opened before */
841
842             if(couldOpen) CloseClipboard();
843         }
844     }
845
846     if(rprop==None) 
847        dprintf_event(stddeb,"Request for %s ignored\n", XGetAtomName(display,event->target));
848
849     result.type=SelectionNotify;
850     result.display=display;
851     result.requestor=request;
852     result.selection=event->selection;
853     result.property=rprop;
854     result.target=event->target;
855     result.time=event->time;
856     XSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
857 }
858
859
860 /***********************************************************************
861  *           EVENT_SelectionNotify
862  */
863 static void EVENT_SelectionNotify( XSelectionEvent *event )
864 {
865     if (event->selection != XA_PRIMARY) return;
866
867     if (event->target != XA_STRING) CLIPBOARD_ReadSelection( 0, None );
868     else CLIPBOARD_ReadSelection( event->requestor, event->property );
869
870     dprintf_clipboard(stddeb,"\tSelectionNotify done!\n");
871 }
872
873
874 /***********************************************************************
875  *           EVENT_SelectionClear
876  */
877 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event )
878 {
879     if (event->selection != XA_PRIMARY) return;
880     CLIPBOARD_ReleaseSelection( event->window, pWnd->hwndSelf ); 
881 }
882
883
884 /**********************************************************************
885  *           EVENT_ClientMessage
886  */
887 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event )
888 {
889     static Atom wmProtocols = None;
890     static Atom wmDeleteWindow = None;
891
892     if (wmProtocols == None)
893         wmProtocols = XInternAtom( display, "WM_PROTOCOLS", True );
894     if (wmDeleteWindow == None)
895         wmDeleteWindow = XInternAtom( display, "WM_DELETE_WINDOW", True );
896
897     if ((event->format != 32) || (event->message_type != wmProtocols) ||
898         (((Atom) event->data.l[0]) != wmDeleteWindow))
899     {
900         dprintf_event( stddeb, "unrecognized ClientMessage\n" );
901         return;
902     }
903     SendMessage16( pWnd->hwndSelf, WM_SYSCOMMAND, SC_CLOSE, 0 );
904 }
905
906 /**********************************************************************
907  *           EVENT_EnterNotify
908  *
909  * Install colormap when Wine window is focused in
910  * self-managed mode with private colormap
911  */
912 /*
913   void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
914   {
915    if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
916      (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
917       XInstallColormap( display, COLOR_GetColormap() );
918   }
919  */ 
920
921 extern void FOCUS_SetXFocus( HWND32 );
922
923 /**********************************************************************
924  *              EVENT_MapNotify
925  */
926 void EVENT_MapNotify( HWND hWnd, XMapEvent *event )
927 {
928     HWND32 hwndFocus = GetFocus32();
929
930     if (hwndFocus && IsChild( hWnd, hwndFocus ))
931       FOCUS_SetXFocus( (HWND32)hwndFocus );
932
933     return;
934 }
935
936
937 /**********************************************************************
938  *              SetCapture16   (USER.18)
939  */
940 HWND16 SetCapture16( HWND16 hwnd )
941 {
942     return (HWND16)SetCapture32( hwnd );
943 }
944
945
946 /**********************************************************************
947  *              SetCapture32   (USER32.463)
948  */
949 HWND32 SetCapture32( HWND32 hwnd )
950 {
951     Window win;
952     HWND32 old_capture_wnd = captureWnd;
953
954     if (!hwnd)
955     {
956         ReleaseCapture();
957         return old_capture_wnd;
958     }
959     if (!(win = WIN_GetXWindow( hwnd ))) return 0;
960     if (XGrabPointer(display, win, False, 
961                      ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
962                      GrabModeAsync, GrabModeAsync,
963                      None, None, CurrentTime ) == GrabSuccess)
964     {
965         dprintf_win(stddeb, "SetCapture: %04x\n", hwnd);
966         captureWnd   = hwnd;
967         return old_capture_wnd;
968     }
969     else return 0;
970 }
971
972
973 /**********************************************************************
974  *              ReleaseCapture   (USER.19) (USER32.438)
975  */
976 void ReleaseCapture(void)
977 {
978     if (captureWnd == 0) return;
979     XUngrabPointer( display, CurrentTime );
980     captureWnd = 0;
981     dprintf_win(stddeb, "ReleaseCapture\n");
982 }
983
984
985 /**********************************************************************
986  *              GetCapture16   (USER.236)
987  */
988 HWND16 GetCapture16(void)
989 {
990     return (HWND16)captureWnd;
991 }
992
993
994 /**********************************************************************
995  *              GetCapture32   (USER32.207)
996  */
997 HWND32 GetCapture32(void)
998 {
999     return captureWnd;
1000 }
1001
1002
1003 /***********************************************************************
1004  *           GetMouseEventProc   (USER.337)
1005  */
1006 FARPROC16 GetMouseEventProc(void)
1007 {
1008     HMODULE16 hmodule = GetModuleHandle("USER");
1009     return MODULE_GetEntryPoint( hmodule,
1010                                  MODULE_GetOrdinal( hmodule, "Mouse_Event" ) );
1011 }
1012
1013
1014 /***********************************************************************
1015  *           Mouse_Event   (USER.299)
1016  */
1017 #ifndef WINELIB
1018 void Mouse_Event( SIGCONTEXT *context )
1019 {
1020     /* Register values:
1021      * AX = mouse event
1022      * BX = horizontal displacement if AX & ME_MOVE
1023      * CX = vertical displacement if AX & ME_MOVE
1024      * DX = button state (?)
1025      * SI = mouse event flags (?)
1026      */
1027     Window root, child;
1028     int rootX, rootY, childX, childY;
1029     unsigned int state;
1030
1031     if (AX_reg(context) & ME_MOVE)
1032     {
1033         /* We have to actually move the cursor */
1034         XWarpPointer( display, rootWindow, None, 0, 0, 0, 0,
1035                       (short)BX_reg(context), (short)CX_reg(context) );
1036         return;
1037     }
1038     if (!XQueryPointer( display, rootWindow, &root, &child,
1039                         &rootX, &rootY, &childX, &childY, &state )) return;
1040     if (AX_reg(context) & ME_LDOWN)
1041         hardware_event( WM_LBUTTONDOWN, EVENT_XStateToKeyState( state ), 0L,
1042                         rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
1043     if (AX_reg(context) & ME_LUP)
1044         hardware_event( WM_LBUTTONUP, EVENT_XStateToKeyState( state ), 0L,
1045                         rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
1046     if (AX_reg(context) & ME_RDOWN)
1047         hardware_event( WM_RBUTTONDOWN, EVENT_XStateToKeyState( state ), 0L,
1048                         rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
1049     if (AX_reg(context) & ME_RUP)
1050         hardware_event( WM_RBUTTONUP, EVENT_XStateToKeyState( state ), 0L,
1051                         rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
1052 }
1053 #endif
1054
1055
1056 /**********************************************************************
1057  *                      EnableHardwareInput   (USER.331)
1058  */
1059 BOOL16 EnableHardwareInput(BOOL16 bEnable)
1060 {
1061   BOOL16 bOldState = InputEnabled;
1062   dprintf_event(stdnimp,"EnableHardwareInput(%d);\n", bEnable);
1063   InputEnabled = bEnable;
1064   return bOldState;
1065 }
1066