Added Drag&Drop from KDE app to 16/32 bit Windoze app.
[wine/multimedia.git] / windows / event.c
blob1ebe5b0f4680cdd05fe79bbc2236551531d90f69
1 /*
2 * X events handling functions
3 *
4 * Copyright 1993 Alexandre Julliard
5 *
6 */
8 #include <assert.h>
9 #include <ctype.h>
10 #include <stdlib.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 "ts_xlib.h"
18 #include "ts_xresource.h"
19 #include "ts_xutil.h"
20 #include <X11/Xatom.h>
22 #include "windows.h"
23 #include "winnt.h"
24 #include "gdi.h"
25 #include "heap.h"
26 #include "queue.h"
27 #include "win.h"
28 #include "class.h"
29 #include "clipboard.h"
30 #include "dce.h"
31 #include "message.h"
32 #include "module.h"
33 #include "options.h"
34 #include "queue.h"
35 #include "winpos.h"
36 #include "drive.h"
37 #include "shell.h"
38 #include "keyboard.h"
39 #include "debug.h"
40 #include "dde_proc.h"
41 #include "winsock.h"
42 #include "callback.h"
45 #define NB_BUTTONS 3 /* Windows can handle 3 buttons */
47 #define DndNotDnd -1 /* OffiX drag&drop */
48 #define DndUnknown 0
49 #define DndRawData 1
50 #define DndFile 2
51 #define DndFiles 3
52 #define DndText 4
53 #define DndDir 5
54 #define DndLink 6
55 #define DndExe 7
57 #define DndEND 8
59 #define DndURL 128 /* KDE drag&drop */
62 /* X context to associate a hwnd to an X window */
63 static XContext winContext = 0;
65 static INT16 captureHT = HTCLIENT;
66 static HWND32 captureWnd = 0;
67 static BOOL32 InputEnabled = TRUE;
68 static BOOL32 SwappedButtons = FALSE;
70 static Atom wmProtocols = None;
71 static Atom wmDeleteWindow = None;
72 static Atom dndProtocol = None;
73 static Atom dndSelection = None;
75 /* EVENT_WaitNetEvent() master fd sets */
77 static fd_set __event_io_set[3];
78 static int __event_max_fd = 0;
79 static int __event_x_connection = 0;
81 static const char * const event_names[] =
83 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
84 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
85 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
86 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
87 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
88 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
89 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
90 "ClientMessage", "MappingNotify"
93 /* Event handlers */
94 static void EVENT_Key( WND *pWnd, XKeyEvent *event );
95 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event );
96 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event );
97 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event );
98 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event );
99 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event );
100 static void EVENT_Expose( WND *pWnd, XExposeEvent *event );
101 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event );
102 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event );
103 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event);
104 static void EVENT_SelectionNotify( XSelectionEvent *event);
105 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event);
106 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event );
107 static void EVENT_MapNotify( HWND32 hwnd, XMapEvent *event );
109 /* Usable only with OLVWM - compile option perhaps?
110 static void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event );
113 static void EVENT_SendMouseEvent( WORD mouseStatus, WORD deltaX, WORD deltaY,
114 WORD buttonCount, DWORD extraInfo );
116 /***********************************************************************
117 * EVENT_Init
119 * Initialize network IO.
121 BOOL32 EVENT_Init(void)
123 int i;
124 for( i = 0; i < 3; i++ )
125 FD_ZERO( __event_io_set + i );
127 __event_max_fd = __event_x_connection = ConnectionNumber(display);
128 FD_SET( __event_x_connection, &__event_io_set[EVENT_IO_READ] );
129 __event_max_fd++;
130 return TRUE;
133 /***********************************************************************
134 * EVENT_AddIO
136 void EVENT_AddIO( int fd, unsigned io_type )
138 FD_SET( fd, &__event_io_set[io_type] );
139 if( __event_max_fd <= fd ) __event_max_fd = fd + 1;
142 void EVENT_DeleteIO( int fd, unsigned io_type )
144 FD_CLR( fd, &__event_io_set[io_type] );
147 /***********************************************************************
148 * EVENT_ProcessEvent
150 * Process an X event.
152 void EVENT_ProcessEvent( XEvent *event )
154 WND *pWnd;
156 if ( TSXFindContext( display, event->xany.window, winContext,
157 (char **)&pWnd ) != 0) {
158 if ( event->type == ClientMessage) {
159 /* query window (drag&drop event contains only drag window) */
160 Window root, child;
161 int root_x, root_y, child_x, child_y;
162 unsigned u;
163 TSXQueryPointer( display, rootWindow, &root, &child,
164 &root_x, &root_y, &child_x, &child_y, &u);
165 if (TSXFindContext( display, child, winContext, (char **)&pWnd ) != 0)
166 return;
167 } else {
168 return; /* Not for a registered window */
172 TRACE(event, "Got event %s for hwnd %04x\n",
173 event_names[event->type], pWnd->hwndSelf );
175 switch(event->type)
177 case KeyPress:
178 case KeyRelease:
179 if (InputEnabled) EVENT_Key( pWnd, (XKeyEvent*)event );
180 break;
182 case ButtonPress:
183 if (InputEnabled)
184 EVENT_ButtonPress( pWnd, (XButtonEvent*)event );
185 break;
187 case ButtonRelease:
188 if (InputEnabled)
189 EVENT_ButtonRelease( pWnd, (XButtonEvent*)event );
190 break;
192 case MotionNotify:
193 /* Wine between two fast machines across the overloaded campus
194 ethernet gets very boged down in MotionEvents. The following
195 simply finds the last motion event in the queue and drops
196 the rest. On a good link events are servered before they build
197 up so this doesn't take place. On a slow link this may cause
198 problems if the event order is important. I'm not yet seen
199 of any problems. Jon 7/6/96.
201 if (InputEnabled)
203 while (TSXCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
204 MotionNotify, event));
205 EVENT_MotionNotify( pWnd, (XMotionEvent*)event );
207 break;
209 case FocusIn:
210 EVENT_FocusIn( pWnd, (XFocusChangeEvent*)event );
211 break;
213 case FocusOut:
214 EVENT_FocusOut( pWnd, (XFocusChangeEvent*)event );
215 break;
217 case Expose:
218 EVENT_Expose( pWnd, (XExposeEvent *)event );
219 break;
221 case GraphicsExpose:
222 EVENT_GraphicsExpose( pWnd, (XGraphicsExposeEvent *)event );
223 break;
225 case ConfigureNotify:
226 EVENT_ConfigureNotify( pWnd, (XConfigureEvent*)event );
227 break;
229 case SelectionRequest:
230 EVENT_SelectionRequest( pWnd, (XSelectionRequestEvent *)event );
231 break;
233 case SelectionNotify:
234 EVENT_SelectionNotify( (XSelectionEvent *)event );
235 break;
237 case SelectionClear:
238 EVENT_SelectionClear( pWnd, (XSelectionClearEvent*) event );
239 break;
241 case ClientMessage:
242 EVENT_ClientMessage( pWnd, (XClientMessageEvent *) event );
243 break;
245 /* case EnterNotify:
246 * EVENT_EnterNotify( pWnd, (XCrossingEvent *) event );
247 * break;
249 case NoExpose:
250 break;
252 /* We get all these because of StructureNotifyMask. */
253 case UnmapNotify:
254 case CirculateNotify:
255 case CreateNotify:
256 case DestroyNotify:
257 case GravityNotify:
258 case ReparentNotify:
259 break;
261 case MapNotify:
262 EVENT_MapNotify( pWnd->hwndSelf, (XMapEvent *)event );
263 break;
265 default:
266 WARN(event, "Unprocessed event %s for hwnd %04x\n",
267 event_names[event->type], pWnd->hwndSelf );
268 break;
273 /***********************************************************************
274 * EVENT_RegisterWindow
276 * Associate an X window to a HWND.
278 void EVENT_RegisterWindow( WND *pWnd )
280 if (wmProtocols == None)
281 wmProtocols = TSXInternAtom( display, "WM_PROTOCOLS", True );
282 if (wmDeleteWindow == None)
283 wmDeleteWindow = TSXInternAtom( display, "WM_DELETE_WINDOW", True );
284 if( dndProtocol == None )
285 dndProtocol = TSXInternAtom( display, "DndProtocol" , False );
286 if( dndSelection == None )
287 dndSelection = TSXInternAtom( display, "DndSelection" , False );
289 TSXSetWMProtocols( display, pWnd->window, &wmDeleteWindow, 1 );
291 if (!winContext) winContext = TSXUniqueContext();
292 TSXSaveContext( display, pWnd->window, winContext, (char *)pWnd );
295 /***********************************************************************
296 * EVENT_DestroyWindow
298 void EVENT_DestroyWindow( WND *pWnd )
300 XEvent xe;
302 TSXDeleteContext( display, pWnd->window, winContext );
303 TSXDestroyWindow( display, pWnd->window );
304 while( TSXCheckWindowEvent(display, pWnd->window, NoEventMask, &xe) );
308 /***********************************************************************
309 * IsUserIdle (USER.333)
311 * Check if we have pending X events.
313 BOOL16 WINAPI IsUserIdle(void)
315 struct timeval timeout = {0, 0};
316 fd_set check_set;
318 FD_ZERO(&check_set);
319 FD_SET(__event_x_connection, &check_set);
320 if( select(__event_x_connection + 1, &check_set, NULL, NULL, &timeout) > 0 )
321 return TRUE;
322 return FALSE;
326 /***********************************************************************
327 * EVENT_WaitNetEvent
329 * Wait for a network event, optionally sleeping until one arrives.
330 * Return TRUE if an event is pending, FALSE on timeout or error
331 * (for instance lost connection with the server).
333 BOOL32 EVENT_WaitNetEvent( BOOL32 sleep, BOOL32 peek )
335 XEvent event;
336 LONG maxWait = sleep ? TIMER_GetNextExpiration() : 0;
337 int pending = TSXPending(display);
339 /* Wait for an event or a timeout. If maxWait is -1, we have no timeout;
340 * in this case, we fall through directly to the XNextEvent loop.
343 if ((maxWait != -1) && !pending)
345 int num_pending;
346 struct timeval timeout;
347 fd_set io_set[3];
349 memcpy( io_set, __event_io_set, sizeof(io_set) );
351 timeout.tv_usec = (maxWait % 1000) * 1000;
352 timeout.tv_sec = maxWait / 1000;
354 #ifdef CONFIG_IPC
355 sigsetjmp(env_wait_x, 1);
356 stop_wait_op= CONT;
358 if (DDE_GetRemoteMessage()) {
359 while(DDE_GetRemoteMessage())
361 return TRUE;
363 stop_wait_op = STOP_WAIT_X;
364 /* The code up to the next "stop_wait_op = CONT" must be reentrant */
365 num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
366 &io_set[EVENT_IO_WRITE],
367 &io_set[EVENT_IO_EXCEPT], &timeout );
368 if ( num_pending == 0 )
370 stop_wait_op = CONT;
371 TIMER_ExpireTimers();
372 return FALSE;
374 else stop_wait_op = CONT;
375 #else /* CONFIG_IPC */
376 num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
377 &io_set[EVENT_IO_WRITE],
378 &io_set[EVENT_IO_EXCEPT], &timeout );
379 if ( num_pending == 0)
381 /* Timeout or error */
382 TIMER_ExpireTimers();
383 return FALSE;
385 #endif /* CONFIG_IPC */
387 /* Winsock asynchronous services */
389 if( FD_ISSET( __event_x_connection, &io_set[EVENT_IO_READ]) )
391 num_pending--;
392 if( num_pending )
393 WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
395 else /* no X events */
396 return WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
398 else if(!pending)
399 { /* Wait for X11 input. */
400 fd_set set;
402 FD_ZERO(&set);
403 FD_SET(__event_x_connection, &set);
404 select(__event_x_connection + 1, &set, 0, 0, 0 );
407 /* Process current X event (and possibly others that occurred in the meantime) */
409 EnterCriticalSection(&X11DRV_CritSection);
410 while (XPending( display ))
413 #ifdef CONFIG_IPC
414 if (DDE_GetRemoteMessage())
416 LeaveCriticalSection(&X11DRV_CritSection);
417 while(DDE_GetRemoteMessage()) ;
418 return TRUE;
420 #endif /* CONFIG_IPC */
422 XNextEvent( display, &event );
424 LeaveCriticalSection(&X11DRV_CritSection);
425 if( peek )
427 WND* pWnd;
428 MESSAGEQUEUE* pQ;
431 /* Check only for those events which can be processed
432 * internally. */
434 if( event.type == MotionNotify ||
435 event.type == ButtonPress || event.type == ButtonRelease ||
436 event.type == KeyPress || event.type == KeyRelease ||
437 event.type == SelectionRequest || event.type == SelectionClear ||
438 event.type == ClientMessage )
440 EVENT_ProcessEvent( &event );
441 continue;
444 if (TSXFindContext( display, ((XAnyEvent *)&event)->window, winContext,
445 (char **)&pWnd ) || (event.type == NoExpose))
446 continue;
448 if( pWnd )
450 if( (pQ = (MESSAGEQUEUE*)GlobalLock16(pWnd->hmemTaskQ)) )
452 pQ->flags |= QUEUE_FLAG_XEVENT;
453 PostEvent(pQ->hTask);
454 TSXPutBackEvent(display, &event);
455 break;
459 else EVENT_ProcessEvent( &event );
460 EnterCriticalSection(&X11DRV_CritSection);
462 LeaveCriticalSection(&X11DRV_CritSection);
463 return TRUE;
467 /***********************************************************************
468 * EVENT_Synchronize
470 * Synchronize with the X server. Should not be used too often.
472 void EVENT_Synchronize()
474 XEvent event;
476 /* Use of the X critical section is needed or we have a small
477 * race between XPending() and XNextEvent().
479 EnterCriticalSection( &X11DRV_CritSection );
480 XSync( display, False );
481 while (XPending( display ))
483 XNextEvent( display, &event );
484 /* unlock X critsection for EVENT_ProcessEvent() might switch tasks */
485 LeaveCriticalSection( &X11DRV_CritSection );
486 EVENT_ProcessEvent( &event );
487 EnterCriticalSection( &X11DRV_CritSection );
489 LeaveCriticalSection( &X11DRV_CritSection );
492 /***********************************************************************
493 * EVENT_QueryZOrder
495 * Try to synchronize internal z-order with the window manager's.
496 * Probably a futile endeavor.
498 static BOOL32 __check_query_condition( WND** pWndA, WND** pWndB )
500 /* return TRUE if we have at least two managed windows */
502 for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
503 if( (*pWndA)->flags & WIN_MANAGED &&
504 (*pWndA)->dwStyle & WS_VISIBLE ) break;
505 if( *pWndA )
506 for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
507 if( (*pWndB)->flags & WIN_MANAGED &&
508 (*pWndB)->dwStyle & WS_VISIBLE ) break;
509 return ((*pWndB) != NULL);
512 static Window __get_common_ancestor( Window A, Window B,
513 Window** children, unsigned* total )
515 /* find the real root window */
517 Window root, *childrenB;
518 unsigned totalB;
522 if( *children ) TSXFree( *children );
523 TSXQueryTree( display, A, &root, &A, children, total );
524 TSXQueryTree( display, B, &root, &B, &childrenB, &totalB );
525 if( childrenB ) TSXFree( childrenB );
526 } while( A != B && A && B );
527 return ( A && B ) ? A : 0 ;
530 static Window __get_top_decoration( Window w, Window ancestor )
532 Window* children, root, prev = w, parent = w;
533 unsigned total;
537 w = parent;
538 TSXQueryTree( display, w, &root, &parent, &children, &total );
539 if( children ) TSXFree( children );
540 } while( parent && parent != ancestor );
541 TRACE(event, "\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
542 return ( parent ) ? w : 0 ;
545 static unsigned __td_lookup( Window w, Window* list, unsigned max )
547 unsigned i;
548 for( i = 0; i < max; i++ ) if( list[i] == w ) break;
549 return i;
552 static BOOL32 EVENT_QueryZOrder( WND* pWndCheck )
554 BOOL32 bRet = FALSE;
555 HWND32 hwndInsertAfter = HWND_TOP;
556 WND* pWnd, *pWndZ = WIN_GetDesktop()->child;
557 Window w, parent, *children = NULL;
558 unsigned total, check, pos, best;
560 if( !__check_query_condition(&pWndZ, &pWnd) ) return TRUE;
562 parent = __get_common_ancestor( pWndZ->window, pWnd->window,
563 &children, &total );
564 if( parent && children )
566 w = __get_top_decoration( pWndCheck->window, parent );
567 if( w != children[total - 1] )
569 check = __td_lookup( w, children, total );
570 best = total;
571 for( pWnd = pWndZ; pWnd; pWnd = pWnd->next )
573 if( pWnd != pWndCheck )
575 if( !(pWnd->flags & WIN_MANAGED) ||
576 !(w = __get_top_decoration( pWnd->window, parent )) )
577 continue;
578 pos = __td_lookup( w, children, total );
579 if( pos < best && pos > check )
581 best = pos;
582 hwndInsertAfter = pWnd->hwndSelf;
584 if( check - best == 1 ) break;
587 WIN_UnlinkWindow( pWndCheck->hwndSelf );
588 WIN_LinkWindow( pWndCheck->hwndSelf, hwndInsertAfter);
591 if( children ) TSXFree( children );
592 return bRet;
596 /***********************************************************************
597 * EVENT_XStateToKeyState
599 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
600 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
602 static WORD EVENT_XStateToKeyState( int state )
604 int kstate = 0;
606 if (state & Button1Mask) kstate |= MK_LBUTTON;
607 if (state & Button2Mask) kstate |= MK_MBUTTON;
608 if (state & Button3Mask) kstate |= MK_RBUTTON;
609 if (state & ShiftMask) kstate |= MK_SHIFT;
610 if (state & ControlMask) kstate |= MK_CONTROL;
611 return kstate;
615 /***********************************************************************
616 * EVENT_Expose
618 static void EVENT_Expose( WND *pWnd, XExposeEvent *event )
620 RECT32 rect;
622 /* Make position relative to client area instead of window */
623 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
624 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
625 rect.right = rect.left + event->width;
626 rect.bottom = rect.top + event->height;
628 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
629 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
630 (event->count ? 0 : RDW_ERASENOW), 0 );
634 /***********************************************************************
635 * EVENT_GraphicsExpose
637 * This is needed when scrolling area is partially obscured
638 * by non-Wine X window.
640 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event )
642 RECT32 rect;
644 /* Make position relative to client area instead of window */
645 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
646 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
647 rect.right = rect.left + event->width;
648 rect.bottom = rect.top + event->height;
650 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
651 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
652 (event->count ? 0 : RDW_ERASENOW), 0 );
656 /***********************************************************************
657 * EVENT_Key
659 * Handle a X key event
661 static void EVENT_Key( WND *pWnd, XKeyEvent *event )
663 KEYBOARD_HandleEvent( pWnd, event );
667 /***********************************************************************
668 * EVENT_MotionNotify
670 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event )
672 hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ), 0L,
673 pWnd->rectWindow.left + event->x,
674 pWnd->rectWindow.top + event->y,
675 event->time - MSG_WineStartTicks, pWnd->hwndSelf );
677 EVENT_SendMouseEvent( ME_MOVE,
678 pWnd->rectWindow.left + event->x,
679 pWnd->rectWindow.top + event->y,
680 0, 0 );
684 /***********************************************************************
685 * EVENT_DummyMotionNotify
687 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
689 void EVENT_DummyMotionNotify(void)
691 Window root, child;
692 int rootX, rootY, winX, winY;
693 unsigned int state;
695 if (TSXQueryPointer( display, rootWindow, &root, &child,
696 &rootX, &rootY, &winX, &winY, &state ))
698 hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( state ), 0L,
699 winX, winY, GetTickCount(), 0 );
704 /***********************************************************************
705 * EVENT_ButtonPress
707 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event )
709 static WORD messages[NB_BUTTONS] =
710 { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
711 static WORD statusCodes[NB_BUTTONS] =
712 { ME_LDOWN, 0, ME_RDOWN };
713 int buttonNum = event->button - 1;
715 if (buttonNum >= NB_BUTTONS) return;
716 if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
717 MouseButtonsStates[buttonNum] = TRUE;
718 AsyncMouseButtonsStates[buttonNum] = TRUE;
719 hardware_event( messages[buttonNum],
720 EVENT_XStateToKeyState( event->state ), 0L,
721 pWnd->rectWindow.left + event->x,
722 pWnd->rectWindow.top + event->y,
723 event->time - MSG_WineStartTicks, pWnd->hwndSelf );
725 EVENT_SendMouseEvent( statusCodes[buttonNum],
726 pWnd->rectWindow.left + event->x,
727 pWnd->rectWindow.top + event->y,
728 0, 0 );
732 /***********************************************************************
733 * EVENT_ButtonRelease
735 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event )
737 static const WORD messages[NB_BUTTONS] =
738 { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
739 static WORD statusCodes[NB_BUTTONS] =
740 { ME_LUP, 0, ME_RUP };
741 int buttonNum = event->button - 1;
743 if (buttonNum >= NB_BUTTONS) return;
744 if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
745 MouseButtonsStates[buttonNum] = FALSE;
746 hardware_event( messages[buttonNum],
747 EVENT_XStateToKeyState( event->state ), 0L,
748 pWnd->rectWindow.left + event->x,
749 pWnd->rectWindow.top + event->y,
750 event->time - MSG_WineStartTicks, pWnd->hwndSelf );
752 EVENT_SendMouseEvent( statusCodes[buttonNum],
753 pWnd->rectWindow.left + event->x,
754 pWnd->rectWindow.top + event->y,
755 0, 0 );
759 /**********************************************************************
760 * EVENT_FocusIn
762 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event )
764 if (Options.managed) EVENT_QueryZOrder( pWnd );
766 if (event->detail != NotifyPointer)
768 HWND32 hwnd = pWnd->hwndSelf;
770 if (hwnd != GetActiveWindow32())
772 WINPOS_ChangeActiveWindow( hwnd, FALSE );
773 KEYBOARD_UpdateState();
775 if ((hwnd != GetFocus32()) && !IsChild32( hwnd, GetFocus32()))
776 SetFocus32( hwnd );
781 /**********************************************************************
782 * EVENT_FocusOut
784 * Note: only top-level override-redirect windows get FocusOut events.
786 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event )
788 if (event->detail != NotifyPointer)
790 HWND32 hwnd = pWnd->hwndSelf;
792 if (hwnd == GetActiveWindow32())
793 WINPOS_ChangeActiveWindow( 0, FALSE );
794 if ((hwnd == GetFocus32()) || IsChild32( hwnd, GetFocus32()))
795 SetFocus32( 0 );
799 /**********************************************************************
800 * EVENT_CheckFocus
802 BOOL32 EVENT_CheckFocus(void)
804 WND* pWnd;
805 Window xW;
806 int state;
808 TSXGetInputFocus(display, &xW, &state);
809 if( xW == None ||
810 TSXFindContext(display, xW, winContext, (char **)&pWnd) )
811 return FALSE;
812 return TRUE;
816 /**********************************************************************
817 * EVENT_GetGeometry
819 * Helper function for ConfigureNotify handling.
820 * Get the new geometry of a window relative to the root window.
822 static void EVENT_GetGeometry( Window win, int *px, int *py,
823 unsigned int *pwidth, unsigned int *pheight )
825 Window root, parent, *children;
826 int xpos, ypos;
827 unsigned int width, height, border, depth, nb_children;
829 if (!TSXGetGeometry( display, win, &root, px, py, pwidth, pheight,
830 &border, &depth )) return;
831 if (win == rootWindow)
833 *px = *py = 0;
834 return;
837 for (;;)
839 if (!TSXQueryTree(display, win, &root, &parent, &children, &nb_children))
840 return;
841 TSXFree( children );
842 if (parent == rootWindow) break;
843 win = parent;
844 if (!TSXGetGeometry( display, win, &root, &xpos, &ypos,
845 &width, &height, &border, &depth )) return;
846 *px += xpos;
847 *py += ypos;
852 /**********************************************************************
853 * EVENT_ConfigureNotify
855 * The ConfigureNotify event is only selected on top-level windows
856 * when the -managed flag is used.
858 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event )
860 WINDOWPOS32 winpos;
861 RECT32 newWindowRect, newClientRect;
862 HRGN32 hrgnOldPos, hrgnNewPos;
863 Window above = event->above;
864 int x, y;
865 unsigned int width, height;
867 assert (pWnd->flags & WIN_MANAGED);
869 /* We don't rely on the event geometry info, because it is relative
870 * to parent and not to root, and it may be wrong (XFree sets x,y to 0,0
871 * if the window hasn't moved).
873 EVENT_GetGeometry( event->window, &x, &y, &width, &height );
875 /* Fill WINDOWPOS struct */
876 winpos.flags = SWP_NOACTIVATE | SWP_NOZORDER;
877 winpos.hwnd = pWnd->hwndSelf;
878 winpos.x = x;
879 winpos.y = y;
880 winpos.cx = width;
881 winpos.cy = height;
883 /* Check for unchanged attributes */
884 if (winpos.x == pWnd->rectWindow.left && winpos.y == pWnd->rectWindow.top)
885 winpos.flags |= SWP_NOMOVE;
886 if ((winpos.cx == pWnd->rectWindow.right - pWnd->rectWindow.left) &&
887 (winpos.cy == pWnd->rectWindow.bottom - pWnd->rectWindow.top))
888 winpos.flags |= SWP_NOSIZE;
889 else
891 RECT32 rect = { 0, 0, pWnd->rectWindow.right - pWnd->rectWindow.left,
892 pWnd->rectWindow.bottom - pWnd->rectWindow.top };
893 DCE_InvalidateDCE( pWnd, &rect );
896 /* Send WM_WINDOWPOSCHANGING */
897 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)&winpos );
899 /* Calculate new position and size */
900 newWindowRect.left = x;
901 newWindowRect.right = x + width;
902 newWindowRect.top = y;
903 newWindowRect.bottom = y + height;
905 WINPOS_SendNCCalcSize( winpos.hwnd, TRUE, &newWindowRect,
906 &pWnd->rectWindow, &pWnd->rectClient,
907 &winpos, &newClientRect );
909 hrgnOldPos = CreateRectRgnIndirect32( &pWnd->rectWindow );
910 hrgnNewPos = CreateRectRgnIndirect32( &newWindowRect );
911 CombineRgn32( hrgnOldPos, hrgnOldPos, hrgnNewPos, RGN_DIFF );
912 DeleteObject32(hrgnOldPos);
913 DeleteObject32(hrgnNewPos);
915 /* Set new size and position */
916 pWnd->rectWindow = newWindowRect;
917 pWnd->rectClient = newClientRect;
918 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)&winpos );
920 if (!IsWindow32( winpos.hwnd )) return;
921 if( above == None ) /* absolute bottom */
923 WIN_UnlinkWindow( winpos.hwnd );
924 WIN_LinkWindow( winpos.hwnd, HWND_BOTTOM);
926 else EVENT_QueryZOrder( pWnd ); /* try to outsmart window manager */
930 /***********************************************************************
931 * EVENT_SelectionRequest
933 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event )
935 XSelectionEvent result;
936 Atom rprop = None;
937 Window request = event->requestor;
939 if(event->target == XA_STRING)
941 HANDLE16 hText;
942 LPSTR text;
943 int size,i,j;
945 rprop = event->property;
947 if(rprop == None) rprop = event->target;
949 if(event->selection!=XA_PRIMARY) rprop = None;
950 else if(!CLIPBOARD_IsPresent(CF_OEMTEXT)) rprop = None;
951 else
953 /* open to make sure that clipboard is available */
955 BOOL32 couldOpen = OpenClipboard32( pWnd->hwndSelf );
956 char* lpstr = 0;
958 hText = GetClipboardData16(CF_TEXT);
959 text = GlobalLock16(hText);
960 size = GlobalSize16(hText);
962 /* remove carriage returns */
964 lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
965 for(i=0,j=0; i < size && text[i]; i++ )
967 if( text[i] == '\r' &&
968 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
969 lpstr[j++] = text[i];
971 lpstr[j]='\0';
973 TSXChangeProperty(display, request, rprop,
974 XA_STRING, 8, PropModeReplace,
975 lpstr, j);
976 HeapFree( GetProcessHeap(), 0, lpstr );
978 /* close only if we opened before */
980 if(couldOpen) CloseClipboard32();
984 if(rprop == None)
985 TRACE(event,"Request for %s ignored\n", TSXGetAtomName(display,event->target));
987 result.type = SelectionNotify;
988 result.display = display;
989 result.requestor = request;
990 result.selection = event->selection;
991 result.property = rprop;
992 result.target = event->target;
993 result.time = event->time;
994 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
998 /***********************************************************************
999 * EVENT_SelectionNotify
1001 static void EVENT_SelectionNotify( XSelectionEvent *event )
1003 if (event->selection != XA_PRIMARY) return;
1005 if (event->target != XA_STRING) CLIPBOARD_ReadSelection( 0, None );
1006 else CLIPBOARD_ReadSelection( event->requestor, event->property );
1008 TRACE(clipboard,"\tSelectionNotify done!\n");
1012 /***********************************************************************
1013 * EVENT_SelectionClear
1015 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event )
1017 if (event->selection != XA_PRIMARY) return;
1018 CLIPBOARD_ReleaseSelection( event->window, pWnd->hwndSelf );
1022 /**********************************************************************
1023 * EVENT_DropFromOffix
1025 * don't know if it still works (last Changlog is from 96/11/04)
1027 static void EVENT_DropFromOffiX( WND *pWnd, XClientMessageEvent *event )
1029 unsigned long data_length;
1030 unsigned long aux_long;
1031 unsigned char* p_data = NULL;
1032 union {
1033 Atom atom_aux;
1034 POINT32 pt_aux;
1035 int i;
1036 } u;
1037 int x, y;
1038 BOOL16 bAccept;
1039 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
1040 LPDRAGINFO lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
1041 SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
1042 Window w_aux_root, w_aux_child;
1043 WND* pDropWnd;
1045 if( !lpDragInfo || !spDragInfo ) return;
1047 TSXQueryPointer( display, pWnd->window, &w_aux_root, &w_aux_child,
1048 &x, &y, &u.pt_aux.x, &u.pt_aux.y, (unsigned int*)&aux_long);
1050 lpDragInfo->hScope = pWnd->hwndSelf;
1051 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1053 /* find out drop point and drop window */
1054 if( x < 0 || y < 0 ||
1055 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1056 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1057 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1058 else
1060 bAccept = DRAG_QueryUpdate( pWnd->hwndSelf, spDragInfo, TRUE );
1061 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1063 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1064 GlobalFree16( hDragInfo );
1066 if( bAccept )
1068 TSXGetWindowProperty( display, DefaultRootWindow(display),
1069 dndSelection, 0, 65535, FALSE,
1070 AnyPropertyType, &u.atom_aux, &u.pt_aux.y,
1071 &data_length, &aux_long, &p_data);
1073 if( !aux_long && p_data) /* don't bother if > 64K */
1075 char *p = (char*) p_data;
1076 char *p_drop;
1078 aux_long = 0;
1079 while( *p ) /* calculate buffer size */
1081 p_drop = p;
1082 if((u.i = *p) != -1 )
1083 u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
1084 if( u.i == -1 ) *p = -1; /* mark as "bad" */
1085 else
1087 INT32 len = GetShortPathName32A( p, NULL, 0 );
1088 if (len) aux_long += len + 1;
1089 else *p = -1;
1091 p += strlen(p) + 1;
1093 if( aux_long && aux_long < 65535 )
1095 HDROP16 hDrop;
1096 LPDROPFILESTRUCT16 lpDrop;
1098 aux_long += sizeof(DROPFILESTRUCT16) + 1;
1099 hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
1100 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop );
1102 if( lpDrop )
1104 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1105 lpDrop->ptMousePos.x = (INT16)x;
1106 lpDrop->ptMousePos.y = (INT16)y;
1107 lpDrop->fInNonClientArea = (BOOL16)
1108 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1109 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1110 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1111 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1112 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1113 p = p_data;
1114 while(*p)
1116 if( *p != -1 ) /* use only "good" entries */
1118 GetShortPathName32A( p, p_drop, 65535 );
1119 p_drop += strlen( p_drop ) + 1;
1121 p += strlen(p) + 1;
1123 *p_drop = '\0';
1124 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1125 (WPARAM16)hDrop, 0L );
1129 if( p_data ) TSXFree(p_data);
1131 } /* WS_EX_ACCEPTFILES */
1134 /**********************************************************************
1135 * EVENT_DropURLs
1137 * drop items are separated by \n
1138 * each item is prefixed by its mime type
1140 * event->data.l[3], event->data.l[4] contains drop x,y position
1142 static void EVENT_DropURLs( WND *pWnd, XClientMessageEvent *event )
1144 WND *pDropWnd;
1145 unsigned long data_length;
1146 unsigned long aux_long, drop_len = 0;
1147 unsigned char *p_data = NULL; /* property data */
1148 char *p_drop = NULL;
1149 char *p, *next;
1150 int x, y, drop32 = FALSE ;
1151 union {
1152 Atom atom_aux;
1153 POINT32 pt_aux;
1154 int i;
1155 Window w_aux;
1156 } u; /* unused */
1157 union {
1158 HDROP16 h16;
1159 HDROP32 h32;
1160 } hDrop;
1162 drop32 = pWnd->flags & WIN_ISWIN32;
1164 if (!(pWnd->dwExStyle & WS_EX_ACCEPTFILES))
1165 return;
1167 TSXGetWindowProperty( display, DefaultRootWindow(display),
1168 dndSelection, 0, 65535, FALSE,
1169 AnyPropertyType, &u.atom_aux, &u.i,
1170 &data_length, &aux_long, &p_data);
1171 if (aux_long)
1172 WARN(event,"property too large, truncated!\n");
1173 TRACE(event,"urls=%s\n", p_data);
1175 if( !aux_long && p_data) { /* don't bother if > 64K */
1176 /* calculate length */
1177 p = p_data;
1178 next = strchr(p, '\n');
1179 while (p) {
1180 if (next) *next=0;
1181 if (strncmp(p,"file:",5) == 0 ) {
1182 INT32 len = GetShortPathName32A( p+5, NULL, 0 );
1183 if (len) drop_len += len + 1;
1185 if (next) {
1186 *next = '\n';
1187 p = next + 1;
1188 next = strchr(p, '\n');
1189 } else {
1190 p = NULL;
1194 if( drop_len && drop_len < 65535 ) {
1195 TSXQueryPointer( display, rootWindow, &u.w_aux, &u.w_aux,
1196 &x, &y, &u.i, &u.i, &u.i);
1197 pDropWnd = WIN_FindWndPtr( pWnd->hwndSelf );
1199 if (drop32) {
1200 LPDROPFILESTRUCT32 lpDrop;
1201 drop_len += sizeof(DROPFILESTRUCT32) + 1;
1202 hDrop.h32 = (HDROP32)GlobalAlloc32( GMEM_SHARE, drop_len );
1203 lpDrop = (LPDROPFILESTRUCT32) GlobalLock32( hDrop.h32 );
1205 if( lpDrop ) {
1206 lpDrop->lSize = sizeof(DROPFILESTRUCT32);
1207 lpDrop->ptMousePos.x = (INT32)x;
1208 lpDrop->ptMousePos.y = (INT32)y;
1209 lpDrop->fInNonClientArea = (BOOL32)
1210 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1211 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1212 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1213 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1214 lpDrop->fWideChar = FALSE;
1215 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT32);
1217 } else {
1218 LPDROPFILESTRUCT16 lpDrop;
1219 drop_len += sizeof(DROPFILESTRUCT16) + 1;
1220 hDrop.h16 = (HDROP16)GlobalAlloc16( GMEM_SHARE, drop_len );
1221 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop.h16 );
1223 if( lpDrop ) {
1224 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1225 lpDrop->ptMousePos.x = (INT16)x;
1226 lpDrop->ptMousePos.y = (INT16)y;
1227 lpDrop->fInNonClientArea = (BOOL16)
1228 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1229 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1230 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1231 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1232 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1236 /* create message content */
1237 if (p_drop) {
1238 p = p_data;
1239 next = strchr(p, '\n');
1240 while (p) {
1241 if (next) *next=0;
1242 if (strncmp(p,"file:",5) == 0 ) {
1243 INT32 len = GetShortPathName32A( p+5, p_drop, 65535 );
1244 if (len) {
1245 TRACE(event, "drop file %s as %s\n", p+5, p_drop);
1246 p_drop += len+1;
1247 } else {
1248 WARN(event, "can't convert file %s to dos name \n", p+5);
1250 } else {
1251 WARN(event, "unknown mime type %s\n", p);
1253 if (next) {
1254 *next = '\n';
1255 p = next + 1;
1256 next = strchr(p, '\n');
1257 } else {
1258 p = NULL;
1260 *p_drop = '\0';
1263 if (drop32) {
1264 /* can not use PostMessage32A because it is currently based on
1265 * PostMessage16 and WPARAM32 would be truncated to WPARAM16
1267 GlobalUnlock32(hDrop.h32);
1268 SendMessage32A( pWnd->hwndSelf, WM_DROPFILES,
1269 (WPARAM32)hDrop.h32, 0L );
1270 } else {
1271 GlobalUnlock16(hDrop.h16);
1272 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1273 (WPARAM16)hDrop.h16, 0L );
1277 if( p_data ) TSXFree(p_data);
1281 /**********************************************************************
1282 * EVENT_ClientMessage
1284 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event )
1286 if (event->message_type != None && event->format == 32) {
1287 if ((event->message_type == wmProtocols) &&
1288 (((Atom) event->data.l[0]) == wmDeleteWindow))
1289 SendMessage16( pWnd->hwndSelf, WM_SYSCOMMAND, SC_CLOSE, 0 );
1290 else if ( event->message_type == dndProtocol &&
1291 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
1292 EVENT_DropFromOffiX(pWnd, event);
1293 else if ( event->message_type == dndProtocol &&
1294 event->data.l[0] == DndURL )
1295 EVENT_DropURLs(pWnd, event);
1296 else {
1297 #if 0
1298 /* enable this if you want to see the message */
1299 unsigned char* p_data = NULL;
1300 union {
1301 unsigned long l;
1302 int i;
1303 Atom atom;
1304 } u; /* unused */
1305 TSXGetWindowProperty( display, DefaultRootWindow(display),
1306 dndSelection, 0, 65535, FALSE,
1307 AnyPropertyType, &u.atom, &u.i,
1308 &u.l, &u.l, &p_data);
1309 TRACE(event, "message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1310 event->message_type, event->data.l[0], event->data.l[1],
1311 event->data.l[2], event->data.l[3], event->data.l[4],
1312 p_data);
1313 #endif
1314 TRACE(event, "unrecognized ClientMessage\n" );
1319 /**********************************************************************
1320 * EVENT_EnterNotify
1322 * Install colormap when Wine window is focused in
1323 * self-managed mode with private colormap
1326 void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
1328 if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
1329 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
1330 TSXInstallColormap( display, COLOR_GetColormap() );
1334 /**********************************************************************
1335 * EVENT_MapNotify
1337 void EVENT_MapNotify( HWND32 hWnd, XMapEvent *event )
1339 HWND32 hwndFocus = GetFocus32();
1341 if (hwndFocus && IsChild32( hWnd, hwndFocus ))
1342 FOCUS_SetXFocus( (HWND32)hwndFocus );
1344 return;
1347 /**********************************************************************
1348 * EVENT_Capture
1350 * We need this to be able to generate double click messages
1351 * when menu code captures mouse in the window without CS_DBLCLK style.
1353 HWND32 EVENT_Capture(HWND32 hwnd, INT16 ht)
1355 HWND32 capturePrev = captureWnd;
1357 if (!hwnd)
1359 captureWnd = 0L;
1360 captureHT = 0;
1362 else
1364 WND* wndPtr = WIN_FindWndPtr( hwnd );
1365 if (wndPtr)
1367 TRACE(win, "(0x%04x)\n", hwnd );
1368 captureWnd = hwnd;
1369 captureHT = ht;
1373 if( capturePrev && capturePrev != captureWnd )
1375 WND* wndPtr = WIN_FindWndPtr( capturePrev );
1376 if( wndPtr && (wndPtr->flags & WIN_ISWIN32) )
1377 SendMessage32A( capturePrev, WM_CAPTURECHANGED, 0L, hwnd);
1379 return capturePrev;
1382 /**********************************************************************
1383 * EVENT_GetCaptureInfo
1385 INT16 EVENT_GetCaptureInfo()
1387 return captureHT;
1390 /**********************************************************************
1391 * SetCapture16 (USER.18)
1393 HWND16 WINAPI SetCapture16( HWND16 hwnd )
1395 return (HWND16)EVENT_Capture( hwnd, HTCLIENT );
1399 /**********************************************************************
1400 * SetCapture32 (USER32.464)
1402 HWND32 WINAPI SetCapture32( HWND32 hwnd )
1404 return EVENT_Capture( hwnd, HTCLIENT );
1408 /**********************************************************************
1409 * ReleaseCapture (USER.19) (USER32.439)
1411 void WINAPI ReleaseCapture(void)
1413 TRACE(win, "captureWnd=%04x\n", captureWnd );
1414 if( captureWnd ) EVENT_Capture( 0, 0 );
1418 /**********************************************************************
1419 * GetCapture16 (USER.236)
1421 HWND16 WINAPI GetCapture16(void)
1423 return captureWnd;
1427 /**********************************************************************
1428 * GetCapture32 (USER32.208)
1430 HWND32 WINAPI GetCapture32(void)
1432 return captureWnd;
1437 /***********************************************************************
1438 * Mouse driver routines:
1441 #pragma pack(1)
1442 typedef struct _MOUSEINFO
1444 BYTE msExist;
1445 BYTE msRelative;
1446 WORD msNumButtons;
1447 WORD msRate;
1448 WORD msXThreshold;
1449 WORD msYThreshold;
1450 WORD msXRes;
1451 WORD msYRes;
1452 WORD msMouseCommPort;
1453 } MOUSEINFO;
1454 #pragma pack(4)
1456 static SEGPTR MouseEventProc = 0;
1458 /***********************************************************************
1459 * MouseInquire (MOUSE.1)
1462 WORD WINAPI MouseInquire(MOUSEINFO *mouseInfo)
1464 mouseInfo->msExist = TRUE;
1465 mouseInfo->msRelative = FALSE;
1466 mouseInfo->msNumButtons = 2;
1467 mouseInfo->msRate = 34; /* the DDK says so ... */
1468 mouseInfo->msXThreshold = 0;
1469 mouseInfo->msYThreshold = 0;
1470 mouseInfo->msXRes = 0;
1471 mouseInfo->msYRes = 0;
1472 mouseInfo->msMouseCommPort = 0;
1474 return sizeof(MOUSEINFO);
1477 /***********************************************************************
1478 * MouseEnable (MOUSE.2)
1480 VOID WINAPI MouseEnable(SEGPTR eventProc)
1482 MouseEventProc = eventProc;
1485 /***********************************************************************
1486 * MouseDisable (MOUSE.3)
1488 VOID WINAPI MouseDisable(VOID)
1490 MouseEventProc = 0;
1493 /***********************************************************************
1494 * EVENT_SendMouseEvent
1496 static void EVENT_SendMouseEvent( WORD mouseStatus, WORD deltaX, WORD deltaY,
1497 WORD buttonCount, DWORD extraInfo )
1499 CONTEXT context;
1501 if ( !MouseEventProc ) return;
1503 TRACE( keyboard, "(%04X,%d,%d,%d,%ld)\n", mouseStatus, deltaX, deltaY, buttonCount, extraInfo );
1505 mouseStatus |= 0x8000;
1506 deltaX = (((long)deltaX << 16) + screenWidth/2) / screenWidth;
1507 deltaY = (((long)deltaY << 16) + screenHeight/2) / screenHeight;
1509 memset( &context, 0, sizeof(context) );
1510 CS_reg(&context) = SELECTOROF( MouseEventProc );
1511 EIP_reg(&context) = OFFSETOF( MouseEventProc );
1512 EAX_reg(&context) = mouseStatus;
1513 EBX_reg(&context) = deltaX;
1514 ECX_reg(&context) = deltaY;
1515 EDX_reg(&context) = buttonCount;
1516 ESI_reg(&context) = LOWORD( extraInfo );
1517 EDI_reg(&context) = HIWORD( extraInfo );
1519 Callbacks->CallRegisterShortProc( &context, 0 );
1525 /***********************************************************************
1526 * GetMouseEventProc (USER.337)
1528 FARPROC16 WINAPI GetMouseEventProc(void)
1530 HMODULE16 hmodule = GetModuleHandle16("USER");
1531 return NE_GetEntryPoint( hmodule, NE_GetOrdinal( hmodule, "Mouse_Event" ));
1535 /***********************************************************************
1536 * Mouse_Event (USER.299)
1538 void WINAPI Mouse_Event( CONTEXT *context )
1540 /* Register values:
1541 * AX = mouse event
1542 * BX = horizontal displacement if AX & ME_MOVE
1543 * CX = vertical displacement if AX & ME_MOVE
1544 * DX = button state (?)
1545 * SI = mouse event flags (?)
1547 Window root, child;
1548 int rootX, rootY, winX, winY;
1549 unsigned int state;
1551 if (AX_reg(context) & ME_MOVE)
1553 /* We have to actually move the cursor */
1554 TSXWarpPointer( display, rootWindow, None, 0, 0, 0, 0,
1555 (short)BX_reg(context), (short)CX_reg(context) );
1556 return;
1558 if (!TSXQueryPointer( display, rootWindow, &root, &child,
1559 &rootX, &rootY, &winX, &winY, &state )) return;
1560 if (AX_reg(context) & ME_LDOWN)
1561 hardware_event( WM_LBUTTONDOWN, EVENT_XStateToKeyState( state ),
1562 0L, winX, winY, GetTickCount(), 0 );
1563 if (AX_reg(context) & ME_LUP)
1564 hardware_event( WM_LBUTTONUP, EVENT_XStateToKeyState( state ),
1565 0L, winX, winY, GetTickCount(), 0 );
1566 if (AX_reg(context) & ME_RDOWN)
1567 hardware_event( WM_RBUTTONDOWN, EVENT_XStateToKeyState( state ),
1568 0L, winX, winY, GetTickCount(), 0 );
1569 if (AX_reg(context) & ME_RUP)
1570 hardware_event( WM_RBUTTONUP, EVENT_XStateToKeyState( state ),
1571 0L, winX, winY, GetTickCount(), 0 );
1575 /**********************************************************************
1576 * EnableHardwareInput (USER.331)
1578 BOOL16 WINAPI EnableHardwareInput(BOOL16 bEnable)
1580 BOOL16 bOldState = InputEnabled;
1581 FIXME(event,"(%d) - stub\n", bEnable);
1582 InputEnabled = bEnable;
1583 return bOldState;
1587 /***********************************************************************
1588 * SwapMouseButton16 (USER.186)
1590 BOOL16 WINAPI SwapMouseButton16( BOOL16 fSwap )
1592 BOOL16 ret = SwappedButtons;
1593 SwappedButtons = fSwap;
1594 return ret;
1598 /***********************************************************************
1599 * SwapMouseButton32 (USER32.537)
1601 BOOL32 WINAPI SwapMouseButton32( BOOL32 fSwap )
1603 BOOL32 ret = SwappedButtons;
1604 SwappedButtons = fSwap;
1605 return ret;