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