Release 961222
[wine/multimedia.git] / windows / event.c
blobd01c38bc3a79c33756bb0f432ab1f2756b96051f
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 );
316 /***********************************************************************
317 * EVENT_DestroyWindow
319 void EVENT_DestroyWindow( WND *pWnd )
321 XEvent xe;
323 XDeleteContext( display, pWnd->window, winContext );
324 XDestroyWindow( display, pWnd->window );
325 while( XCheckWindowEvent(display, pWnd->window, NoEventMask, &xe) );
328 /***********************************************************************
329 * EVENT_WaitXEvent
331 * Wait for an X event, optionally sleeping until one arrives.
332 * Return TRUE if an event is pending, FALSE on timeout or error
333 * (for instance lost connection with the server).
335 BOOL32 EVENT_WaitXEvent( BOOL32 sleep, BOOL32 peek )
337 XEvent event;
338 LONG maxWait = sleep ? TIMER_GetNextExpiration() : 0;
340 /* Wait for an event or a timeout. If maxWait is -1, we have no timeout;
341 * in this case, we fall through directly to the XNextEvent loop.
344 if ((maxWait != -1) && !XPending(display))
346 fd_set read_set;
347 struct timeval timeout;
348 int fd = ConnectionNumber(display);
350 FD_ZERO( &read_set );
351 FD_SET( fd, &read_set );
353 timeout.tv_usec = (maxWait % 1000) * 1000;
354 timeout.tv_sec = maxWait / 1000;
356 #ifdef CONFIG_IPC
357 sigsetjmp(env_wait_x, 1);
358 stop_wait_op= CONT;
360 if (DDE_GetRemoteMessage()) {
361 while(DDE_GetRemoteMessage())
363 return TRUE;
365 stop_wait_op = STOP_WAIT_X;
366 /* The code up to the next "stop_wait_op = CONT" must be reentrant */
367 if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1 &&
368 !XPending(display))
370 stop_wait_op = CONT;
371 TIMER_ExpireTimers();
372 return FALSE;
374 else stop_wait_op = CONT;
375 #else /* CONFIG_IPC */
376 if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1)
378 /* Timeout or error */
379 TIMER_ExpireTimers();
380 return FALSE;
382 #endif /* CONFIG_IPC */
386 /* Process the event (and possibly others that occurred in the meantime) */
391 #ifdef CONFIG_IPC
392 if (DDE_GetRemoteMessage())
394 while(DDE_GetRemoteMessage()) ;
395 return TRUE;
397 #endif /* CONFIG_IPC */
399 XNextEvent( display, &event );
401 if( peek )
403 WND* pWnd;
404 MESSAGEQUEUE* pQ;
406 if (XFindContext( display, ((XAnyEvent *)&event)->window, winContext,
407 (char **)&pWnd ) || (event.type == NoExpose))
408 continue;
410 /* check for the "safe" hardware events */
412 if( event.type == MotionNotify ||
413 event.type == ButtonPress || event.type == ButtonRelease ||
414 event.type == KeyPress || event.type == KeyRelease ||
415 event.type == SelectionRequest || event.type == SelectionClear )
417 EVENT_ProcessEvent( &event );
418 continue;
421 if( pWnd )
422 if( (pQ = (MESSAGEQUEUE*)GlobalLock16(pWnd->hmemTaskQ)) )
424 pQ->flags |= QUEUE_FLAG_XEVENT;
425 PostEvent(pQ->hTask);
426 XPutBackEvent(display, &event);
427 break;
430 else
431 EVENT_ProcessEvent( &event );
433 while (XPending( display ));
434 return TRUE;
438 /***********************************************************************
439 * EVENT_Synchronize
441 * Synchronize with the X server. Should not be used too often.
443 void EVENT_Synchronize()
445 XEvent event;
447 XSync( display, False );
448 while (XPending( display ))
450 XNextEvent( display, &event );
451 EVENT_ProcessEvent( &event );
456 /***********************************************************************
457 * EVENT_XStateToKeyState
459 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
460 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
462 static WORD EVENT_XStateToKeyState( int state )
464 int kstate = 0;
466 if (state & Button1Mask) kstate |= MK_LBUTTON;
467 if (state & Button2Mask) kstate |= MK_MBUTTON;
468 if (state & Button3Mask) kstate |= MK_RBUTTON;
469 if (state & ShiftMask) kstate |= MK_SHIFT;
470 if (state & ControlMask) kstate |= MK_CONTROL;
471 return kstate;
475 /***********************************************************************
476 * EVENT_Expose
478 static void EVENT_Expose( WND *pWnd, XExposeEvent *event )
480 RECT32 rect;
482 /* Make position relative to client area instead of window */
483 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
484 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
485 rect.right = rect.left + event->width;
486 rect.bottom = rect.top + event->height;
488 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
489 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
490 (event->count ? 0 : RDW_ERASENOW), 0 );
494 /***********************************************************************
495 * EVENT_GraphicsExpose
497 * This is needed when scrolling area is partially obscured
498 * by non-Wine X window.
500 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event )
502 RECT32 rect;
504 /* Make position relative to client area instead of window */
505 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
506 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
507 rect.right = rect.left + event->width;
508 rect.bottom = rect.top + event->height;
510 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
511 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
512 (event->count ? 0 : RDW_ERASENOW), 0 );
516 /***********************************************************************
517 * EVENT_key
519 * Handle a X key event
521 static void EVENT_key( XKeyEvent *event )
523 char Str[24];
524 XComposeStatus cs;
525 KeySym keysym;
526 WORD vkey = 0;
527 WORD xkey, key_type, key;
528 KEYLP keylp;
529 BOOL extended = FALSE;
531 int ascii_chars = XLookupString(event, Str, 1, &keysym, &cs);
533 Str[ascii_chars] = '\0';
534 if (debugging_key)
536 char *ksname;
538 ksname = XKeysymToString(keysym);
539 if (!ksname)
540 ksname = "No Name";
541 fprintf(stddeb, "WM_KEY??? : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
542 keysym, ksname, ascii_chars, Str[0], Str);
545 /* Ctrl-Alt-Return enters the debugger */
546 if ((keysym == XK_Return) && (event->type == KeyPress) &&
547 (event->state & ControlMask) && (event->state & Mod1Mask))
548 DEBUG_EnterDebugger();
550 xkey = LOWORD(keysym);
551 key_type = HIBYTE(xkey);
552 key = LOBYTE(xkey);
553 dprintf_key(stddeb," key_type=%X, key=%X\n", key_type, key);
555 if (key_type == 0xFF) /* non-character key */
557 if (key >= 0x08 && key <= 0x1B) /* special key */
558 vkey = special_key[key - 0x08];
559 else if (key >= 0x50 && key <= 0x57) /* cursor key */
560 vkey = cursor_key[key - 0x50];
561 else if (key >= 0x60 && key <= 0x6B) /* miscellaneous key */
562 vkey = misc_key[key - 0x60];
563 else if (key >= 0x7E && key <= 0xB9) /* keypad key */
565 vkey = keypad_key[key - 0x7E];
566 extended = TRUE;
568 else if (key >= 0xBE && key <= 0xCD) /* function key */
570 vkey = function_key[key - 0xBE];
571 extended = TRUE;
573 else if (key >= 0xE1 && key <= 0xEA) /* modifier key */
574 vkey = modifier_key[key - 0xE1];
575 else if (key == 0xFF) /* DEL key */
576 vkey = VK_DELETE;
577 /* extended must also be set for ALT_R, CTRL_R,
578 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
579 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
580 switch (keysym)
582 case XK_Control_R :
583 case XK_Alt_R :
584 case XK_Insert :
585 case XK_Delete :
586 case XK_Home :
587 case XK_End :
588 case XK_Page_Up :
589 case XK_Page_Down :
590 case XK_Left :
591 case XK_Up :
592 case XK_Right :
593 case XK_Down :
594 case XK_KP_Divide :
595 case XK_KP_Enter :
596 extended = 1;
599 else if (key_type == 0) /* character key */
601 if ( isalnum(key) )
602 vkey = toupper(key); /* convert lc to uc */
603 else if ( isspace(key) )
604 vkey = key; /* XXX approximately */
605 else
606 switch (key) /* the rest... */
608 #define vkcase(k,val) case k: vkey = val; break;
609 #define vkcase2(k1,k2,val) case k1: case k2: vkey = val; break;
610 WINE_VKEY_MAPPINGS
611 #undef vkcase
612 #undef vkcase2
613 default:
614 fprintf( stderr, "Unknown key! Please report!\n" );
615 vkey = 0; /* whatever */
619 if (event->type == KeyPress)
621 if (!(InputKeyStateTable[vkey] & 0x80))
622 InputKeyStateTable[vkey] ^= 0x01;
623 InputKeyStateTable[vkey] |= 0x80;
624 keylp.lp1.count = 1;
625 keylp.lp1.code = LOBYTE(event->keycode) - 8;
626 keylp.lp1.extended = (extended ? 1 : 0);
627 keylp.lp1.win_internal = 0; /* this has something to do with dialogs,
628 * don't remember where I read it - AK */
629 keylp.lp1.context = ( (event->state & Mod1Mask) ||
630 (InputKeyStateTable[VK_MENU] & 0x80)) ? 1 : 0;
631 keylp.lp1.previous = (KeyDown ? 0 : 1);
632 keylp.lp1.transition = 0;
633 dprintf_key(stddeb," wParam=%X, lParam=%lX\n",
634 vkey, keylp.lp2 );
635 dprintf_key(stddeb," InputKeyState=%X\n", InputKeyStateTable[vkey]);
636 hardware_event( InputKeyStateTable[VK_MENU] & 0x80 ? WM_SYSKEYDOWN : WM_KEYDOWN,
637 vkey, keylp.lp2,
638 event->x_root - desktopX, event->y_root - desktopY,
639 event->time - MSG_WineStartTicks, 0 );
640 KeyDown = TRUE;
642 else
644 UINT sysKey = InputKeyStateTable[VK_MENU];
646 InputKeyStateTable[vkey] &= ~0x80;
647 keylp.lp1.count = 1;
648 keylp.lp1.code = LOBYTE(event->keycode) - 8;
649 keylp.lp1.extended = (extended ? 1 : 0);
650 keylp.lp1.win_internal = 0;
651 keylp.lp1.context = (event->state & Mod1Mask ? 1 : 0);
652 keylp.lp1.previous = 1;
653 keylp.lp1.transition = 1;
654 dprintf_key(stddeb," wParam=%X, lParam=%lX\n",
655 vkey, keylp.lp2 );
656 dprintf_key(stddeb," InputKeyState=%X\n", InputKeyStateTable[vkey]);
657 hardware_event( sysKey & 0x80 ? WM_SYSKEYUP : WM_KEYUP,
658 vkey, keylp.lp2,
659 event->x_root - desktopX, event->y_root - desktopY,
660 event->time - MSG_WineStartTicks, 0 );
661 KeyDown = FALSE;
666 /***********************************************************************
667 * EVENT_MotionNotify
669 static void EVENT_MotionNotify( XMotionEvent *event )
671 hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ), 0L,
672 event->x_root - desktopX, event->y_root - desktopY,
673 event->time - MSG_WineStartTicks, 0 );
677 /***********************************************************************
678 * EVENT_DummyMotionNotify
680 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
682 void EVENT_DummyMotionNotify(void)
684 Window root, child;
685 int rootX, rootY, childX, childY;
686 unsigned int state;
688 if (XQueryPointer( display, rootWindow, &root, &child,
689 &rootX, &rootY, &childX, &childY, &state ))
691 hardware_event(WM_MOUSEMOVE, EVENT_XStateToKeyState( state ), 0L,
692 rootX - desktopX, rootY - desktopY, GetTickCount(), 0 );
697 /***********************************************************************
698 * EVENT_ButtonPress
700 static void EVENT_ButtonPress( XButtonEvent *event )
702 static WORD messages[NB_BUTTONS] =
703 { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
704 int buttonNum = event->button - 1;
706 if (buttonNum >= NB_BUTTONS) return;
707 MouseButtonsStates[buttonNum] = 0x8000;
708 AsyncMouseButtonsStates[buttonNum] = 0x8000;
709 hardware_event( messages[buttonNum],
710 EVENT_XStateToKeyState( event->state ), 0L,
711 event->x_root - desktopX, event->y_root - desktopY,
712 event->time - MSG_WineStartTicks, 0 );
716 /***********************************************************************
717 * EVENT_ButtonRelease
719 static void EVENT_ButtonRelease( XButtonEvent *event )
721 static const WORD messages[NB_BUTTONS] =
722 { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
723 int buttonNum = event->button - 1;
725 if (buttonNum >= NB_BUTTONS) return;
726 MouseButtonsStates[buttonNum] = FALSE;
727 hardware_event( messages[buttonNum],
728 EVENT_XStateToKeyState( event->state ), 0L,
729 event->x_root - desktopX, event->y_root - desktopY,
730 event->time - MSG_WineStartTicks, 0 );
734 /**********************************************************************
735 * EVENT_FocusIn
737 static void EVENT_FocusIn (HWND hwnd, XFocusChangeEvent *event )
739 if (event->detail == NotifyPointer) return;
740 if (hwnd != GetActiveWindow()) WINPOS_ChangeActiveWindow( hwnd, FALSE );
741 if ((hwnd != GetFocus32()) && !IsChild( hwnd, GetFocus32()))
742 SetFocus32( hwnd );
746 /**********************************************************************
747 * EVENT_FocusOut
749 * Note: only top-level override-redirect windows get FocusOut events.
751 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event )
753 if (event->detail == NotifyPointer) return;
754 if (hwnd == GetActiveWindow()) WINPOS_ChangeActiveWindow( 0, FALSE );
755 if ((hwnd == GetFocus32()) || IsChild( hwnd, GetFocus32()))
756 SetFocus32( 0 );
760 /**********************************************************************
761 * EVENT_ConfigureNotify
763 * The ConfigureNotify event is only selected on the desktop window
764 * and on top-level windows when the -managed flag is used.
766 static void EVENT_ConfigureNotify( HWND hwnd, XConfigureEvent *event )
768 /* FIXME: with -desktop xxx we get this event _before_ desktop
769 * window structure is created. WIN_GetDesktop() check is a hack.
772 if ( !WIN_GetDesktop() || hwnd == GetDesktopWindow32())
774 desktopX = event->x;
775 desktopY = event->y;
777 else
779 WND *wndPtr;
780 WINDOWPOS16 *winpos;
781 RECT16 newWindowRect, newClientRect;
782 HRGN32 hrgnOldPos, hrgnNewPos;
784 if (!(wndPtr = WIN_FindWndPtr( hwnd )) ||
785 !(wndPtr->flags & WIN_MANAGED) )
786 return;
788 if (!(winpos = SEGPTR_NEW(WINDOWPOS16))) return;
790 /* XTranslateCoordinates(display, event->window, rootWindow,
791 event->x, event->y, &event->x, &event->y, &child);
794 /* Fill WINDOWPOS struct */
795 winpos->flags = SWP_NOACTIVATE | SWP_NOZORDER;
796 winpos->hwnd = hwnd;
797 winpos->x = event->x;
798 winpos->y = event->y;
799 winpos->cx = event->width;
800 winpos->cy = event->height;
802 /* Check for unchanged attributes */
803 if(winpos->x == wndPtr->rectWindow.left &&
804 winpos->y == wndPtr->rectWindow.top)
805 winpos->flags |= SWP_NOMOVE;
806 if(winpos->cx == wndPtr->rectWindow.right - wndPtr->rectWindow.left &&
807 winpos->cy == wndPtr->rectWindow.bottom - wndPtr->rectWindow.top)
808 winpos->flags |= SWP_NOSIZE;
810 /* Send WM_WINDOWPOSCHANGING */
811 SendMessage16(hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)SEGPTR_GET(winpos));
813 /* Calculate new position and size */
814 newWindowRect.left = event->x;
815 newWindowRect.right = event->x + event->width;
816 newWindowRect.top = event->y;
817 newWindowRect.bottom = event->y + event->height;
819 WINPOS_SendNCCalcSize( winpos->hwnd, TRUE, &newWindowRect,
820 &wndPtr->rectWindow, &wndPtr->rectClient,
821 SEGPTR_GET(winpos), &newClientRect );
823 hrgnOldPos = CreateRectRgnIndirect16( &wndPtr->rectWindow );
824 hrgnNewPos = CreateRectRgnIndirect16( &newWindowRect );
825 CombineRgn32( hrgnOldPos, hrgnOldPos, hrgnNewPos, RGN_DIFF );
827 /* Set new size and position */
828 wndPtr->rectWindow = newWindowRect;
829 wndPtr->rectClient = newClientRect;
830 SendMessage16( hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)SEGPTR_GET(winpos));
831 SEGPTR_FREE(winpos);
833 /* full window drag leaves unrepainted garbage without this */
834 PAINT_RedrawWindow( 0, NULL, hrgnOldPos, RDW_INVALIDATE |
835 RDW_ALLCHILDREN | RDW_ERASE | RDW_ERASENOW,
836 RDW_C_USEHRGN );
837 DeleteObject32(hrgnOldPos);
838 DeleteObject32(hrgnNewPos);
843 /***********************************************************************
844 * EVENT_SelectionRequest
846 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event )
848 XSelectionEvent result;
849 Atom rprop = None;
850 Window request = event->requestor;
852 if(event->target == XA_STRING)
854 HANDLE16 hText;
855 LPSTR text;
856 int size,i,j;
858 rprop = event->property;
860 if(rprop == None) rprop = event->target;
862 if(event->selection!=XA_PRIMARY) rprop = None;
863 else if(!CLIPBOARD_IsPresent(CF_OEMTEXT)) rprop = None;
864 else
866 /* open to make sure that clipboard is available */
868 BOOL couldOpen = OpenClipboard( pWnd->hwndSelf );
869 char* lpstr = 0;
871 hText = GetClipboardData(CF_TEXT);
872 text = GlobalLock16(hText);
873 size = GlobalSize16(hText);
875 /* remove carriage returns */
877 lpstr = (char*)xmalloc(size--);
878 for(i=0,j=0; i < size && text[i]; i++ )
880 if( text[i] == '\r' &&
881 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
882 lpstr[j++] = text[i];
884 lpstr[j]='\0';
886 XChangeProperty(display, request, rprop,
887 XA_STRING, 8, PropModeReplace,
888 lpstr, j);
889 free(lpstr);
891 /* close only if we opened before */
893 if(couldOpen) CloseClipboard();
897 if(rprop==None)
898 dprintf_event(stddeb,"Request for %s ignored\n", XGetAtomName(display,event->target));
900 result.type=SelectionNotify;
901 result.display=display;
902 result.requestor=request;
903 result.selection=event->selection;
904 result.property=rprop;
905 result.target=event->target;
906 result.time=event->time;
907 XSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
911 /***********************************************************************
912 * EVENT_SelectionNotify
914 static void EVENT_SelectionNotify( XSelectionEvent *event )
916 if (event->selection != XA_PRIMARY) return;
918 if (event->target != XA_STRING) CLIPBOARD_ReadSelection( 0, None );
919 else CLIPBOARD_ReadSelection( event->requestor, event->property );
921 dprintf_clipboard(stddeb,"\tSelectionNotify done!\n");
925 /***********************************************************************
926 * EVENT_SelectionClear
928 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event )
930 if (event->selection != XA_PRIMARY) return;
931 CLIPBOARD_ReleaseSelection( event->window, pWnd->hwndSelf );
935 /**********************************************************************
936 * EVENT_ClientMessage
938 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event )
940 if (event->message_type != None && event->format == 32)
942 if ((event->message_type == wmProtocols) &&
943 (((Atom) event->data.l[0]) == wmDeleteWindow))
944 SendMessage16( pWnd->hwndSelf, WM_SYSCOMMAND, SC_CLOSE, 0 );
945 else if ( event->message_type == dndProtocol &&
946 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
948 unsigned long data_length;
949 unsigned long aux_long;
950 unsigned char* p_data = NULL;
951 union {
952 Atom atom_aux;
953 POINT32 pt_aux;
954 BOOL16 bAccept;
955 int i;
956 } u;
957 int x, y;
958 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
959 LPDRAGINFO lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
960 SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
961 Window w_aux_root, w_aux_child;
962 WND* pDropWnd;
964 if( !lpDragInfo || !spDragInfo ) return;
966 XQueryPointer( display, pWnd->window, &w_aux_root, &w_aux_child,
967 &x, &y, &u.pt_aux.x, &u.pt_aux.y, (unsigned int*)&aux_long);
969 lpDragInfo->hScope = pWnd->hwndSelf;
970 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
972 /* find out drop point and drop window */
973 if( x < 0 || y < 0 ||
974 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
975 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
976 { u.bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
977 else
979 u.bAccept = DRAG_QueryUpdate( pWnd->hwndSelf, spDragInfo, TRUE );
980 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
982 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
983 GlobalFree16( hDragInfo );
985 if( u.bAccept )
987 XGetWindowProperty( display, DefaultRootWindow(display),
988 dndSelection, 0, 65535, FALSE,
989 AnyPropertyType, &u.atom_aux, &u.pt_aux.y,
990 &data_length, &aux_long, &p_data);
992 if( !aux_long && p_data) /* don't bother if > 64K */
994 char* p = (char*) p_data;
995 char* p_filename,*p_drop;
997 aux_long = 0;
998 while( *p ) /* calculate buffer size */
1000 p_drop = p;
1001 if((u.i = *p) != -1 )
1002 u.i = DRIVE_FindDriveRoot( (const char**)&p_drop );
1003 if( u.i == -1 ) *p = -1; /* mark as "bad" */
1004 else
1006 p_filename = (char*) DOSFS_GetDosTrueName( (const char*)p, TRUE );
1007 if( p_filename ) aux_long += strlen(p_filename) + 1;
1008 else *p = -1;
1010 p += strlen(p) + 1;
1012 if( aux_long && aux_long < 65535 )
1014 HDROP16 hDrop;
1015 LPDROPFILESTRUCT lpDrop;
1017 aux_long += sizeof(DROPFILESTRUCT) + 1;
1018 hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
1019 lpDrop = (LPDROPFILESTRUCT) GlobalLock16( hDrop );
1021 if( lpDrop )
1023 lpDrop->wSize = sizeof(DROPFILESTRUCT);
1024 lpDrop->ptMousePos.x = (INT16)x;
1025 lpDrop->ptMousePos.y = (INT16)y;
1026 lpDrop->fInNonClientArea = (BOOL16)
1027 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1028 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1029 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1030 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1031 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT);
1032 p = p_data;
1033 while(*p)
1035 if( *p != -1 ) /* use only "good" entries */
1037 p_filename = (char*) DOSFS_GetDosTrueName( p, TRUE );
1038 strcpy(p_drop, p_filename);
1039 p_drop += strlen( p_filename ) + 1;
1041 p += strlen(p) + 1;
1043 *p_drop = '\0';
1044 PostMessage( pWnd->hwndSelf, WM_DROPFILES, (WPARAM16)hDrop, 0L );
1048 if( p_data ) XFree(p_data);
1050 } /* WS_EX_ACCEPTFILES */
1051 } /* dndProtocol */
1052 else
1053 dprintf_event( stddeb, "unrecognized ClientMessage\n" );
1057 /**********************************************************************
1058 * EVENT_EnterNotify
1060 * Install colormap when Wine window is focused in
1061 * self-managed mode with private colormap
1064 void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
1066 if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
1067 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
1068 XInstallColormap( display, COLOR_GetColormap() );
1072 /**********************************************************************
1073 * EVENT_MapNotify
1075 void EVENT_MapNotify( HWND hWnd, XMapEvent *event )
1077 HWND32 hwndFocus = GetFocus32();
1079 if (hwndFocus && IsChild( hWnd, hwndFocus ))
1080 FOCUS_SetXFocus( (HWND32)hwndFocus );
1082 return;
1086 /**********************************************************************
1087 * SetCapture16 (USER.18)
1089 HWND16 SetCapture16( HWND16 hwnd )
1091 return (HWND16)SetCapture32( hwnd );
1095 /**********************************************************************
1096 * SetCapture32 (USER32.463)
1098 HWND32 SetCapture32( HWND32 hwnd )
1100 Window win;
1101 HWND32 old_capture_wnd = captureWnd;
1103 if (!hwnd)
1105 ReleaseCapture();
1106 return old_capture_wnd;
1108 if (!(win = WIN_GetXWindow( hwnd ))) return 0;
1109 if (XGrabPointer(display, win, False,
1110 ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
1111 GrabModeAsync, GrabModeAsync,
1112 None, None, CurrentTime ) == GrabSuccess)
1114 dprintf_win(stddeb, "SetCapture: %04x\n", hwnd);
1115 captureWnd = hwnd;
1116 return old_capture_wnd;
1118 else return 0;
1122 /**********************************************************************
1123 * ReleaseCapture (USER.19) (USER32.438)
1125 void ReleaseCapture(void)
1127 if (captureWnd == 0) return;
1128 XUngrabPointer( display, CurrentTime );
1129 captureWnd = 0;
1130 dprintf_win(stddeb, "ReleaseCapture\n");
1134 /**********************************************************************
1135 * GetCapture16 (USER.236)
1137 HWND16 GetCapture16(void)
1139 return (HWND16)captureWnd;
1143 /**********************************************************************
1144 * GetCapture32 (USER32.207)
1146 HWND32 GetCapture32(void)
1148 return captureWnd;
1152 /***********************************************************************
1153 * GetMouseEventProc (USER.337)
1155 FARPROC16 GetMouseEventProc(void)
1157 HMODULE16 hmodule = GetModuleHandle("USER");
1158 return MODULE_GetEntryPoint( hmodule,
1159 MODULE_GetOrdinal( hmodule, "Mouse_Event" ) );
1163 /***********************************************************************
1164 * Mouse_Event (USER.299)
1166 #ifndef WINELIB
1167 void Mouse_Event( SIGCONTEXT *context )
1169 /* Register values:
1170 * AX = mouse event
1171 * BX = horizontal displacement if AX & ME_MOVE
1172 * CX = vertical displacement if AX & ME_MOVE
1173 * DX = button state (?)
1174 * SI = mouse event flags (?)
1176 Window root, child;
1177 int rootX, rootY, childX, childY;
1178 unsigned int state;
1180 if (AX_reg(context) & ME_MOVE)
1182 /* We have to actually move the cursor */
1183 XWarpPointer( display, rootWindow, None, 0, 0, 0, 0,
1184 (short)BX_reg(context), (short)CX_reg(context) );
1185 return;
1187 if (!XQueryPointer( display, rootWindow, &root, &child,
1188 &rootX, &rootY, &childX, &childY, &state )) return;
1189 if (AX_reg(context) & ME_LDOWN)
1190 hardware_event( WM_LBUTTONDOWN, EVENT_XStateToKeyState( state ), 0L,
1191 rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
1192 if (AX_reg(context) & ME_LUP)
1193 hardware_event( WM_LBUTTONUP, EVENT_XStateToKeyState( state ), 0L,
1194 rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
1195 if (AX_reg(context) & ME_RDOWN)
1196 hardware_event( WM_RBUTTONDOWN, EVENT_XStateToKeyState( state ), 0L,
1197 rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
1198 if (AX_reg(context) & ME_RUP)
1199 hardware_event( WM_RBUTTONUP, EVENT_XStateToKeyState( state ), 0L,
1200 rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
1202 #endif
1205 /**********************************************************************
1206 * EnableHardwareInput (USER.331)
1208 BOOL16 EnableHardwareInput(BOOL16 bEnable)
1210 BOOL16 bOldState = InputEnabled;
1211 dprintf_event(stdnimp,"EnableHardwareInput(%d);\n", bEnable);
1212 InputEnabled = bEnable;
1213 return bOldState;