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