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