Initial revision
[wine/multimedia.git] / windows / event.c
blob3caa4b9b6866065f468af67bd4fd52491e81128d
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"
44 #define NB_BUTTONS 3 /* Windows can handle 3 buttons */
46 #define DndNotDnd -1 /* OffiX drag&drop */
47 #define DndUnknown 0
48 #define DndRawData 1
49 #define DndFile 2
50 #define DndFiles 3
51 #define DndText 4
52 #define DndDir 5
53 #define DndLink 6
54 #define DndExe 7
56 #define DndEND 8
58 /* X context to associate a hwnd to an X window */
59 static XContext winContext = 0;
61 static INT16 captureHT = HTCLIENT;
62 static HWND32 captureWnd = 0;
63 static BOOL32 InputEnabled = TRUE;
64 static BOOL32 SwappedButtons = FALSE;
66 static Atom wmProtocols = None;
67 static Atom wmDeleteWindow = None;
68 static Atom dndProtocol = None;
69 static Atom dndSelection = None;
71 /* EVENT_WaitNetEvent() master fd sets */
73 static fd_set __event_io_set[3];
74 static int __event_max_fd = 0;
75 static int __event_x_connection = 0;
77 static const char * const event_names[] =
79 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
80 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
81 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
82 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
83 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
84 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
85 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
86 "ClientMessage", "MappingNotify"
89 /* Event handlers */
90 static void EVENT_Key( WND *pWnd, XKeyEvent *event );
91 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event );
92 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event );
93 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event );
94 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event );
95 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event );
96 static void EVENT_Expose( WND *pWnd, XExposeEvent *event );
97 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event );
98 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event );
99 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event);
100 static void EVENT_SelectionNotify( XSelectionEvent *event);
101 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event);
102 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event );
103 static void EVENT_MapNotify( HWND32 hwnd, XMapEvent *event );
105 /* Usable only with OLVWM - compile option perhaps?
106 static void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event );
109 /***********************************************************************
110 * EVENT_Init
112 * Initialize network IO.
114 BOOL32 EVENT_Init(void)
116 int i;
117 for( i = 0; i < 3; i++ )
118 FD_ZERO( __event_io_set + i );
120 __event_max_fd = __event_x_connection = ConnectionNumber(display);
121 FD_SET( __event_x_connection, &__event_io_set[EVENT_IO_READ] );
122 __event_max_fd++;
123 return TRUE;
126 /***********************************************************************
127 * EVENT_AddIO
129 void EVENT_AddIO( int fd, unsigned io_type )
131 FD_SET( fd, &__event_io_set[io_type] );
132 if( __event_max_fd <= fd ) __event_max_fd = fd + 1;
135 void EVENT_DeleteIO( int fd, unsigned io_type )
137 FD_CLR( fd, &__event_io_set[io_type] );
140 /***********************************************************************
141 * EVENT_ProcessEvent
143 * Process an X event.
145 void EVENT_ProcessEvent( XEvent *event )
147 WND *pWnd;
149 if (TSXFindContext( display, event->xany.window, winContext,
150 (char **)&pWnd ) != 0)
151 return; /* Not for a registered window */
153 TRACE(event, "Got event %s for hwnd %04x\n",
154 event_names[event->type], pWnd->hwndSelf );
156 switch(event->type)
158 case KeyPress:
159 case KeyRelease:
160 if (InputEnabled) EVENT_Key( pWnd, (XKeyEvent*)event );
161 break;
163 case ButtonPress:
164 if (InputEnabled)
165 EVENT_ButtonPress( pWnd, (XButtonEvent*)event );
166 break;
168 case ButtonRelease:
169 if (InputEnabled)
170 EVENT_ButtonRelease( pWnd, (XButtonEvent*)event );
171 break;
173 case MotionNotify:
174 /* Wine between two fast machines across the overloaded campus
175 ethernet gets very boged down in MotionEvents. The following
176 simply finds the last motion event in the queue and drops
177 the rest. On a good link events are servered before they build
178 up so this doesn't take place. On a slow link this may cause
179 problems if the event order is important. I'm not yet seen
180 of any problems. Jon 7/6/96.
182 if (InputEnabled)
184 while (TSXCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
185 MotionNotify, event));
186 EVENT_MotionNotify( pWnd, (XMotionEvent*)event );
188 break;
190 case FocusIn:
191 EVENT_FocusIn( pWnd, (XFocusChangeEvent*)event );
192 break;
194 case FocusOut:
195 EVENT_FocusOut( pWnd, (XFocusChangeEvent*)event );
196 break;
198 case Expose:
199 EVENT_Expose( pWnd, (XExposeEvent *)event );
200 break;
202 case GraphicsExpose:
203 EVENT_GraphicsExpose( pWnd, (XGraphicsExposeEvent *)event );
204 break;
206 case ConfigureNotify:
207 EVENT_ConfigureNotify( pWnd, (XConfigureEvent*)event );
208 break;
210 case SelectionRequest:
211 EVENT_SelectionRequest( pWnd, (XSelectionRequestEvent *)event );
212 break;
214 case SelectionNotify:
215 EVENT_SelectionNotify( (XSelectionEvent *)event );
216 break;
218 case SelectionClear:
219 EVENT_SelectionClear( pWnd, (XSelectionClearEvent*) event );
220 break;
222 case ClientMessage:
223 EVENT_ClientMessage( pWnd, (XClientMessageEvent *) event );
224 break;
226 /* case EnterNotify:
227 * EVENT_EnterNotify( pWnd, (XCrossingEvent *) event );
228 * break;
230 case NoExpose:
231 break;
233 /* We get all these because of StructureNotifyMask. */
234 case UnmapNotify:
235 case CirculateNotify:
236 case CreateNotify:
237 case DestroyNotify:
238 case GravityNotify:
239 case ReparentNotify:
240 break;
242 case MapNotify:
243 EVENT_MapNotify( pWnd->hwndSelf, (XMapEvent *)event );
244 break;
246 default:
247 WARN(event, "Unprocessed event %s for hwnd %04x\n",
248 event_names[event->type], pWnd->hwndSelf );
249 break;
254 /***********************************************************************
255 * EVENT_RegisterWindow
257 * Associate an X window to a HWND.
259 void EVENT_RegisterWindow( WND *pWnd )
261 if (wmProtocols == None)
262 wmProtocols = TSXInternAtom( display, "WM_PROTOCOLS", True );
263 if (wmDeleteWindow == None)
264 wmDeleteWindow = TSXInternAtom( display, "WM_DELETE_WINDOW", True );
265 if( dndProtocol == None )
266 dndProtocol = TSXInternAtom( display, "DndProtocol" , False );
267 if( dndSelection == None )
268 dndSelection = TSXInternAtom( display, "DndSelection" , False );
270 TSXSetWMProtocols( display, pWnd->window, &wmDeleteWindow, 1 );
272 if (!winContext) winContext = TSXUniqueContext();
273 TSXSaveContext( display, pWnd->window, winContext, (char *)pWnd );
276 /***********************************************************************
277 * EVENT_DestroyWindow
279 void EVENT_DestroyWindow( WND *pWnd )
281 XEvent xe;
283 TSXDeleteContext( display, pWnd->window, winContext );
284 TSXDestroyWindow( display, pWnd->window );
285 while( TSXCheckWindowEvent(display, pWnd->window, NoEventMask, &xe) );
289 /***********************************************************************
290 * IsUserIdle (USER.333)
292 * Check if we have pending X events.
294 BOOL16 WINAPI IsUserIdle(void)
296 struct timeval timeout = {0, 0};
297 fd_set check_set;
299 FD_ZERO(&check_set);
300 FD_SET(__event_x_connection, &check_set);
301 if( select(__event_x_connection + 1, &check_set, NULL, NULL, &timeout) > 0 )
302 return TRUE;
303 return FALSE;
307 /***********************************************************************
308 * EVENT_WaitNetEvent
310 * Wait for a network event, optionally sleeping until one arrives.
311 * Return TRUE if an event is pending, FALSE on timeout or error
312 * (for instance lost connection with the server).
314 BOOL32 EVENT_WaitNetEvent( BOOL32 sleep, BOOL32 peek )
316 XEvent event;
317 LONG maxWait = sleep ? TIMER_GetNextExpiration() : 0;
318 int pending = TSXPending(display);
320 /* Wait for an event or a timeout. If maxWait is -1, we have no timeout;
321 * in this case, we fall through directly to the XNextEvent loop.
324 if ((maxWait != -1) && !pending)
326 int num_pending;
327 struct timeval timeout;
328 fd_set io_set[3];
330 memcpy( io_set, __event_io_set, sizeof(io_set) );
332 timeout.tv_usec = (maxWait % 1000) * 1000;
333 timeout.tv_sec = maxWait / 1000;
335 #ifdef CONFIG_IPC
336 sigsetjmp(env_wait_x, 1);
337 stop_wait_op= CONT;
339 if (DDE_GetRemoteMessage()) {
340 while(DDE_GetRemoteMessage())
342 return TRUE;
344 stop_wait_op = STOP_WAIT_X;
345 /* The code up to the next "stop_wait_op = CONT" must be reentrant */
346 num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
347 &io_set[EVENT_IO_WRITE],
348 &io_set[EVENT_IO_EXCEPT], &timeout );
349 if ( num_pending == 0 )
351 stop_wait_op = CONT;
352 TIMER_ExpireTimers();
353 return FALSE;
355 else stop_wait_op = CONT;
356 #else /* CONFIG_IPC */
357 num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
358 &io_set[EVENT_IO_WRITE],
359 &io_set[EVENT_IO_EXCEPT], &timeout );
360 if ( num_pending == 0)
362 /* Timeout or error */
363 TIMER_ExpireTimers();
364 return FALSE;
366 #endif /* CONFIG_IPC */
368 /* Winsock asynchronous services */
370 if( FD_ISSET( __event_x_connection, &io_set[EVENT_IO_READ]) )
372 num_pending--;
373 if( num_pending )
374 WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
376 else /* no X events */
377 return WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
379 else if(!pending)
380 { /* Wait for X11 input. */
381 fd_set set;
383 FD_ZERO(&set);
384 FD_SET(__event_x_connection, &set);
385 select(__event_x_connection + 1, &set, 0, 0, 0 );
388 /* Process current X event (and possibly others that occurred in the meantime) */
390 EnterCriticalSection(&X11DRV_CritSection);
391 while (XPending( display ))
394 #ifdef CONFIG_IPC
395 if (DDE_GetRemoteMessage())
397 LeaveCriticalSection(&X11DRV_CritSection);
398 while(DDE_GetRemoteMessage()) ;
399 return TRUE;
401 #endif /* CONFIG_IPC */
403 XNextEvent( display, &event );
405 LeaveCriticalSection(&X11DRV_CritSection);
406 if( peek )
408 WND* pWnd;
409 MESSAGEQUEUE* pQ;
411 if (TSXFindContext( display, ((XAnyEvent *)&event)->window, winContext,
412 (char **)&pWnd ) || (event.type == NoExpose))
413 continue;
415 /* Check only for those events which can be processed
416 * internally. */
418 if( event.type == MotionNotify ||
419 event.type == ButtonPress || event.type == ButtonRelease ||
420 event.type == KeyPress || event.type == KeyRelease ||
421 event.type == SelectionRequest || event.type == SelectionClear )
423 EVENT_ProcessEvent( &event );
424 continue;
427 if( pWnd )
429 if( (pQ = (MESSAGEQUEUE*)GlobalLock16(pWnd->hmemTaskQ)) )
431 pQ->flags |= QUEUE_FLAG_XEVENT;
432 PostEvent(pQ->hTask);
433 TSXPutBackEvent(display, &event);
434 break;
438 else EVENT_ProcessEvent( &event );
439 EnterCriticalSection(&X11DRV_CritSection);
441 LeaveCriticalSection(&X11DRV_CritSection);
442 return TRUE;
446 /***********************************************************************
447 * EVENT_Synchronize
449 * Synchronize with the X server. Should not be used too often.
451 void EVENT_Synchronize()
453 XEvent event;
455 /* Use of the X critical section is needed or we have a small
456 * race between XPending() and XNextEvent().
458 EnterCriticalSection( &X11DRV_CritSection );
459 XSync( display, False );
460 while (XPending( display ))
462 XNextEvent( display, &event );
463 /* unlock X critsection for EVENT_ProcessEvent() might switch tasks */
464 LeaveCriticalSection( &X11DRV_CritSection );
465 EVENT_ProcessEvent( &event );
466 EnterCriticalSection( &X11DRV_CritSection );
468 LeaveCriticalSection( &X11DRV_CritSection );
471 /***********************************************************************
472 * EVENT_QueryZOrder
474 * Try to synchronize internal z-order with the window manager's.
475 * Probably a futile endeavor.
477 static BOOL32 __check_query_condition( WND** pWndA, WND** pWndB )
479 /* return TRUE if we have at least two managed windows */
481 for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
482 if( (*pWndA)->flags & WIN_MANAGED &&
483 (*pWndA)->dwStyle & WS_VISIBLE ) break;
484 if( *pWndA )
485 for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
486 if( (*pWndB)->flags & WIN_MANAGED &&
487 (*pWndB)->dwStyle & WS_VISIBLE ) break;
488 return ((*pWndB) != NULL);
491 static Window __get_common_ancestor( Window A, Window B,
492 Window** children, unsigned* total )
494 /* find the real root window */
496 Window root, *childrenB;
497 unsigned totalB;
501 if( *children ) TSXFree( *children );
502 TSXQueryTree( display, A, &root, &A, children, total );
503 TSXQueryTree( display, B, &root, &B, &childrenB, &totalB );
504 if( childrenB ) TSXFree( childrenB );
505 } while( A != B && A && B );
506 return ( A && B ) ? A : 0 ;
509 static Window __get_top_decoration( Window w, Window ancestor )
511 Window* children, root, prev = w, parent = w;
512 unsigned total;
516 w = parent;
517 TSXQueryTree( display, w, &root, &parent, &children, &total );
518 if( children ) TSXFree( children );
519 } while( parent && parent != ancestor );
520 TRACE(event, "\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
521 return ( parent ) ? w : 0 ;
524 static unsigned __td_lookup( Window w, Window* list, unsigned max )
526 unsigned i;
527 for( i = 0; i < max; i++ ) if( list[i] == w ) break;
528 return i;
531 static BOOL32 EVENT_QueryZOrder( WND* pWndCheck )
533 BOOL32 bRet = FALSE;
534 HWND32 hwndInsertAfter = HWND_TOP;
535 WND* pWnd, *pWndZ = WIN_GetDesktop()->child;
536 Window w, parent, *children = NULL;
537 unsigned total, check, pos, best;
539 if( !__check_query_condition(&pWndZ, &pWnd) ) return TRUE;
541 parent = __get_common_ancestor( pWndZ->window, pWnd->window,
542 &children, &total );
543 if( parent && children )
545 w = __get_top_decoration( pWndCheck->window, parent );
546 if( w != children[total - 1] )
548 check = __td_lookup( w, children, total );
549 best = total;
550 for( pWnd = pWndZ; pWnd; pWnd = pWnd->next )
552 if( pWnd != pWndCheck )
554 if( !(pWnd->flags & WIN_MANAGED) ||
555 !(w = __get_top_decoration( pWnd->window, parent )) )
556 continue;
557 pos = __td_lookup( w, children, total );
558 if( pos < best && pos > check )
560 best = pos;
561 hwndInsertAfter = pWnd->hwndSelf;
563 if( check - best == 1 ) break;
566 WIN_UnlinkWindow( pWndCheck->hwndSelf );
567 WIN_LinkWindow( pWndCheck->hwndSelf, hwndInsertAfter);
570 if( children ) TSXFree( children );
571 return bRet;
575 /***********************************************************************
576 * EVENT_XStateToKeyState
578 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
579 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
581 static WORD EVENT_XStateToKeyState( int state )
583 int kstate = 0;
585 if (state & Button1Mask) kstate |= MK_LBUTTON;
586 if (state & Button2Mask) kstate |= MK_MBUTTON;
587 if (state & Button3Mask) kstate |= MK_RBUTTON;
588 if (state & ShiftMask) kstate |= MK_SHIFT;
589 if (state & ControlMask) kstate |= MK_CONTROL;
590 return kstate;
594 /***********************************************************************
595 * EVENT_Expose
597 static void EVENT_Expose( WND *pWnd, XExposeEvent *event )
599 RECT32 rect;
601 /* Make position relative to client area instead of window */
602 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
603 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
604 rect.right = rect.left + event->width;
605 rect.bottom = rect.top + event->height;
607 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
608 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
609 (event->count ? 0 : RDW_ERASENOW), 0 );
613 /***********************************************************************
614 * EVENT_GraphicsExpose
616 * This is needed when scrolling area is partially obscured
617 * by non-Wine X window.
619 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event )
621 RECT32 rect;
623 /* Make position relative to client area instead of window */
624 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
625 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
626 rect.right = rect.left + event->width;
627 rect.bottom = rect.top + event->height;
629 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
630 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
631 (event->count ? 0 : RDW_ERASENOW), 0 );
635 /***********************************************************************
636 * EVENT_Key
638 * Handle a X key event
640 static void EVENT_Key( WND *pWnd, XKeyEvent *event )
642 KEYBOARD_HandleEvent( pWnd, event );
646 /***********************************************************************
647 * EVENT_MotionNotify
649 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event )
651 hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ), 0L,
652 pWnd->rectWindow.left + event->x,
653 pWnd->rectWindow.top + event->y,
654 event->time - MSG_WineStartTicks, pWnd->hwndSelf );
658 /***********************************************************************
659 * EVENT_DummyMotionNotify
661 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
663 void EVENT_DummyMotionNotify(void)
665 Window root, child;
666 int rootX, rootY, winX, winY;
667 unsigned int state;
669 if (TSXQueryPointer( display, rootWindow, &root, &child,
670 &rootX, &rootY, &winX, &winY, &state ))
672 hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( state ), 0L,
673 winX, winY, GetTickCount(), 0 );
678 /***********************************************************************
679 * EVENT_ButtonPress
681 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event )
683 static WORD messages[NB_BUTTONS] =
684 { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
685 int buttonNum = event->button - 1;
687 if (buttonNum >= NB_BUTTONS) return;
688 if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
689 MouseButtonsStates[buttonNum] = TRUE;
690 AsyncMouseButtonsStates[buttonNum] = TRUE;
691 hardware_event( messages[buttonNum],
692 EVENT_XStateToKeyState( event->state ), 0L,
693 pWnd->rectWindow.left + event->x,
694 pWnd->rectWindow.top + event->y,
695 event->time - MSG_WineStartTicks, pWnd->hwndSelf );
699 /***********************************************************************
700 * EVENT_ButtonRelease
702 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event )
704 static const WORD messages[NB_BUTTONS] =
705 { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
706 int buttonNum = event->button - 1;
708 if (buttonNum >= NB_BUTTONS) return;
709 if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
710 MouseButtonsStates[buttonNum] = FALSE;
711 hardware_event( messages[buttonNum],
712 EVENT_XStateToKeyState( event->state ), 0L,
713 pWnd->rectWindow.left + event->x,
714 pWnd->rectWindow.top + event->y,
715 event->time - MSG_WineStartTicks, pWnd->hwndSelf );
719 /**********************************************************************
720 * EVENT_FocusIn
722 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event )
724 if (Options.managed) EVENT_QueryZOrder( pWnd );
726 if (event->detail != NotifyPointer)
728 HWND32 hwnd = pWnd->hwndSelf;
730 if (hwnd != GetActiveWindow32())
731 WINPOS_ChangeActiveWindow( hwnd, FALSE );
732 if ((hwnd != GetFocus32()) && !IsChild32( hwnd, GetFocus32()))
733 SetFocus32( hwnd );
738 /**********************************************************************
739 * EVENT_FocusOut
741 * Note: only top-level override-redirect windows get FocusOut events.
743 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event )
745 if (event->detail != NotifyPointer)
747 HWND32 hwnd = pWnd->hwndSelf;
749 if (hwnd == GetActiveWindow32())
750 WINPOS_ChangeActiveWindow( 0, FALSE );
751 if ((hwnd == GetFocus32()) || IsChild32( hwnd, GetFocus32()))
752 SetFocus32( 0 );
756 /**********************************************************************
757 * EVENT_CheckFocus
759 BOOL32 EVENT_CheckFocus(void)
761 WND* pWnd;
762 Window xW;
763 int state;
765 TSXGetInputFocus(display, &xW, &state);
766 if( xW == None ||
767 TSXFindContext(display, xW, winContext, (char **)&pWnd) )
768 return FALSE;
769 return TRUE;
773 /**********************************************************************
774 * EVENT_GetGeometry
776 * Helper function for ConfigureNotify handling.
777 * Get the new geometry of a window relative to the root window.
779 static void EVENT_GetGeometry( Window win, int *px, int *py,
780 unsigned int *pwidth, unsigned int *pheight )
782 Window root, parent, *children;
783 int xpos, ypos;
784 unsigned int width, height, border, depth, nb_children;
786 if (!TSXGetGeometry( display, win, &root, px, py, pwidth, pheight,
787 &border, &depth )) return;
788 if (win == rootWindow)
790 *px = *py = 0;
791 return;
794 for (;;)
796 if (!TSXQueryTree(display, win, &root, &parent, &children, &nb_children))
797 return;
798 TSXFree( children );
799 if (parent == rootWindow) break;
800 win = parent;
801 if (!TSXGetGeometry( display, win, &root, &xpos, &ypos,
802 &width, &height, &border, &depth )) return;
803 *px += xpos;
804 *py += ypos;
809 /**********************************************************************
810 * EVENT_ConfigureNotify
812 * The ConfigureNotify event is only selected on top-level windows
813 * when the -managed flag is used.
815 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event )
817 WINDOWPOS32 winpos;
818 RECT32 newWindowRect, newClientRect;
819 HRGN32 hrgnOldPos, hrgnNewPos;
820 Window above = event->above;
821 int x, y;
822 unsigned int width, height;
824 assert (pWnd->flags & WIN_MANAGED);
826 /* We don't rely on the event geometry info, because it is relative
827 * to parent and not to root, and it may be wrong (XFree sets x,y to 0,0
828 * if the window hasn't moved).
830 EVENT_GetGeometry( event->window, &x, &y, &width, &height );
832 /* Fill WINDOWPOS struct */
833 winpos.flags = SWP_NOACTIVATE | SWP_NOZORDER;
834 winpos.hwnd = pWnd->hwndSelf;
835 winpos.x = x;
836 winpos.y = y;
837 winpos.cx = width;
838 winpos.cy = height;
840 /* Check for unchanged attributes */
841 if (winpos.x == pWnd->rectWindow.left && winpos.y == pWnd->rectWindow.top)
842 winpos.flags |= SWP_NOMOVE;
843 if ((winpos.cx == pWnd->rectWindow.right - pWnd->rectWindow.left) &&
844 (winpos.cy == pWnd->rectWindow.bottom - pWnd->rectWindow.top))
845 winpos.flags |= SWP_NOSIZE;
846 else
848 RECT32 rect = { 0, 0, pWnd->rectWindow.right - pWnd->rectWindow.left,
849 pWnd->rectWindow.bottom - pWnd->rectWindow.top };
850 DCE_InvalidateDCE( pWnd, &rect );
853 /* Send WM_WINDOWPOSCHANGING */
854 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)&winpos );
856 /* Calculate new position and size */
857 newWindowRect.left = x;
858 newWindowRect.right = x + width;
859 newWindowRect.top = y;
860 newWindowRect.bottom = y + height;
862 WINPOS_SendNCCalcSize( winpos.hwnd, TRUE, &newWindowRect,
863 &pWnd->rectWindow, &pWnd->rectClient,
864 &winpos, &newClientRect );
866 hrgnOldPos = CreateRectRgnIndirect32( &pWnd->rectWindow );
867 hrgnNewPos = CreateRectRgnIndirect32( &newWindowRect );
868 CombineRgn32( hrgnOldPos, hrgnOldPos, hrgnNewPos, RGN_DIFF );
869 DeleteObject32(hrgnOldPos);
870 DeleteObject32(hrgnNewPos);
872 /* Set new size and position */
873 pWnd->rectWindow = newWindowRect;
874 pWnd->rectClient = newClientRect;
875 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)&winpos );
877 if (!IsWindow32( winpos.hwnd )) return;
878 if( above == None ) /* absolute bottom */
880 WIN_UnlinkWindow( winpos.hwnd );
881 WIN_LinkWindow( winpos.hwnd, HWND_BOTTOM);
883 else EVENT_QueryZOrder( pWnd ); /* try to outsmart window manager */
887 /***********************************************************************
888 * EVENT_SelectionRequest
890 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event )
892 XSelectionEvent result;
893 Atom rprop = None;
894 Window request = event->requestor;
896 if(event->target == XA_STRING)
898 HANDLE16 hText;
899 LPSTR text;
900 int size,i,j;
902 rprop = event->property;
904 if(rprop == None) rprop = event->target;
906 if(event->selection!=XA_PRIMARY) rprop = None;
907 else if(!CLIPBOARD_IsPresent(CF_OEMTEXT)) rprop = None;
908 else
910 /* open to make sure that clipboard is available */
912 BOOL32 couldOpen = OpenClipboard32( pWnd->hwndSelf );
913 char* lpstr = 0;
915 hText = GetClipboardData16(CF_TEXT);
916 text = GlobalLock16(hText);
917 size = GlobalSize16(hText);
919 /* remove carriage returns */
921 lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
922 for(i=0,j=0; i < size && text[i]; i++ )
924 if( text[i] == '\r' &&
925 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
926 lpstr[j++] = text[i];
928 lpstr[j]='\0';
930 TSXChangeProperty(display, request, rprop,
931 XA_STRING, 8, PropModeReplace,
932 lpstr, j);
933 HeapFree( GetProcessHeap(), 0, lpstr );
935 /* close only if we opened before */
937 if(couldOpen) CloseClipboard32();
941 if(rprop == None)
942 TRACE(event,"Request for %s ignored\n", TSXGetAtomName(display,event->target));
944 result.type = SelectionNotify;
945 result.display = display;
946 result.requestor = request;
947 result.selection = event->selection;
948 result.property = rprop;
949 result.target = event->target;
950 result.time = event->time;
951 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
955 /***********************************************************************
956 * EVENT_SelectionNotify
958 static void EVENT_SelectionNotify( XSelectionEvent *event )
960 if (event->selection != XA_PRIMARY) return;
962 if (event->target != XA_STRING) CLIPBOARD_ReadSelection( 0, None );
963 else CLIPBOARD_ReadSelection( event->requestor, event->property );
965 TRACE(clipboard,"\tSelectionNotify done!\n");
969 /***********************************************************************
970 * EVENT_SelectionClear
972 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event )
974 if (event->selection != XA_PRIMARY) return;
975 CLIPBOARD_ReleaseSelection( event->window, pWnd->hwndSelf );
979 /**********************************************************************
980 * EVENT_ClientMessage
982 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event )
984 if (event->message_type != None && event->format == 32)
986 if ((event->message_type == wmProtocols) &&
987 (((Atom) event->data.l[0]) == wmDeleteWindow))
988 SendMessage16( pWnd->hwndSelf, WM_SYSCOMMAND, SC_CLOSE, 0 );
989 else if ( event->message_type == dndProtocol &&
990 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
992 unsigned long data_length;
993 unsigned long aux_long;
994 unsigned char* p_data = NULL;
995 union {
996 Atom atom_aux;
997 POINT32 pt_aux;
998 int i;
999 } u;
1000 int x, y;
1001 BOOL16 bAccept;
1002 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
1003 LPDRAGINFO lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
1004 SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
1005 Window w_aux_root, w_aux_child;
1006 WND* pDropWnd;
1008 if( !lpDragInfo || !spDragInfo ) return;
1010 TSXQueryPointer( display, pWnd->window, &w_aux_root, &w_aux_child,
1011 &x, &y, &u.pt_aux.x, &u.pt_aux.y, (unsigned int*)&aux_long);
1013 lpDragInfo->hScope = pWnd->hwndSelf;
1014 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1016 /* find out drop point and drop window */
1017 if( x < 0 || y < 0 ||
1018 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1019 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1020 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1021 else
1023 bAccept = DRAG_QueryUpdate( pWnd->hwndSelf, spDragInfo, TRUE );
1024 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1026 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1027 GlobalFree16( hDragInfo );
1029 if( bAccept )
1031 TSXGetWindowProperty( display, DefaultRootWindow(display),
1032 dndSelection, 0, 65535, FALSE,
1033 AnyPropertyType, &u.atom_aux, &u.pt_aux.y,
1034 &data_length, &aux_long, &p_data);
1036 if( !aux_long && p_data) /* don't bother if > 64K */
1038 char *p = (char*) p_data;
1039 char *p_drop;
1041 aux_long = 0;
1042 while( *p ) /* calculate buffer size */
1044 p_drop = p;
1045 if((u.i = *p) != -1 )
1046 u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
1047 if( u.i == -1 ) *p = -1; /* mark as "bad" */
1048 else
1050 INT32 len = GetShortPathName32A( p, NULL, 0 );
1051 if (len) aux_long += len + 1;
1052 else *p = -1;
1054 p += strlen(p) + 1;
1056 if( aux_long && aux_long < 65535 )
1058 HDROP16 hDrop;
1059 LPDROPFILESTRUCT lpDrop;
1061 aux_long += sizeof(DROPFILESTRUCT) + 1;
1062 hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
1063 lpDrop = (LPDROPFILESTRUCT) GlobalLock16( hDrop );
1065 if( lpDrop )
1067 lpDrop->wSize = sizeof(DROPFILESTRUCT);
1068 lpDrop->ptMousePos.x = (INT16)x;
1069 lpDrop->ptMousePos.y = (INT16)y;
1070 lpDrop->fInNonClientArea = (BOOL16)
1071 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1072 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1073 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1074 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1075 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT);
1076 p = p_data;
1077 while(*p)
1079 if( *p != -1 ) /* use only "good" entries */
1081 GetShortPathName32A( p, p_drop, 65535 );
1082 p_drop += strlen( p_drop ) + 1;
1084 p += strlen(p) + 1;
1086 *p_drop = '\0';
1087 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1088 (WPARAM16)hDrop, 0L );
1092 if( p_data ) TSXFree(p_data);
1094 } /* WS_EX_ACCEPTFILES */
1095 } /* dndProtocol */
1096 else
1097 TRACE(event, "unrecognized ClientMessage\n" );
1101 /**********************************************************************
1102 * EVENT_EnterNotify
1104 * Install colormap when Wine window is focused in
1105 * self-managed mode with private colormap
1108 void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
1110 if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
1111 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
1112 TSXInstallColormap( display, COLOR_GetColormap() );
1116 /**********************************************************************
1117 * EVENT_MapNotify
1119 void EVENT_MapNotify( HWND32 hWnd, XMapEvent *event )
1121 HWND32 hwndFocus = GetFocus32();
1123 if (hwndFocus && IsChild32( hWnd, hwndFocus ))
1124 FOCUS_SetXFocus( (HWND32)hwndFocus );
1126 return;
1129 /**********************************************************************
1130 * EVENT_Capture
1132 * We need this to be able to generate double click messages
1133 * when menu code captures mouse in the window without CS_DBLCLK style.
1135 HWND32 EVENT_Capture(HWND32 hwnd, INT16 ht)
1137 Window win;
1138 HWND32 capturePrev = captureWnd;
1140 if (!hwnd)
1142 captureWnd = NULL;
1143 captureHT = 0;
1145 else
1147 WND* wndPtr = WIN_FindWndPtr( hwnd );
1148 if (wndPtr)
1150 TRACE(win, "(0x%04x)\n", hwnd );
1151 captureWnd = hwnd;
1152 captureHT = ht;
1156 if( capturePrev && capturePrev != captureWnd )
1158 WND* wndPtr = WIN_FindWndPtr( capturePrev );
1159 if( wndPtr && (wndPtr->flags & WIN_ISWIN32) )
1160 SendMessage32A( capturePrev, WM_CAPTURECHANGED, 0L, hwnd);
1162 return capturePrev;
1165 /**********************************************************************
1166 * EVENT_GetCaptureInfo
1168 INT16 EVENT_GetCaptureInfo()
1170 return captureHT;
1173 /**********************************************************************
1174 * SetCapture16 (USER.18)
1176 HWND16 WINAPI SetCapture16( HWND16 hwnd )
1178 return (HWND16)EVENT_Capture( hwnd, HTCLIENT );
1182 /**********************************************************************
1183 * SetCapture32 (USER32.464)
1185 HWND32 WINAPI SetCapture32( HWND32 hwnd )
1187 return EVENT_Capture( hwnd, HTCLIENT );
1191 /**********************************************************************
1192 * ReleaseCapture (USER.19) (USER32.439)
1194 void WINAPI ReleaseCapture(void)
1196 TRACE(win, "captureWnd=%04x\n", captureWnd );
1197 if( captureWnd ) EVENT_Capture( 0, 0 );
1201 /**********************************************************************
1202 * GetCapture16 (USER.236)
1204 HWND16 WINAPI GetCapture16(void)
1206 return captureWnd;
1210 /**********************************************************************
1211 * GetCapture32 (USER32.208)
1213 HWND32 WINAPI GetCapture32(void)
1215 return captureWnd;
1219 /***********************************************************************
1220 * GetMouseEventProc (USER.337)
1222 FARPROC16 WINAPI GetMouseEventProc(void)
1224 HMODULE16 hmodule = GetModuleHandle16("USER");
1225 return NE_GetEntryPoint( hmodule, NE_GetOrdinal( hmodule, "Mouse_Event" ));
1229 /***********************************************************************
1230 * Mouse_Event (USER.299)
1232 void WINAPI Mouse_Event( CONTEXT *context )
1234 /* Register values:
1235 * AX = mouse event
1236 * BX = horizontal displacement if AX & ME_MOVE
1237 * CX = vertical displacement if AX & ME_MOVE
1238 * DX = button state (?)
1239 * SI = mouse event flags (?)
1241 Window root, child;
1242 int rootX, rootY, winX, winY;
1243 unsigned int state;
1245 if (AX_reg(context) & ME_MOVE)
1247 /* We have to actually move the cursor */
1248 TSXWarpPointer( display, rootWindow, None, 0, 0, 0, 0,
1249 (short)BX_reg(context), (short)CX_reg(context) );
1250 return;
1252 if (!TSXQueryPointer( display, rootWindow, &root, &child,
1253 &rootX, &rootY, &winX, &winY, &state )) return;
1254 if (AX_reg(context) & ME_LDOWN)
1255 hardware_event( WM_LBUTTONDOWN, EVENT_XStateToKeyState( state ),
1256 0L, winX, winY, GetTickCount(), 0 );
1257 if (AX_reg(context) & ME_LUP)
1258 hardware_event( WM_LBUTTONUP, EVENT_XStateToKeyState( state ),
1259 0L, winX, winY, GetTickCount(), 0 );
1260 if (AX_reg(context) & ME_RDOWN)
1261 hardware_event( WM_RBUTTONDOWN, EVENT_XStateToKeyState( state ),
1262 0L, winX, winY, GetTickCount(), 0 );
1263 if (AX_reg(context) & ME_RUP)
1264 hardware_event( WM_RBUTTONUP, EVENT_XStateToKeyState( state ),
1265 0L, winX, winY, GetTickCount(), 0 );
1269 /**********************************************************************
1270 * EnableHardwareInput (USER.331)
1272 BOOL16 WINAPI EnableHardwareInput(BOOL16 bEnable)
1274 BOOL16 bOldState = InputEnabled;
1275 FIXME(event,"(%d) - stub\n", bEnable);
1276 InputEnabled = bEnable;
1277 return bOldState;
1281 /***********************************************************************
1282 * SwapMouseButton16 (USER.186)
1284 BOOL16 WINAPI SwapMouseButton16( BOOL16 fSwap )
1286 BOOL16 ret = SwappedButtons;
1287 SwappedButtons = fSwap;
1288 return ret;
1292 /***********************************************************************
1293 * SwapMouseButton32 (USER32.537)
1295 BOOL32 WINAPI SwapMouseButton32( BOOL32 fSwap )
1297 BOOL32 ret = SwappedButtons;
1298 SwappedButtons = fSwap;
1299 return ret;