Release 961208
[wine/multimedia.git] / windows / event.c
blob1143c449fb7e840f34efb6bb389f4a2c317143f4
1 /*
2 * X events handling functions
3 *
4 * Copyright 1993 Alexandre Julliard
5 *
6 */
8 #include <ctype.h>
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <sys/time.h>
14 #include <sys/types.h>
15 #include <errno.h>
16 #include <X11/keysym.h>
17 #include <X11/Xlib.h>
18 #include <X11/Xresource.h>
19 #include <X11/Xutil.h>
20 #include <X11/Xatom.h>
22 #include "windows.h"
23 #include "gdi.h"
24 #include "heap.h"
25 #include "queue.h"
26 #include "win.h"
27 #include "class.h"
28 #include "clipboard.h"
29 #include "debugger.h"
30 #include "message.h"
31 #include "module.h"
32 #include "options.h"
33 #include "queue.h"
34 #include "winpos.h"
35 #include "drive.h"
36 #include "dos_fs.h"
37 #include "shell.h"
38 #include "registers.h"
39 #include "xmalloc.h"
40 #include "keyboard.h"
41 #include "stddebug.h"
42 #include "debug.h"
43 #include "dde_proc.h"
46 #define NB_BUTTONS 3 /* Windows can handle 3 buttons */
48 #define DndNotDnd -1 /* OffiX drag&drop */
49 #define DndUnknown 0
50 #define DndRawData 1
51 #define DndFile 2
52 #define DndFiles 3
53 #define DndText 4
54 #define DndDir 5
55 #define DndLink 6
56 #define DndExe 7
58 #define DndEND 8
60 /* X context to associate a hwnd to an X window */
61 static XContext winContext = 0;
63 /* State variables */
64 BOOL MouseButtonsStates[NB_BUTTONS];
65 BOOL AsyncMouseButtonsStates[NB_BUTTONS];
66 BYTE InputKeyStateTable[256];
69 static HWND32 captureWnd = 0;
70 static BOOL32 InputEnabled = TRUE;
72 /* Keyboard translation tables */
73 static const int special_key[] =
75 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
76 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
77 0, 0, 0, VK_ESCAPE /* FF18 */
80 static const int cursor_key[] =
82 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_PRIOR,
83 VK_NEXT, VK_END /* FF50 */
86 static const int misc_key[] =
88 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
89 VK_CANCEL, VK_HELP, VK_CANCEL, VK_MENU /* FF68 */
92 static const int keypad_key[] =
94 VK_MENU, VK_NUMLOCK, /* FF7E */
95 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
96 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
97 0, 0, 0, 0, 0, 0, 0, 0, /* FF90 */
98 0, 0, 0, 0, 0, 0, 0, 0, /* FF98 */
99 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
100 0, 0, VK_MULTIPLY, VK_ADD, VK_SEPARATOR, VK_SUBTRACT,
101 VK_DECIMAL, VK_DIVIDE, /* FFA8 */
102 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4,
103 VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, /* FFB0 */
104 VK_NUMPAD8, VK_NUMPAD9 /* FFB8 */
107 static const int function_key[] =
109 VK_F1, VK_F2, /* FFBE */
110 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
111 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16 /* FFC8 */
114 static const int modifier_key[] =
116 VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL, VK_CAPITAL,
117 0, 0, /* FFE1 */
118 0, VK_MENU, VK_MENU /* FFE8 */
121 typedef union
123 struct
125 unsigned long count : 16;
126 unsigned long code : 8;
127 unsigned long extended : 1;
128 unsigned long unused : 2;
129 unsigned long win_internal : 2;
130 unsigned long context : 1;
131 unsigned long previous : 1;
132 unsigned long transition : 1;
133 } lp1;
134 unsigned long lp2;
135 } KEYLP;
137 static BOOL KeyDown = FALSE;
139 static Atom wmProtocols = None;
140 static Atom wmDeleteWindow = None;
141 static Atom dndProtocol = None;
142 static Atom dndSelection = None;
144 static const char * const event_names[] =
146 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
147 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
148 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
149 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
150 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
151 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
152 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
153 "ClientMessage", "MappingNotify"
156 /* Event handlers */
157 static void EVENT_key( XKeyEvent *event );
158 static void EVENT_ButtonPress( XButtonEvent *event );
159 static void EVENT_ButtonRelease( XButtonEvent *event );
160 static void EVENT_MotionNotify( XMotionEvent *event );
161 static void EVENT_FocusIn( HWND hwnd, XFocusChangeEvent *event );
162 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event );
163 static void EVENT_Expose( WND *pWnd, XExposeEvent *event );
164 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event );
165 static void EVENT_ConfigureNotify( HWND hwnd, XConfigureEvent *event );
166 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event);
167 static void EVENT_SelectionNotify( XSelectionEvent *event);
168 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event);
169 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event );
170 static void EVENT_MapNotify( HWND hwnd, XMapEvent *event );
172 /* Usable only with OLVWM - compile option perhaps?
173 static void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event );
176 extern void FOCUS_SetXFocus( HWND32 );
177 extern BOOL16 DRAG_QueryUpdate( HWND, SEGPTR, BOOL32 );
179 /***********************************************************************
180 * EVENT_ProcessEvent
182 * Process an X event.
184 void EVENT_ProcessEvent( XEvent *event )
186 WND *pWnd;
188 if (XFindContext( display, event->xany.window, winContext,
189 (char **)&pWnd ) != 0)
190 return; /* Not for a registered window */
192 dprintf_event( stddeb, "Got event %s for hwnd %04x\n",
193 event_names[event->type], pWnd->hwndSelf );
195 switch(event->type)
197 case KeyPress:
198 case KeyRelease:
199 if (InputEnabled)
200 EVENT_key( (XKeyEvent*)event );
201 break;
203 case ButtonPress:
204 if (InputEnabled)
205 EVENT_ButtonPress( (XButtonEvent*)event );
206 break;
208 case ButtonRelease:
209 if (InputEnabled)
210 EVENT_ButtonRelease( (XButtonEvent*)event );
211 break;
213 case MotionNotify:
214 /* Wine between two fast machines across the overloaded campus
215 ethernet gets very boged down in MotionEvents. The following
216 simply finds the last motion event in the queue and drops
217 the rest. On a good link events are servered before they build
218 up so this doesn't take place. On a slow link this may cause
219 problems if the event order is important. I'm not yet seen
220 of any problems. Jon 7/6/96.
222 if (InputEnabled)
224 while (XCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
225 MotionNotify, event));
226 EVENT_MotionNotify( (XMotionEvent*)event );
228 break;
230 case FocusIn:
231 EVENT_FocusIn( pWnd->hwndSelf, (XFocusChangeEvent*)event );
232 break;
234 case FocusOut:
235 EVENT_FocusOut( pWnd->hwndSelf, (XFocusChangeEvent*)event );
236 break;
238 case Expose:
239 EVENT_Expose( pWnd, (XExposeEvent *)event );
240 break;
242 case GraphicsExpose:
243 EVENT_GraphicsExpose( pWnd, (XGraphicsExposeEvent *)event );
244 break;
246 case ConfigureNotify:
247 EVENT_ConfigureNotify( pWnd->hwndSelf, (XConfigureEvent*)event );
248 break;
250 case SelectionRequest:
251 EVENT_SelectionRequest( pWnd, (XSelectionRequestEvent *)event );
252 break;
254 case SelectionNotify:
255 EVENT_SelectionNotify( (XSelectionEvent *)event );
256 break;
258 case SelectionClear:
259 EVENT_SelectionClear( pWnd, (XSelectionClearEvent*) event );
260 break;
262 case ClientMessage:
263 EVENT_ClientMessage( pWnd, (XClientMessageEvent *) event );
264 break;
266 /* case EnterNotify:
267 * EVENT_EnterNotify( pWnd, (XCrossingEvent *) event );
268 * break;
270 case NoExpose:
271 break;
273 /* We get all these because of StructureNotifyMask. */
274 case UnmapNotify:
275 case CirculateNotify:
276 case CreateNotify:
277 case DestroyNotify:
278 case GravityNotify:
279 case ReparentNotify:
280 break;
282 case MapNotify:
283 EVENT_MapNotify( pWnd->hwndSelf, (XMapEvent *)event );
284 break;
286 default:
287 dprintf_event(stddeb, "Unprocessed event %s for hwnd %04x\n",
288 event_names[event->type], pWnd->hwndSelf );
289 break;
294 /***********************************************************************
295 * EVENT_RegisterWindow
297 * Associate an X window to a HWND.
299 void EVENT_RegisterWindow( WND *pWnd )
301 if (wmProtocols == None)
302 wmProtocols = XInternAtom( display, "WM_PROTOCOLS", True );
303 if (wmDeleteWindow == None)
304 wmDeleteWindow = XInternAtom( display, "WM_DELETE_WINDOW", True );
305 if( dndProtocol == None )
306 dndProtocol = XInternAtom( display, "DndProtocol" , False );
307 if( dndSelection == None )
308 dndSelection = XInternAtom( display, "DndSelection" , False );
310 XSetWMProtocols( display, pWnd->window, &wmDeleteWindow, 1 );
312 if (!winContext) winContext = XUniqueContext();
313 XSaveContext( display, pWnd->window, winContext, (char *)pWnd );
317 /***********************************************************************
318 * EVENT_WaitXEvent
320 * Wait for an X event, optionally sleeping until one arrives.
321 * Return TRUE if an event is pending, FALSE on timeout or error
322 * (for instance lost connection with the server).
324 BOOL32 EVENT_WaitXEvent( BOOL32 sleep, BOOL32 peek )
326 XEvent event;
327 LONG maxWait = sleep ? TIMER_GetNextExpiration() : 0;
329 /* Wait for an event or a timeout. If maxWait is -1, we have no timeout;
330 * in this case, we fall through directly to the XNextEvent loop.
333 if ((maxWait != -1) && !XPending(display))
335 fd_set read_set;
336 struct timeval timeout;
337 int fd = ConnectionNumber(display);
339 FD_ZERO( &read_set );
340 FD_SET( fd, &read_set );
342 timeout.tv_usec = (maxWait % 1000) * 1000;
343 timeout.tv_sec = maxWait / 1000;
345 #ifdef CONFIG_IPC
346 sigsetjmp(env_wait_x, 1);
347 stop_wait_op= CONT;
349 if (DDE_GetRemoteMessage()) {
350 while(DDE_GetRemoteMessage())
352 return TRUE;
354 stop_wait_op = STOP_WAIT_X;
355 /* The code up to the next "stop_wait_op = CONT" must be reentrant */
356 if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1 &&
357 !XPending(display))
359 stop_wait_op = CONT;
360 TIMER_ExpireTimers();
361 return FALSE;
363 else stop_wait_op = CONT;
364 #else /* CONFIG_IPC */
365 if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1)
367 /* Timeout or error */
368 TIMER_ExpireTimers();
369 return FALSE;
371 #endif /* CONFIG_IPC */
375 /* Process the event (and possibly others that occurred in the meantime) */
380 #ifdef CONFIG_IPC
381 if (DDE_GetRemoteMessage())
383 while(DDE_GetRemoteMessage()) ;
384 return TRUE;
386 #endif /* CONFIG_IPC */
388 XNextEvent( display, &event );
390 if( peek )
392 WND* pWnd;
393 MESSAGEQUEUE* pQ;
395 if( XFindContext( display, ((XAnyEvent *)&event)->window, winContext, (char **)&pWnd)
396 || event.type == NoExpose )
397 continue;
399 /* check for the "safe" hardware events */
401 if( event.type == MotionNotify ||
402 event.type == ButtonPress || event.type == ButtonRelease ||
403 event.type == KeyPress || event.type == KeyRelease ||
404 event.type == SelectionRequest || event.type == SelectionClear )
406 EVENT_ProcessEvent( &event );
407 continue;
410 if( pWnd )
411 if( (pQ = (MESSAGEQUEUE*)GlobalLock16(pWnd->hmemTaskQ)) )
413 pQ->flags |= QUEUE_FLAG_XEVENT;
414 PostEvent(pQ->hTask);
415 XPutBackEvent(display, &event);
416 break;
419 else
420 EVENT_ProcessEvent( &event );
422 while (XPending( display ));
423 return TRUE;
427 /***********************************************************************
428 * EVENT_Synchronize
430 * Synchronize with the X server. Should not be used too often.
432 void EVENT_Synchronize()
434 XEvent event;
436 XSync( display, False );
437 while (XPending( display ))
439 XNextEvent( display, &event );
440 EVENT_ProcessEvent( &event );
445 /***********************************************************************
446 * EVENT_XStateToKeyState
448 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
449 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
451 static WORD EVENT_XStateToKeyState( int state )
453 int kstate = 0;
455 if (state & Button1Mask) kstate |= MK_LBUTTON;
456 if (state & Button2Mask) kstate |= MK_MBUTTON;
457 if (state & Button3Mask) kstate |= MK_RBUTTON;
458 if (state & ShiftMask) kstate |= MK_SHIFT;
459 if (state & ControlMask) kstate |= MK_CONTROL;
460 return kstate;
464 /***********************************************************************
465 * EVENT_Expose
467 static void EVENT_Expose( WND *pWnd, XExposeEvent *event )
469 RECT32 rect;
471 /* Make position relative to client area instead of window */
472 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
473 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
474 rect.right = rect.left + event->width;
475 rect.bottom = rect.top + event->height;
477 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
478 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
479 (event->count ? 0 : RDW_ERASENOW), 0 );
483 /***********************************************************************
484 * EVENT_GraphicsExpose
486 * This is needed when scrolling area is partially obscured
487 * by non-Wine X window.
489 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event )
491 RECT32 rect;
493 /* Make position relative to client area instead of window */
494 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
495 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
496 rect.right = rect.left + event->width;
497 rect.bottom = rect.top + event->height;
499 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
500 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
501 (event->count ? 0 : RDW_ERASENOW), 0 );
505 /***********************************************************************
506 * EVENT_key
508 * Handle a X key event
510 static void EVENT_key( XKeyEvent *event )
512 char Str[24];
513 XComposeStatus cs;
514 KeySym keysym;
515 WORD vkey = 0;
516 WORD xkey, key_type, key;
517 KEYLP keylp;
518 BOOL extended = FALSE;
520 int ascii_chars = XLookupString(event, Str, 1, &keysym, &cs);
522 Str[ascii_chars] = '\0';
523 if (debugging_key)
525 char *ksname;
527 ksname = XKeysymToString(keysym);
528 if (!ksname)
529 ksname = "No Name";
530 fprintf(stddeb, "WM_KEY??? : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
531 keysym, ksname, ascii_chars, Str[0], Str);
534 /* Ctrl-Alt-Return enters the debugger */
535 if ((keysym == XK_Return) && (event->type == KeyPress) &&
536 (event->state & ControlMask) && (event->state & Mod1Mask))
537 DEBUG_EnterDebugger();
539 xkey = LOWORD(keysym);
540 key_type = HIBYTE(xkey);
541 key = LOBYTE(xkey);
542 dprintf_key(stddeb," key_type=%X, key=%X\n", key_type, key);
544 if (key_type == 0xFF) /* non-character key */
546 if (key >= 0x08 && key <= 0x1B) /* special key */
547 vkey = special_key[key - 0x08];
548 else if (key >= 0x50 && key <= 0x57) /* cursor key */
549 vkey = cursor_key[key - 0x50];
550 else if (key >= 0x60 && key <= 0x6B) /* miscellaneous key */
551 vkey = misc_key[key - 0x60];
552 else if (key >= 0x7E && key <= 0xB9) /* keypad key */
554 vkey = keypad_key[key - 0x7E];
555 extended = TRUE;
557 else if (key >= 0xBE && key <= 0xCD) /* function key */
559 vkey = function_key[key - 0xBE];
560 extended = TRUE;
562 else if (key >= 0xE1 && key <= 0xEA) /* modifier key */
563 vkey = modifier_key[key - 0xE1];
564 else if (key == 0xFF) /* DEL key */
565 vkey = VK_DELETE;
566 /* extended must also be set for ALT_R, CTRL_R,
567 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
568 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
569 switch (keysym)
571 case XK_Control_R :
572 case XK_Alt_R :
573 case XK_Insert :
574 case XK_Delete :
575 case XK_Home :
576 case XK_End :
577 case XK_Page_Up :
578 case XK_Page_Down :
579 case XK_Left :
580 case XK_Up :
581 case XK_Right :
582 case XK_Down :
583 case XK_KP_Divide :
584 case XK_KP_Enter :
585 extended = 1;
588 else if (key_type == 0) /* character key */
590 if ( isalnum(key) )
591 vkey = toupper(key); /* convert lc to uc */
592 else if ( isspace(key) )
593 vkey = key; /* XXX approximately */
594 else
595 switch (key) /* the rest... */
597 #define vkcase(k,val) case k: vkey = val; break;
598 #define vkcase2(k1,k2,val) case k1: case k2: vkey = val; break;
599 WINE_VKEY_MAPPINGS
600 #undef vkcase
601 #undef vkcase2
602 default:
603 fprintf( stderr, "Unknown key! Please report!\n" );
604 vkey = 0; /* whatever */
608 if (event->type == KeyPress)
610 if (!(InputKeyStateTable[vkey] & 0x80))
611 InputKeyStateTable[vkey] ^= 0x01;
612 InputKeyStateTable[vkey] |= 0x80;
613 keylp.lp1.count = 1;
614 keylp.lp1.code = LOBYTE(event->keycode) - 8;
615 keylp.lp1.extended = (extended ? 1 : 0);
616 keylp.lp1.win_internal = 0;
617 keylp.lp1.context = ( (event->state & Mod1Mask) ||
618 (InputKeyStateTable[VK_MENU] & 0x80)) ? 1 : 0;
619 keylp.lp1.previous = (KeyDown ? 0 : 1);
620 keylp.lp1.transition = 0;
621 dprintf_key(stddeb," wParam=%X, lParam=%lX\n",
622 vkey, keylp.lp2 );
623 dprintf_key(stddeb," InputKeyState=%X\n", InputKeyStateTable[vkey]);
624 hardware_event( InputKeyStateTable[VK_MENU] & 0x80 ? WM_SYSKEYDOWN : WM_KEYDOWN,
625 vkey, keylp.lp2,
626 event->x_root - desktopX, event->y_root - desktopY,
627 event->time - MSG_WineStartTicks, 0 );
628 KeyDown = TRUE;
630 else
632 UINT sysKey = InputKeyStateTable[VK_MENU];
634 InputKeyStateTable[vkey] &= ~0x80;
635 keylp.lp1.count = 1;
636 keylp.lp1.code = LOBYTE(event->keycode) - 8;
637 keylp.lp1.extended = (extended ? 1 : 0);
638 keylp.lp1.win_internal = 0;
639 keylp.lp1.context = (event->state & Mod1Mask ? 1 : 0);
640 keylp.lp1.previous = 1;
641 keylp.lp1.transition = 1;
642 dprintf_key(stddeb," wParam=%X, lParam=%lX\n",
643 vkey, keylp.lp2 );
644 dprintf_key(stddeb," InputKeyState=%X\n", InputKeyStateTable[vkey]);
645 hardware_event( sysKey & 0x80 ? WM_SYSKEYUP : WM_KEYUP,
646 vkey, keylp.lp2,
647 event->x_root - desktopX, event->y_root - desktopY,
648 event->time - MSG_WineStartTicks, 0 );
649 KeyDown = FALSE;
654 /***********************************************************************
655 * EVENT_MotionNotify
657 static void EVENT_MotionNotify( XMotionEvent *event )
659 hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ), 0L,
660 event->x_root - desktopX, event->y_root - desktopY,
661 event->time - MSG_WineStartTicks, 0 );
665 /***********************************************************************
666 * EVENT_DummyMotionNotify
668 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
670 void EVENT_DummyMotionNotify(void)
672 Window root, child;
673 int rootX, rootY, childX, childY;
674 unsigned int state;
676 if (XQueryPointer( display, rootWindow, &root, &child,
677 &rootX, &rootY, &childX, &childY, &state ))
679 hardware_event(WM_MOUSEMOVE, EVENT_XStateToKeyState( state ), 0L,
680 rootX - desktopX, rootY - desktopY, GetTickCount(), 0 );
685 /***********************************************************************
686 * EVENT_ButtonPress
688 static void EVENT_ButtonPress( XButtonEvent *event )
690 static WORD messages[NB_BUTTONS] =
691 { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
692 int buttonNum = event->button - 1;
694 if (buttonNum >= NB_BUTTONS) return;
695 MouseButtonsStates[buttonNum] = 0x8000;
696 AsyncMouseButtonsStates[buttonNum] = 0x8000;
697 hardware_event( messages[buttonNum],
698 EVENT_XStateToKeyState( event->state ), 0L,
699 event->x_root - desktopX, event->y_root - desktopY,
700 event->time - MSG_WineStartTicks, 0 );
704 /***********************************************************************
705 * EVENT_ButtonRelease
707 static void EVENT_ButtonRelease( XButtonEvent *event )
709 static const WORD messages[NB_BUTTONS] =
710 { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
711 int buttonNum = event->button - 1;
713 if (buttonNum >= NB_BUTTONS) return;
714 MouseButtonsStates[buttonNum] = FALSE;
715 hardware_event( messages[buttonNum],
716 EVENT_XStateToKeyState( event->state ), 0L,
717 event->x_root - desktopX, event->y_root - desktopY,
718 event->time - MSG_WineStartTicks, 0 );
722 /**********************************************************************
723 * EVENT_FocusIn
725 static void EVENT_FocusIn (HWND hwnd, XFocusChangeEvent *event )
727 if (event->detail == NotifyPointer) return;
728 if (hwnd != GetActiveWindow()) WINPOS_ChangeActiveWindow( hwnd, FALSE );
729 if ((hwnd != GetFocus32()) && !IsChild( hwnd, GetFocus32()))
730 SetFocus32( hwnd );
734 /**********************************************************************
735 * EVENT_FocusOut
737 * Note: only top-level override-redirect windows get FocusOut events.
739 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event )
741 if (event->detail == NotifyPointer) return;
742 if (hwnd == GetActiveWindow()) WINPOS_ChangeActiveWindow( 0, FALSE );
743 if ((hwnd == GetFocus32()) || IsChild( hwnd, GetFocus32()))
744 SetFocus32( 0 );
748 /**********************************************************************
749 * EVENT_ConfigureNotify
751 * The ConfigureNotify event is only selected on the desktop window
752 * and on top-level windows when the -managed flag is used.
754 static void EVENT_ConfigureNotify( HWND hwnd, XConfigureEvent *event )
756 /* FIXME: with -desktop xxx we get this event _before_ desktop
757 * window structure is created. WIN_GetDesktop() check is a hack.
760 if ( !WIN_GetDesktop() || hwnd == GetDesktopWindow32())
762 desktopX = event->x;
763 desktopY = event->y;
765 else
767 WND *wndPtr;
768 WINDOWPOS16 *winpos;
769 RECT16 newWindowRect, newClientRect;
770 HRGN32 hrgnOldPos, hrgnNewPos;
772 if (!(wndPtr = WIN_FindWndPtr( hwnd )) ||
773 !(wndPtr->flags & WIN_MANAGED) )
774 return;
776 if (!(winpos = SEGPTR_NEW(WINDOWPOS16))) return;
778 /* XTranslateCoordinates(display, event->window, rootWindow,
779 event->x, event->y, &event->x, &event->y, &child);
782 /* Fill WINDOWPOS struct */
783 winpos->flags = SWP_NOACTIVATE | SWP_NOZORDER;
784 winpos->hwnd = hwnd;
785 winpos->x = event->x;
786 winpos->y = event->y;
787 winpos->cx = event->width;
788 winpos->cy = event->height;
790 /* Check for unchanged attributes */
791 if(winpos->x == wndPtr->rectWindow.left &&
792 winpos->y == wndPtr->rectWindow.top)
793 winpos->flags |= SWP_NOMOVE;
794 if(winpos->cx == wndPtr->rectWindow.right - wndPtr->rectWindow.left &&
795 winpos->cy == wndPtr->rectWindow.bottom - wndPtr->rectWindow.top)
796 winpos->flags |= SWP_NOSIZE;
798 /* Send WM_WINDOWPOSCHANGING */
799 SendMessage16(hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)SEGPTR_GET(winpos));
801 /* Calculate new position and size */
802 newWindowRect.left = event->x;
803 newWindowRect.right = event->x + event->width;
804 newWindowRect.top = event->y;
805 newWindowRect.bottom = event->y + event->height;
807 WINPOS_SendNCCalcSize( winpos->hwnd, TRUE, &newWindowRect,
808 &wndPtr->rectWindow, &wndPtr->rectClient,
809 SEGPTR_GET(winpos), &newClientRect );
811 hrgnOldPos = CreateRectRgnIndirect16( &wndPtr->rectWindow );
812 hrgnNewPos = CreateRectRgnIndirect16( &newWindowRect );
813 CombineRgn32( hrgnOldPos, hrgnOldPos, hrgnNewPos, RGN_DIFF );
815 /* Set new size and position */
816 wndPtr->rectWindow = newWindowRect;
817 wndPtr->rectClient = newClientRect;
818 SendMessage16( hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)SEGPTR_GET(winpos));
819 SEGPTR_FREE(winpos);
821 /* full window drag leaves unrepainted garbage without this */
822 PAINT_RedrawWindow( 0, NULL, hrgnOldPos, RDW_INVALIDATE |
823 RDW_ALLCHILDREN | RDW_ERASE | RDW_ERASENOW,
824 RDW_C_USEHRGN );
825 DeleteObject32(hrgnOldPos);
826 DeleteObject32(hrgnNewPos);
831 /***********************************************************************
832 * EVENT_SelectionRequest
834 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event )
836 XSelectionEvent result;
837 Atom rprop = None;
838 Window request = event->requestor;
840 if(event->target == XA_STRING)
842 HANDLE16 hText;
843 LPSTR text;
844 int size,i,j;
846 rprop = event->property;
848 if(rprop == None) rprop = event->target;
850 if(event->selection!=XA_PRIMARY) rprop = None;
851 else if(!CLIPBOARD_IsPresent(CF_OEMTEXT)) rprop = None;
852 else
854 /* open to make sure that clipboard is available */
856 BOOL couldOpen = OpenClipboard( pWnd->hwndSelf );
857 char* lpstr = 0;
859 hText = GetClipboardData(CF_TEXT);
860 text = GlobalLock16(hText);
861 size = GlobalSize16(hText);
863 /* remove carriage returns */
865 lpstr = (char*)xmalloc(size--);
866 for(i=0,j=0; i < size && text[i]; i++ )
868 if( text[i] == '\r' &&
869 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
870 lpstr[j++] = text[i];
872 lpstr[j]='\0';
874 XChangeProperty(display, request, rprop,
875 XA_STRING, 8, PropModeReplace,
876 lpstr, j);
877 free(lpstr);
879 /* close only if we opened before */
881 if(couldOpen) CloseClipboard();
885 if(rprop==None)
886 dprintf_event(stddeb,"Request for %s ignored\n", XGetAtomName(display,event->target));
888 result.type=SelectionNotify;
889 result.display=display;
890 result.requestor=request;
891 result.selection=event->selection;
892 result.property=rprop;
893 result.target=event->target;
894 result.time=event->time;
895 XSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
899 /***********************************************************************
900 * EVENT_SelectionNotify
902 static void EVENT_SelectionNotify( XSelectionEvent *event )
904 if (event->selection != XA_PRIMARY) return;
906 if (event->target != XA_STRING) CLIPBOARD_ReadSelection( 0, None );
907 else CLIPBOARD_ReadSelection( event->requestor, event->property );
909 dprintf_clipboard(stddeb,"\tSelectionNotify done!\n");
913 /***********************************************************************
914 * EVENT_SelectionClear
916 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event )
918 if (event->selection != XA_PRIMARY) return;
919 CLIPBOARD_ReleaseSelection( event->window, pWnd->hwndSelf );
923 /**********************************************************************
924 * EVENT_ClientMessage
926 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event )
928 if (event->message_type != None && event->format == 32)
930 if ((event->message_type == wmProtocols) &&
931 (((Atom) event->data.l[0]) == wmDeleteWindow))
932 SendMessage16( pWnd->hwndSelf, WM_SYSCOMMAND, SC_CLOSE, 0 );
933 else if ( event->message_type == dndProtocol &&
934 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
936 unsigned long data_length;
937 unsigned long aux_long;
938 unsigned char* p_data = NULL;
939 union {
940 Atom atom_aux;
941 POINT32 pt_aux;
942 BOOL16 bAccept;
943 int i;
944 } u;
945 int x, y;
946 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
947 LPDRAGINFO lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
948 SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
949 Window w_aux_root, w_aux_child;
950 WND* pDropWnd;
952 if( !lpDragInfo || !spDragInfo ) return;
954 XQueryPointer( display, pWnd->window, &w_aux_root, &w_aux_child,
955 &x, &y, &u.pt_aux.x, &u.pt_aux.y, (unsigned int*)&aux_long);
957 lpDragInfo->hScope = pWnd->hwndSelf;
958 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
960 /* find out drop point and drop window */
961 if( x < 0 || y < 0 ||
962 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
963 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
964 { u.bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
965 else
967 u.bAccept = DRAG_QueryUpdate( pWnd->hwndSelf, spDragInfo, TRUE );
968 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
970 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
971 GlobalFree16( hDragInfo );
973 if( u.bAccept )
975 XGetWindowProperty( display, DefaultRootWindow(display),
976 dndSelection, 0, 65535, FALSE,
977 AnyPropertyType, &u.atom_aux, &u.pt_aux.y,
978 &data_length, &aux_long, &p_data);
980 if( !aux_long && p_data) /* don't bother if > 64K */
982 char* p = (char*) p_data;
983 char* p_filename,*p_drop;
985 aux_long = 0;
986 while( *p ) /* calculate buffer size */
988 p_drop = p;
989 if((u.i = *p) != -1 )
990 u.i = DRIVE_FindDriveRoot( (const char**)&p_drop );
991 if( u.i == -1 ) *p = -1; /* mark as "bad" */
992 else
994 p_filename = (char*) DOSFS_GetDosTrueName( (const char*)p, TRUE );
995 if( p_filename ) aux_long += strlen(p_filename) + 1;
996 else *p = -1;
998 p += strlen(p) + 1;
1000 if( aux_long && aux_long < 65535 )
1002 HDROP16 hDrop;
1003 LPDROPFILESTRUCT lpDrop;
1005 aux_long += sizeof(DROPFILESTRUCT) + 1;
1006 hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
1007 lpDrop = (LPDROPFILESTRUCT) GlobalLock16( hDrop );
1009 if( lpDrop )
1011 lpDrop->wSize = sizeof(DROPFILESTRUCT);
1012 lpDrop->ptMousePos.x = (INT16)x;
1013 lpDrop->ptMousePos.y = (INT16)y;
1014 lpDrop->fInNonClientArea = (BOOL16)
1015 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1016 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1017 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1018 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1019 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT);
1020 p = p_data;
1021 while(*p)
1023 if( *p != -1 ) /* use only "good" entries */
1025 p_filename = (char*) DOSFS_GetDosTrueName( p, TRUE );
1026 strcpy(p_drop, p_filename);
1027 p_drop += strlen( p_filename ) + 1;
1029 p += strlen(p) + 1;
1031 *p_drop = '\0';
1032 PostMessage( pWnd->hwndSelf, WM_DROPFILES, (WPARAM16)hDrop, 0L );
1036 if( p_data ) XFree(p_data);
1038 } /* WS_EX_ACCEPTFILES */
1039 } /* dndProtocol */
1040 else
1041 dprintf_event( stddeb, "unrecognized ClientMessage\n" );
1045 /**********************************************************************
1046 * EVENT_EnterNotify
1048 * Install colormap when Wine window is focused in
1049 * self-managed mode with private colormap
1052 void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
1054 if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
1055 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
1056 XInstallColormap( display, COLOR_GetColormap() );
1060 /**********************************************************************
1061 * EVENT_MapNotify
1063 void EVENT_MapNotify( HWND hWnd, XMapEvent *event )
1065 HWND32 hwndFocus = GetFocus32();
1067 if (hwndFocus && IsChild( hWnd, hwndFocus ))
1068 FOCUS_SetXFocus( (HWND32)hwndFocus );
1070 return;
1074 /**********************************************************************
1075 * SetCapture16 (USER.18)
1077 HWND16 SetCapture16( HWND16 hwnd )
1079 return (HWND16)SetCapture32( hwnd );
1083 /**********************************************************************
1084 * SetCapture32 (USER32.463)
1086 HWND32 SetCapture32( HWND32 hwnd )
1088 Window win;
1089 HWND32 old_capture_wnd = captureWnd;
1091 if (!hwnd)
1093 ReleaseCapture();
1094 return old_capture_wnd;
1096 if (!(win = WIN_GetXWindow( hwnd ))) return 0;
1097 if (XGrabPointer(display, win, False,
1098 ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
1099 GrabModeAsync, GrabModeAsync,
1100 None, None, CurrentTime ) == GrabSuccess)
1102 dprintf_win(stddeb, "SetCapture: %04x\n", hwnd);
1103 captureWnd = hwnd;
1104 return old_capture_wnd;
1106 else return 0;
1110 /**********************************************************************
1111 * ReleaseCapture (USER.19) (USER32.438)
1113 void ReleaseCapture(void)
1115 if (captureWnd == 0) return;
1116 XUngrabPointer( display, CurrentTime );
1117 captureWnd = 0;
1118 dprintf_win(stddeb, "ReleaseCapture\n");
1122 /**********************************************************************
1123 * GetCapture16 (USER.236)
1125 HWND16 GetCapture16(void)
1127 return (HWND16)captureWnd;
1131 /**********************************************************************
1132 * GetCapture32 (USER32.207)
1134 HWND32 GetCapture32(void)
1136 return captureWnd;
1140 /***********************************************************************
1141 * GetMouseEventProc (USER.337)
1143 FARPROC16 GetMouseEventProc(void)
1145 HMODULE16 hmodule = GetModuleHandle("USER");
1146 return MODULE_GetEntryPoint( hmodule,
1147 MODULE_GetOrdinal( hmodule, "Mouse_Event" ) );
1151 /***********************************************************************
1152 * Mouse_Event (USER.299)
1154 #ifndef WINELIB
1155 void Mouse_Event( SIGCONTEXT *context )
1157 /* Register values:
1158 * AX = mouse event
1159 * BX = horizontal displacement if AX & ME_MOVE
1160 * CX = vertical displacement if AX & ME_MOVE
1161 * DX = button state (?)
1162 * SI = mouse event flags (?)
1164 Window root, child;
1165 int rootX, rootY, childX, childY;
1166 unsigned int state;
1168 if (AX_reg(context) & ME_MOVE)
1170 /* We have to actually move the cursor */
1171 XWarpPointer( display, rootWindow, None, 0, 0, 0, 0,
1172 (short)BX_reg(context), (short)CX_reg(context) );
1173 return;
1175 if (!XQueryPointer( display, rootWindow, &root, &child,
1176 &rootX, &rootY, &childX, &childY, &state )) return;
1177 if (AX_reg(context) & ME_LDOWN)
1178 hardware_event( WM_LBUTTONDOWN, EVENT_XStateToKeyState( state ), 0L,
1179 rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
1180 if (AX_reg(context) & ME_LUP)
1181 hardware_event( WM_LBUTTONUP, EVENT_XStateToKeyState( state ), 0L,
1182 rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
1183 if (AX_reg(context) & ME_RDOWN)
1184 hardware_event( WM_RBUTTONDOWN, EVENT_XStateToKeyState( state ), 0L,
1185 rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
1186 if (AX_reg(context) & ME_RUP)
1187 hardware_event( WM_RBUTTONUP, EVENT_XStateToKeyState( state ), 0L,
1188 rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
1190 #endif
1193 /**********************************************************************
1194 * EnableHardwareInput (USER.331)
1196 BOOL16 EnableHardwareInput(BOOL16 bEnable)
1198 BOOL16 bOldState = InputEnabled;
1199 dprintf_event(stdnimp,"EnableHardwareInput(%d);\n", bEnable);
1200 InputEnabled = bEnable;
1201 return bOldState;