Added indirection for ctx_debug to the DOS loader, so Winelib works
[wine/multimedia.git] / windows / event.c
blob4ec26dd5db64f9a0186c9259208e0455776d51fd
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 /* X context to associate a hwnd to an X window */
60 static XContext winContext = 0;
62 static INT16 captureHT = HTCLIENT;
63 static HWND32 captureWnd = 0;
64 static BOOL32 InputEnabled = TRUE;
65 static BOOL32 SwappedButtons = FALSE;
67 static Atom wmProtocols = None;
68 static Atom wmDeleteWindow = None;
69 static Atom dndProtocol = None;
70 static Atom dndSelection = None;
72 /* EVENT_WaitNetEvent() master fd sets */
74 static fd_set __event_io_set[3];
75 static int __event_max_fd = 0;
76 static int __event_x_connection = 0;
78 static const char * const event_names[] =
80 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
81 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
82 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
83 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
84 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
85 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
86 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
87 "ClientMessage", "MappingNotify"
90 /* Event handlers */
91 static void EVENT_Key( WND *pWnd, XKeyEvent *event );
92 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event );
93 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event );
94 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event );
95 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event );
96 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event );
97 static void EVENT_Expose( WND *pWnd, XExposeEvent *event );
98 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event );
99 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event );
100 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event);
101 static void EVENT_SelectionNotify( XSelectionEvent *event);
102 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event);
103 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event );
104 static void EVENT_MapNotify( HWND32 hwnd, XMapEvent *event );
106 /* Usable only with OLVWM - compile option perhaps?
107 static void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event );
110 static void EVENT_SendMouseEvent( WORD mouseStatus, WORD deltaX, WORD deltaY,
111 WORD buttonCount, DWORD extraInfo );
113 /***********************************************************************
114 * EVENT_Init
116 * Initialize network IO.
118 BOOL32 EVENT_Init(void)
120 int i;
121 for( i = 0; i < 3; i++ )
122 FD_ZERO( __event_io_set + i );
124 __event_max_fd = __event_x_connection = ConnectionNumber(display);
125 FD_SET( __event_x_connection, &__event_io_set[EVENT_IO_READ] );
126 __event_max_fd++;
127 return TRUE;
130 /***********************************************************************
131 * EVENT_AddIO
133 void EVENT_AddIO( int fd, unsigned io_type )
135 FD_SET( fd, &__event_io_set[io_type] );
136 if( __event_max_fd <= fd ) __event_max_fd = fd + 1;
139 void EVENT_DeleteIO( int fd, unsigned io_type )
141 FD_CLR( fd, &__event_io_set[io_type] );
144 /***********************************************************************
145 * EVENT_ProcessEvent
147 * Process an X event.
149 void EVENT_ProcessEvent( XEvent *event )
151 WND *pWnd;
153 if (TSXFindContext( display, event->xany.window, winContext,
154 (char **)&pWnd ) != 0)
155 return; /* Not for a registered window */
157 TRACE(event, "Got event %s for hwnd %04x\n",
158 event_names[event->type], pWnd->hwndSelf );
160 switch(event->type)
162 case KeyPress:
163 case KeyRelease:
164 if (InputEnabled) EVENT_Key( pWnd, (XKeyEvent*)event );
165 break;
167 case ButtonPress:
168 if (InputEnabled)
169 EVENT_ButtonPress( pWnd, (XButtonEvent*)event );
170 break;
172 case ButtonRelease:
173 if (InputEnabled)
174 EVENT_ButtonRelease( pWnd, (XButtonEvent*)event );
175 break;
177 case MotionNotify:
178 /* Wine between two fast machines across the overloaded campus
179 ethernet gets very boged down in MotionEvents. The following
180 simply finds the last motion event in the queue and drops
181 the rest. On a good link events are servered before they build
182 up so this doesn't take place. On a slow link this may cause
183 problems if the event order is important. I'm not yet seen
184 of any problems. Jon 7/6/96.
186 if (InputEnabled)
188 while (TSXCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
189 MotionNotify, event));
190 EVENT_MotionNotify( pWnd, (XMotionEvent*)event );
192 break;
194 case FocusIn:
195 EVENT_FocusIn( pWnd, (XFocusChangeEvent*)event );
196 break;
198 case FocusOut:
199 EVENT_FocusOut( pWnd, (XFocusChangeEvent*)event );
200 break;
202 case Expose:
203 EVENT_Expose( pWnd, (XExposeEvent *)event );
204 break;
206 case GraphicsExpose:
207 EVENT_GraphicsExpose( pWnd, (XGraphicsExposeEvent *)event );
208 break;
210 case ConfigureNotify:
211 EVENT_ConfigureNotify( pWnd, (XConfigureEvent*)event );
212 break;
214 case SelectionRequest:
215 EVENT_SelectionRequest( pWnd, (XSelectionRequestEvent *)event );
216 break;
218 case SelectionNotify:
219 EVENT_SelectionNotify( (XSelectionEvent *)event );
220 break;
222 case SelectionClear:
223 EVENT_SelectionClear( pWnd, (XSelectionClearEvent*) event );
224 break;
226 case ClientMessage:
227 EVENT_ClientMessage( pWnd, (XClientMessageEvent *) event );
228 break;
230 /* case EnterNotify:
231 * EVENT_EnterNotify( pWnd, (XCrossingEvent *) event );
232 * break;
234 case NoExpose:
235 break;
237 /* We get all these because of StructureNotifyMask. */
238 case UnmapNotify:
239 case CirculateNotify:
240 case CreateNotify:
241 case DestroyNotify:
242 case GravityNotify:
243 case ReparentNotify:
244 break;
246 case MapNotify:
247 EVENT_MapNotify( pWnd->hwndSelf, (XMapEvent *)event );
248 break;
250 default:
251 WARN(event, "Unprocessed event %s for hwnd %04x\n",
252 event_names[event->type], pWnd->hwndSelf );
253 break;
258 /***********************************************************************
259 * EVENT_RegisterWindow
261 * Associate an X window to a HWND.
263 void EVENT_RegisterWindow( WND *pWnd )
265 if (wmProtocols == None)
266 wmProtocols = TSXInternAtom( display, "WM_PROTOCOLS", True );
267 if (wmDeleteWindow == None)
268 wmDeleteWindow = TSXInternAtom( display, "WM_DELETE_WINDOW", True );
269 if( dndProtocol == None )
270 dndProtocol = TSXInternAtom( display, "DndProtocol" , False );
271 if( dndSelection == None )
272 dndSelection = TSXInternAtom( display, "DndSelection" , False );
274 TSXSetWMProtocols( display, pWnd->window, &wmDeleteWindow, 1 );
276 if (!winContext) winContext = TSXUniqueContext();
277 TSXSaveContext( display, pWnd->window, winContext, (char *)pWnd );
280 /***********************************************************************
281 * EVENT_DestroyWindow
283 void EVENT_DestroyWindow( WND *pWnd )
285 XEvent xe;
287 TSXDeleteContext( display, pWnd->window, winContext );
288 TSXDestroyWindow( display, pWnd->window );
289 while( TSXCheckWindowEvent(display, pWnd->window, NoEventMask, &xe) );
293 /***********************************************************************
294 * IsUserIdle (USER.333)
296 * Check if we have pending X events.
298 BOOL16 WINAPI IsUserIdle(void)
300 struct timeval timeout = {0, 0};
301 fd_set check_set;
303 FD_ZERO(&check_set);
304 FD_SET(__event_x_connection, &check_set);
305 if( select(__event_x_connection + 1, &check_set, NULL, NULL, &timeout) > 0 )
306 return TRUE;
307 return FALSE;
311 /***********************************************************************
312 * EVENT_WaitNetEvent
314 * Wait for a network event, optionally sleeping until one arrives.
315 * Return TRUE if an event is pending, FALSE on timeout or error
316 * (for instance lost connection with the server).
318 BOOL32 EVENT_WaitNetEvent( BOOL32 sleep, BOOL32 peek )
320 XEvent event;
321 LONG maxWait = sleep ? TIMER_GetNextExpiration() : 0;
322 int pending = TSXPending(display);
324 /* Wait for an event or a timeout. If maxWait is -1, we have no timeout;
325 * in this case, we fall through directly to the XNextEvent loop.
328 if ((maxWait != -1) && !pending)
330 int num_pending;
331 struct timeval timeout;
332 fd_set io_set[3];
334 memcpy( io_set, __event_io_set, sizeof(io_set) );
336 timeout.tv_usec = (maxWait % 1000) * 1000;
337 timeout.tv_sec = maxWait / 1000;
339 #ifdef CONFIG_IPC
340 sigsetjmp(env_wait_x, 1);
341 stop_wait_op= CONT;
343 if (DDE_GetRemoteMessage()) {
344 while(DDE_GetRemoteMessage())
346 return TRUE;
348 stop_wait_op = STOP_WAIT_X;
349 /* The code up to the next "stop_wait_op = CONT" must be reentrant */
350 num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
351 &io_set[EVENT_IO_WRITE],
352 &io_set[EVENT_IO_EXCEPT], &timeout );
353 if ( num_pending == 0 )
355 stop_wait_op = CONT;
356 TIMER_ExpireTimers();
357 return FALSE;
359 else stop_wait_op = CONT;
360 #else /* CONFIG_IPC */
361 num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
362 &io_set[EVENT_IO_WRITE],
363 &io_set[EVENT_IO_EXCEPT], &timeout );
364 if ( num_pending == 0)
366 /* Timeout or error */
367 TIMER_ExpireTimers();
368 return FALSE;
370 #endif /* CONFIG_IPC */
372 /* Winsock asynchronous services */
374 if( FD_ISSET( __event_x_connection, &io_set[EVENT_IO_READ]) )
376 num_pending--;
377 if( num_pending )
378 WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
380 else /* no X events */
381 return WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
383 else if(!pending)
384 { /* Wait for X11 input. */
385 fd_set set;
387 FD_ZERO(&set);
388 FD_SET(__event_x_connection, &set);
389 select(__event_x_connection + 1, &set, 0, 0, 0 );
392 /* Process current X event (and possibly others that occurred in the meantime) */
394 EnterCriticalSection(&X11DRV_CritSection);
395 while (XPending( display ))
398 #ifdef CONFIG_IPC
399 if (DDE_GetRemoteMessage())
401 LeaveCriticalSection(&X11DRV_CritSection);
402 while(DDE_GetRemoteMessage()) ;
403 return TRUE;
405 #endif /* CONFIG_IPC */
407 XNextEvent( display, &event );
409 LeaveCriticalSection(&X11DRV_CritSection);
410 if( peek )
412 WND* pWnd;
413 MESSAGEQUEUE* pQ;
415 if (TSXFindContext( display, ((XAnyEvent *)&event)->window, winContext,
416 (char **)&pWnd ) || (event.type == NoExpose))
417 continue;
419 /* Check only for those events which can be processed
420 * internally. */
422 if( event.type == MotionNotify ||
423 event.type == ButtonPress || event.type == ButtonRelease ||
424 event.type == KeyPress || event.type == KeyRelease ||
425 event.type == SelectionRequest || event.type == SelectionClear )
427 EVENT_ProcessEvent( &event );
428 continue;
431 if( pWnd )
433 if( (pQ = (MESSAGEQUEUE*)GlobalLock16(pWnd->hmemTaskQ)) )
435 pQ->flags |= QUEUE_FLAG_XEVENT;
436 PostEvent(pQ->hTask);
437 TSXPutBackEvent(display, &event);
438 break;
442 else EVENT_ProcessEvent( &event );
443 EnterCriticalSection(&X11DRV_CritSection);
445 LeaveCriticalSection(&X11DRV_CritSection);
446 return TRUE;
450 /***********************************************************************
451 * EVENT_Synchronize
453 * Synchronize with the X server. Should not be used too often.
455 void EVENT_Synchronize()
457 XEvent event;
459 /* Use of the X critical section is needed or we have a small
460 * race between XPending() and XNextEvent().
462 EnterCriticalSection( &X11DRV_CritSection );
463 XSync( display, False );
464 while (XPending( display ))
466 XNextEvent( display, &event );
467 /* unlock X critsection for EVENT_ProcessEvent() might switch tasks */
468 LeaveCriticalSection( &X11DRV_CritSection );
469 EVENT_ProcessEvent( &event );
470 EnterCriticalSection( &X11DRV_CritSection );
472 LeaveCriticalSection( &X11DRV_CritSection );
475 /***********************************************************************
476 * EVENT_QueryZOrder
478 * Try to synchronize internal z-order with the window manager's.
479 * Probably a futile endeavor.
481 static BOOL32 __check_query_condition( WND** pWndA, WND** pWndB )
483 /* return TRUE if we have at least two managed windows */
485 for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
486 if( (*pWndA)->flags & WIN_MANAGED &&
487 (*pWndA)->dwStyle & WS_VISIBLE ) break;
488 if( *pWndA )
489 for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
490 if( (*pWndB)->flags & WIN_MANAGED &&
491 (*pWndB)->dwStyle & WS_VISIBLE ) break;
492 return ((*pWndB) != NULL);
495 static Window __get_common_ancestor( Window A, Window B,
496 Window** children, unsigned* total )
498 /* find the real root window */
500 Window root, *childrenB;
501 unsigned totalB;
505 if( *children ) TSXFree( *children );
506 TSXQueryTree( display, A, &root, &A, children, total );
507 TSXQueryTree( display, B, &root, &B, &childrenB, &totalB );
508 if( childrenB ) TSXFree( childrenB );
509 } while( A != B && A && B );
510 return ( A && B ) ? A : 0 ;
513 static Window __get_top_decoration( Window w, Window ancestor )
515 Window* children, root, prev = w, parent = w;
516 unsigned total;
520 w = parent;
521 TSXQueryTree( display, w, &root, &parent, &children, &total );
522 if( children ) TSXFree( children );
523 } while( parent && parent != ancestor );
524 TRACE(event, "\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
525 return ( parent ) ? w : 0 ;
528 static unsigned __td_lookup( Window w, Window* list, unsigned max )
530 unsigned i;
531 for( i = 0; i < max; i++ ) if( list[i] == w ) break;
532 return i;
535 static BOOL32 EVENT_QueryZOrder( WND* pWndCheck )
537 BOOL32 bRet = FALSE;
538 HWND32 hwndInsertAfter = HWND_TOP;
539 WND* pWnd, *pWndZ = WIN_GetDesktop()->child;
540 Window w, parent, *children = NULL;
541 unsigned total, check, pos, best;
543 if( !__check_query_condition(&pWndZ, &pWnd) ) return TRUE;
545 parent = __get_common_ancestor( pWndZ->window, pWnd->window,
546 &children, &total );
547 if( parent && children )
549 w = __get_top_decoration( pWndCheck->window, parent );
550 if( w != children[total - 1] )
552 check = __td_lookup( w, children, total );
553 best = total;
554 for( pWnd = pWndZ; pWnd; pWnd = pWnd->next )
556 if( pWnd != pWndCheck )
558 if( !(pWnd->flags & WIN_MANAGED) ||
559 !(w = __get_top_decoration( pWnd->window, parent )) )
560 continue;
561 pos = __td_lookup( w, children, total );
562 if( pos < best && pos > check )
564 best = pos;
565 hwndInsertAfter = pWnd->hwndSelf;
567 if( check - best == 1 ) break;
570 WIN_UnlinkWindow( pWndCheck->hwndSelf );
571 WIN_LinkWindow( pWndCheck->hwndSelf, hwndInsertAfter);
574 if( children ) TSXFree( children );
575 return bRet;
579 /***********************************************************************
580 * EVENT_XStateToKeyState
582 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
583 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
585 static WORD EVENT_XStateToKeyState( int state )
587 int kstate = 0;
589 if (state & Button1Mask) kstate |= MK_LBUTTON;
590 if (state & Button2Mask) kstate |= MK_MBUTTON;
591 if (state & Button3Mask) kstate |= MK_RBUTTON;
592 if (state & ShiftMask) kstate |= MK_SHIFT;
593 if (state & ControlMask) kstate |= MK_CONTROL;
594 return kstate;
598 /***********************************************************************
599 * EVENT_Expose
601 static void EVENT_Expose( WND *pWnd, XExposeEvent *event )
603 RECT32 rect;
605 /* Make position relative to client area instead of window */
606 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
607 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
608 rect.right = rect.left + event->width;
609 rect.bottom = rect.top + event->height;
611 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
612 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
613 (event->count ? 0 : RDW_ERASENOW), 0 );
617 /***********************************************************************
618 * EVENT_GraphicsExpose
620 * This is needed when scrolling area is partially obscured
621 * by non-Wine X window.
623 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event )
625 RECT32 rect;
627 /* Make position relative to client area instead of window */
628 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
629 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
630 rect.right = rect.left + event->width;
631 rect.bottom = rect.top + event->height;
633 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
634 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
635 (event->count ? 0 : RDW_ERASENOW), 0 );
639 /***********************************************************************
640 * EVENT_Key
642 * Handle a X key event
644 static void EVENT_Key( WND *pWnd, XKeyEvent *event )
646 KEYBOARD_HandleEvent( pWnd, event );
650 /***********************************************************************
651 * EVENT_MotionNotify
653 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event )
655 hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ), 0L,
656 pWnd->rectWindow.left + event->x,
657 pWnd->rectWindow.top + event->y,
658 event->time - MSG_WineStartTicks, pWnd->hwndSelf );
660 EVENT_SendMouseEvent( ME_MOVE,
661 pWnd->rectWindow.left + event->x,
662 pWnd->rectWindow.top + event->y,
663 0, 0 );
667 /***********************************************************************
668 * EVENT_DummyMotionNotify
670 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
672 void EVENT_DummyMotionNotify(void)
674 Window root, child;
675 int rootX, rootY, winX, winY;
676 unsigned int state;
678 if (TSXQueryPointer( display, rootWindow, &root, &child,
679 &rootX, &rootY, &winX, &winY, &state ))
681 hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( state ), 0L,
682 winX, winY, GetTickCount(), 0 );
687 /***********************************************************************
688 * EVENT_ButtonPress
690 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event )
692 static WORD messages[NB_BUTTONS] =
693 { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
694 static WORD statusCodes[NB_BUTTONS] =
695 { ME_LDOWN, 0, ME_RDOWN };
696 int buttonNum = event->button - 1;
698 if (buttonNum >= NB_BUTTONS) return;
699 if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
700 MouseButtonsStates[buttonNum] = TRUE;
701 AsyncMouseButtonsStates[buttonNum] = TRUE;
702 hardware_event( messages[buttonNum],
703 EVENT_XStateToKeyState( event->state ), 0L,
704 pWnd->rectWindow.left + event->x,
705 pWnd->rectWindow.top + event->y,
706 event->time - MSG_WineStartTicks, pWnd->hwndSelf );
708 EVENT_SendMouseEvent( statusCodes[buttonNum],
709 pWnd->rectWindow.left + event->x,
710 pWnd->rectWindow.top + event->y,
711 0, 0 );
715 /***********************************************************************
716 * EVENT_ButtonRelease
718 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event )
720 static const WORD messages[NB_BUTTONS] =
721 { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
722 static WORD statusCodes[NB_BUTTONS] =
723 { ME_LUP, 0, ME_RUP };
724 int buttonNum = event->button - 1;
726 if (buttonNum >= NB_BUTTONS) return;
727 if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
728 MouseButtonsStates[buttonNum] = FALSE;
729 hardware_event( messages[buttonNum],
730 EVENT_XStateToKeyState( event->state ), 0L,
731 pWnd->rectWindow.left + event->x,
732 pWnd->rectWindow.top + event->y,
733 event->time - MSG_WineStartTicks, pWnd->hwndSelf );
735 EVENT_SendMouseEvent( statusCodes[buttonNum],
736 pWnd->rectWindow.left + event->x,
737 pWnd->rectWindow.top + event->y,
738 0, 0 );
742 /**********************************************************************
743 * EVENT_FocusIn
745 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event )
747 if (Options.managed) EVENT_QueryZOrder( pWnd );
749 if (event->detail != NotifyPointer)
751 HWND32 hwnd = pWnd->hwndSelf;
753 if (hwnd != GetActiveWindow32())
755 WINPOS_ChangeActiveWindow( hwnd, FALSE );
756 KEYBOARD_UpdateState();
758 if ((hwnd != GetFocus32()) && !IsChild32( hwnd, GetFocus32()))
759 SetFocus32( hwnd );
764 /**********************************************************************
765 * EVENT_FocusOut
767 * Note: only top-level override-redirect windows get FocusOut events.
769 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event )
771 if (event->detail != NotifyPointer)
773 HWND32 hwnd = pWnd->hwndSelf;
775 if (hwnd == GetActiveWindow32())
776 WINPOS_ChangeActiveWindow( 0, FALSE );
777 if ((hwnd == GetFocus32()) || IsChild32( hwnd, GetFocus32()))
778 SetFocus32( 0 );
782 /**********************************************************************
783 * EVENT_CheckFocus
785 BOOL32 EVENT_CheckFocus(void)
787 WND* pWnd;
788 Window xW;
789 int state;
791 TSXGetInputFocus(display, &xW, &state);
792 if( xW == None ||
793 TSXFindContext(display, xW, winContext, (char **)&pWnd) )
794 return FALSE;
795 return TRUE;
799 /**********************************************************************
800 * EVENT_GetGeometry
802 * Helper function for ConfigureNotify handling.
803 * Get the new geometry of a window relative to the root window.
805 static void EVENT_GetGeometry( Window win, int *px, int *py,
806 unsigned int *pwidth, unsigned int *pheight )
808 Window root, parent, *children;
809 int xpos, ypos;
810 unsigned int width, height, border, depth, nb_children;
812 if (!TSXGetGeometry( display, win, &root, px, py, pwidth, pheight,
813 &border, &depth )) return;
814 if (win == rootWindow)
816 *px = *py = 0;
817 return;
820 for (;;)
822 if (!TSXQueryTree(display, win, &root, &parent, &children, &nb_children))
823 return;
824 TSXFree( children );
825 if (parent == rootWindow) break;
826 win = parent;
827 if (!TSXGetGeometry( display, win, &root, &xpos, &ypos,
828 &width, &height, &border, &depth )) return;
829 *px += xpos;
830 *py += ypos;
835 /**********************************************************************
836 * EVENT_ConfigureNotify
838 * The ConfigureNotify event is only selected on top-level windows
839 * when the -managed flag is used.
841 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event )
843 WINDOWPOS32 winpos;
844 RECT32 newWindowRect, newClientRect;
845 HRGN32 hrgnOldPos, hrgnNewPos;
846 Window above = event->above;
847 int x, y;
848 unsigned int width, height;
850 assert (pWnd->flags & WIN_MANAGED);
852 /* We don't rely on the event geometry info, because it is relative
853 * to parent and not to root, and it may be wrong (XFree sets x,y to 0,0
854 * if the window hasn't moved).
856 EVENT_GetGeometry( event->window, &x, &y, &width, &height );
858 /* Fill WINDOWPOS struct */
859 winpos.flags = SWP_NOACTIVATE | SWP_NOZORDER;
860 winpos.hwnd = pWnd->hwndSelf;
861 winpos.x = x;
862 winpos.y = y;
863 winpos.cx = width;
864 winpos.cy = height;
866 /* Check for unchanged attributes */
867 if (winpos.x == pWnd->rectWindow.left && winpos.y == pWnd->rectWindow.top)
868 winpos.flags |= SWP_NOMOVE;
869 if ((winpos.cx == pWnd->rectWindow.right - pWnd->rectWindow.left) &&
870 (winpos.cy == pWnd->rectWindow.bottom - pWnd->rectWindow.top))
871 winpos.flags |= SWP_NOSIZE;
872 else
874 RECT32 rect = { 0, 0, pWnd->rectWindow.right - pWnd->rectWindow.left,
875 pWnd->rectWindow.bottom - pWnd->rectWindow.top };
876 DCE_InvalidateDCE( pWnd, &rect );
879 /* Send WM_WINDOWPOSCHANGING */
880 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)&winpos );
882 /* Calculate new position and size */
883 newWindowRect.left = x;
884 newWindowRect.right = x + width;
885 newWindowRect.top = y;
886 newWindowRect.bottom = y + height;
888 WINPOS_SendNCCalcSize( winpos.hwnd, TRUE, &newWindowRect,
889 &pWnd->rectWindow, &pWnd->rectClient,
890 &winpos, &newClientRect );
892 hrgnOldPos = CreateRectRgnIndirect32( &pWnd->rectWindow );
893 hrgnNewPos = CreateRectRgnIndirect32( &newWindowRect );
894 CombineRgn32( hrgnOldPos, hrgnOldPos, hrgnNewPos, RGN_DIFF );
895 DeleteObject32(hrgnOldPos);
896 DeleteObject32(hrgnNewPos);
898 /* Set new size and position */
899 pWnd->rectWindow = newWindowRect;
900 pWnd->rectClient = newClientRect;
901 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)&winpos );
903 if (!IsWindow32( winpos.hwnd )) return;
904 if( above == None ) /* absolute bottom */
906 WIN_UnlinkWindow( winpos.hwnd );
907 WIN_LinkWindow( winpos.hwnd, HWND_BOTTOM);
909 else EVENT_QueryZOrder( pWnd ); /* try to outsmart window manager */
913 /***********************************************************************
914 * EVENT_SelectionRequest
916 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event )
918 XSelectionEvent result;
919 Atom rprop = None;
920 Window request = event->requestor;
922 if(event->target == XA_STRING)
924 HANDLE16 hText;
925 LPSTR text;
926 int size,i,j;
928 rprop = event->property;
930 if(rprop == None) rprop = event->target;
932 if(event->selection!=XA_PRIMARY) rprop = None;
933 else if(!CLIPBOARD_IsPresent(CF_OEMTEXT)) rprop = None;
934 else
936 /* open to make sure that clipboard is available */
938 BOOL32 couldOpen = OpenClipboard32( pWnd->hwndSelf );
939 char* lpstr = 0;
941 hText = GetClipboardData16(CF_TEXT);
942 text = GlobalLock16(hText);
943 size = GlobalSize16(hText);
945 /* remove carriage returns */
947 lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
948 for(i=0,j=0; i < size && text[i]; i++ )
950 if( text[i] == '\r' &&
951 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
952 lpstr[j++] = text[i];
954 lpstr[j]='\0';
956 TSXChangeProperty(display, request, rprop,
957 XA_STRING, 8, PropModeReplace,
958 lpstr, j);
959 HeapFree( GetProcessHeap(), 0, lpstr );
961 /* close only if we opened before */
963 if(couldOpen) CloseClipboard32();
967 if(rprop == None)
968 TRACE(event,"Request for %s ignored\n", TSXGetAtomName(display,event->target));
970 result.type = SelectionNotify;
971 result.display = display;
972 result.requestor = request;
973 result.selection = event->selection;
974 result.property = rprop;
975 result.target = event->target;
976 result.time = event->time;
977 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
981 /***********************************************************************
982 * EVENT_SelectionNotify
984 static void EVENT_SelectionNotify( XSelectionEvent *event )
986 if (event->selection != XA_PRIMARY) return;
988 if (event->target != XA_STRING) CLIPBOARD_ReadSelection( 0, None );
989 else CLIPBOARD_ReadSelection( event->requestor, event->property );
991 TRACE(clipboard,"\tSelectionNotify done!\n");
995 /***********************************************************************
996 * EVENT_SelectionClear
998 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event )
1000 if (event->selection != XA_PRIMARY) return;
1001 CLIPBOARD_ReleaseSelection( event->window, pWnd->hwndSelf );
1005 /**********************************************************************
1006 * EVENT_ClientMessage
1008 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event )
1010 if (event->message_type != None && event->format == 32)
1012 if ((event->message_type == wmProtocols) &&
1013 (((Atom) event->data.l[0]) == wmDeleteWindow))
1014 SendMessage16( pWnd->hwndSelf, WM_SYSCOMMAND, SC_CLOSE, 0 );
1015 else if ( event->message_type == dndProtocol &&
1016 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
1018 unsigned long data_length;
1019 unsigned long aux_long;
1020 unsigned char* p_data = NULL;
1021 union {
1022 Atom atom_aux;
1023 POINT32 pt_aux;
1024 int i;
1025 } u;
1026 int x, y;
1027 BOOL16 bAccept;
1028 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
1029 LPDRAGINFO lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
1030 SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
1031 Window w_aux_root, w_aux_child;
1032 WND* pDropWnd;
1034 if( !lpDragInfo || !spDragInfo ) return;
1036 TSXQueryPointer( display, pWnd->window, &w_aux_root, &w_aux_child,
1037 &x, &y, &u.pt_aux.x, &u.pt_aux.y, (unsigned int*)&aux_long);
1039 lpDragInfo->hScope = pWnd->hwndSelf;
1040 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1042 /* find out drop point and drop window */
1043 if( x < 0 || y < 0 ||
1044 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1045 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1046 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1047 else
1049 bAccept = DRAG_QueryUpdate( pWnd->hwndSelf, spDragInfo, TRUE );
1050 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1052 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1053 GlobalFree16( hDragInfo );
1055 if( bAccept )
1057 TSXGetWindowProperty( display, DefaultRootWindow(display),
1058 dndSelection, 0, 65535, FALSE,
1059 AnyPropertyType, &u.atom_aux, &u.pt_aux.y,
1060 &data_length, &aux_long, &p_data);
1062 if( !aux_long && p_data) /* don't bother if > 64K */
1064 char *p = (char*) p_data;
1065 char *p_drop;
1067 aux_long = 0;
1068 while( *p ) /* calculate buffer size */
1070 p_drop = p;
1071 if((u.i = *p) != -1 )
1072 u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
1073 if( u.i == -1 ) *p = -1; /* mark as "bad" */
1074 else
1076 INT32 len = GetShortPathName32A( p, NULL, 0 );
1077 if (len) aux_long += len + 1;
1078 else *p = -1;
1080 p += strlen(p) + 1;
1082 if( aux_long && aux_long < 65535 )
1084 HDROP16 hDrop;
1085 LPDROPFILESTRUCT lpDrop;
1087 aux_long += sizeof(DROPFILESTRUCT) + 1;
1088 hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
1089 lpDrop = (LPDROPFILESTRUCT) GlobalLock16( hDrop );
1091 if( lpDrop )
1093 lpDrop->wSize = sizeof(DROPFILESTRUCT);
1094 lpDrop->ptMousePos.x = (INT16)x;
1095 lpDrop->ptMousePos.y = (INT16)y;
1096 lpDrop->fInNonClientArea = (BOOL16)
1097 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1098 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1099 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1100 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1101 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT);
1102 p = p_data;
1103 while(*p)
1105 if( *p != -1 ) /* use only "good" entries */
1107 GetShortPathName32A( p, p_drop, 65535 );
1108 p_drop += strlen( p_drop ) + 1;
1110 p += strlen(p) + 1;
1112 *p_drop = '\0';
1113 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1114 (WPARAM16)hDrop, 0L );
1118 if( p_data ) TSXFree(p_data);
1120 } /* WS_EX_ACCEPTFILES */
1121 } /* dndProtocol */
1122 else
1123 TRACE(event, "unrecognized ClientMessage\n" );
1127 /**********************************************************************
1128 * EVENT_EnterNotify
1130 * Install colormap when Wine window is focused in
1131 * self-managed mode with private colormap
1134 void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
1136 if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
1137 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
1138 TSXInstallColormap( display, COLOR_GetColormap() );
1142 /**********************************************************************
1143 * EVENT_MapNotify
1145 void EVENT_MapNotify( HWND32 hWnd, XMapEvent *event )
1147 HWND32 hwndFocus = GetFocus32();
1149 if (hwndFocus && IsChild32( hWnd, hwndFocus ))
1150 FOCUS_SetXFocus( (HWND32)hwndFocus );
1152 return;
1155 /**********************************************************************
1156 * EVENT_Capture
1158 * We need this to be able to generate double click messages
1159 * when menu code captures mouse in the window without CS_DBLCLK style.
1161 HWND32 EVENT_Capture(HWND32 hwnd, INT16 ht)
1163 HWND32 capturePrev = captureWnd;
1165 if (!hwnd)
1167 captureWnd = 0L;
1168 captureHT = 0;
1170 else
1172 WND* wndPtr = WIN_FindWndPtr( hwnd );
1173 if (wndPtr)
1175 TRACE(win, "(0x%04x)\n", hwnd );
1176 captureWnd = hwnd;
1177 captureHT = ht;
1181 if( capturePrev && capturePrev != captureWnd )
1183 WND* wndPtr = WIN_FindWndPtr( capturePrev );
1184 if( wndPtr && (wndPtr->flags & WIN_ISWIN32) )
1185 SendMessage32A( capturePrev, WM_CAPTURECHANGED, 0L, hwnd);
1187 return capturePrev;
1190 /**********************************************************************
1191 * EVENT_GetCaptureInfo
1193 INT16 EVENT_GetCaptureInfo()
1195 return captureHT;
1198 /**********************************************************************
1199 * SetCapture16 (USER.18)
1201 HWND16 WINAPI SetCapture16( HWND16 hwnd )
1203 return (HWND16)EVENT_Capture( hwnd, HTCLIENT );
1207 /**********************************************************************
1208 * SetCapture32 (USER32.464)
1210 HWND32 WINAPI SetCapture32( HWND32 hwnd )
1212 return EVENT_Capture( hwnd, HTCLIENT );
1216 /**********************************************************************
1217 * ReleaseCapture (USER.19) (USER32.439)
1219 void WINAPI ReleaseCapture(void)
1221 TRACE(win, "captureWnd=%04x\n", captureWnd );
1222 if( captureWnd ) EVENT_Capture( 0, 0 );
1226 /**********************************************************************
1227 * GetCapture16 (USER.236)
1229 HWND16 WINAPI GetCapture16(void)
1231 return captureWnd;
1235 /**********************************************************************
1236 * GetCapture32 (USER32.208)
1238 HWND32 WINAPI GetCapture32(void)
1240 return captureWnd;
1245 /***********************************************************************
1246 * Mouse driver routines:
1249 #pragma pack(1)
1250 typedef struct _MOUSEINFO
1252 BYTE msExist;
1253 BYTE msRelative;
1254 WORD msNumButtons;
1255 WORD msRate;
1256 WORD msXThreshold;
1257 WORD msYThreshold;
1258 WORD msXRes;
1259 WORD msYRes;
1260 WORD msMouseCommPort;
1261 } MOUSEINFO;
1262 #pragma pack(4)
1264 static SEGPTR MouseEventProc = 0;
1266 /***********************************************************************
1267 * MouseInquire (MOUSE.1)
1270 WORD WINAPI MouseInquire(MOUSEINFO *mouseInfo)
1272 mouseInfo->msExist = TRUE;
1273 mouseInfo->msRelative = FALSE;
1274 mouseInfo->msNumButtons = 2;
1275 mouseInfo->msRate = 34; /* the DDK says so ... */
1276 mouseInfo->msXThreshold = 0;
1277 mouseInfo->msYThreshold = 0;
1278 mouseInfo->msXRes = 0;
1279 mouseInfo->msYRes = 0;
1280 mouseInfo->msMouseCommPort = 0;
1282 return sizeof(MOUSEINFO);
1285 /***********************************************************************
1286 * MouseEnable (MOUSE.2)
1288 VOID WINAPI MouseEnable(SEGPTR eventProc)
1290 MouseEventProc = eventProc;
1293 /***********************************************************************
1294 * MouseDisable (MOUSE.3)
1296 VOID WINAPI MouseDisable(VOID)
1298 MouseEventProc = 0;
1301 /***********************************************************************
1302 * EVENT_SendMouseEvent
1304 static void EVENT_SendMouseEvent( WORD mouseStatus, WORD deltaX, WORD deltaY,
1305 WORD buttonCount, DWORD extraInfo )
1307 CONTEXT context;
1309 if ( !MouseEventProc ) return;
1311 TRACE( keyboard, "(%04X,%d,%d,%d,%ld)\n", mouseStatus, deltaX, deltaY, buttonCount, extraInfo );
1313 mouseStatus |= 0x8000;
1314 deltaX = (((long)deltaX << 16) + screenWidth/2) / screenWidth;
1315 deltaY = (((long)deltaY << 16) + screenHeight/2) / screenHeight;
1317 memset( &context, 0, sizeof(context) );
1318 CS_reg(&context) = SELECTOROF( MouseEventProc );
1319 EIP_reg(&context) = OFFSETOF( MouseEventProc );
1320 EAX_reg(&context) = mouseStatus;
1321 EBX_reg(&context) = deltaX;
1322 ECX_reg(&context) = deltaY;
1323 EDX_reg(&context) = buttonCount;
1324 ESI_reg(&context) = LOWORD( extraInfo );
1325 EDI_reg(&context) = HIWORD( extraInfo );
1327 Callbacks->CallRegisterShortProc( &context, 0 );
1333 /***********************************************************************
1334 * GetMouseEventProc (USER.337)
1336 FARPROC16 WINAPI GetMouseEventProc(void)
1338 HMODULE16 hmodule = GetModuleHandle16("USER");
1339 return NE_GetEntryPoint( hmodule, NE_GetOrdinal( hmodule, "Mouse_Event" ));
1343 /***********************************************************************
1344 * Mouse_Event (USER.299)
1346 void WINAPI Mouse_Event( CONTEXT *context )
1348 /* Register values:
1349 * AX = mouse event
1350 * BX = horizontal displacement if AX & ME_MOVE
1351 * CX = vertical displacement if AX & ME_MOVE
1352 * DX = button state (?)
1353 * SI = mouse event flags (?)
1355 Window root, child;
1356 int rootX, rootY, winX, winY;
1357 unsigned int state;
1359 if (AX_reg(context) & ME_MOVE)
1361 /* We have to actually move the cursor */
1362 TSXWarpPointer( display, rootWindow, None, 0, 0, 0, 0,
1363 (short)BX_reg(context), (short)CX_reg(context) );
1364 return;
1366 if (!TSXQueryPointer( display, rootWindow, &root, &child,
1367 &rootX, &rootY, &winX, &winY, &state )) return;
1368 if (AX_reg(context) & ME_LDOWN)
1369 hardware_event( WM_LBUTTONDOWN, EVENT_XStateToKeyState( state ),
1370 0L, winX, winY, GetTickCount(), 0 );
1371 if (AX_reg(context) & ME_LUP)
1372 hardware_event( WM_LBUTTONUP, EVENT_XStateToKeyState( state ),
1373 0L, winX, winY, GetTickCount(), 0 );
1374 if (AX_reg(context) & ME_RDOWN)
1375 hardware_event( WM_RBUTTONDOWN, EVENT_XStateToKeyState( state ),
1376 0L, winX, winY, GetTickCount(), 0 );
1377 if (AX_reg(context) & ME_RUP)
1378 hardware_event( WM_RBUTTONUP, EVENT_XStateToKeyState( state ),
1379 0L, winX, winY, GetTickCount(), 0 );
1383 /**********************************************************************
1384 * EnableHardwareInput (USER.331)
1386 BOOL16 WINAPI EnableHardwareInput(BOOL16 bEnable)
1388 BOOL16 bOldState = InputEnabled;
1389 FIXME(event,"(%d) - stub\n", bEnable);
1390 InputEnabled = bEnable;
1391 return bOldState;
1395 /***********************************************************************
1396 * SwapMouseButton16 (USER.186)
1398 BOOL16 WINAPI SwapMouseButton16( BOOL16 fSwap )
1400 BOOL16 ret = SwappedButtons;
1401 SwappedButtons = fSwap;
1402 return ret;
1406 /***********************************************************************
1407 * SwapMouseButton32 (USER32.537)
1409 BOOL32 WINAPI SwapMouseButton32( BOOL32 fSwap )
1411 BOOL32 ret = SwappedButtons;
1412 SwappedButtons = fSwap;
1413 return ret;