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