Yet another small self-loader fix.
[wine/multimedia.git] / windows / event.c
blob8572f3413a57290515c21588dcd7def7db0beb8f
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())
732 WINPOS_ChangeActiveWindow( hwnd, FALSE );
733 KEYBOARD_UpdateState();
735 if ((hwnd != GetFocus32()) && !IsChild32( hwnd, GetFocus32()))
736 SetFocus32( hwnd );
741 /**********************************************************************
742 * EVENT_FocusOut
744 * Note: only top-level override-redirect windows get FocusOut events.
746 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event )
748 if (event->detail != NotifyPointer)
750 HWND32 hwnd = pWnd->hwndSelf;
752 if (hwnd == GetActiveWindow32())
753 WINPOS_ChangeActiveWindow( 0, FALSE );
754 if ((hwnd == GetFocus32()) || IsChild32( hwnd, GetFocus32()))
755 SetFocus32( 0 );
759 /**********************************************************************
760 * EVENT_CheckFocus
762 BOOL32 EVENT_CheckFocus(void)
764 WND* pWnd;
765 Window xW;
766 int state;
768 TSXGetInputFocus(display, &xW, &state);
769 if( xW == None ||
770 TSXFindContext(display, xW, winContext, (char **)&pWnd) )
771 return FALSE;
772 return TRUE;
776 /**********************************************************************
777 * EVENT_GetGeometry
779 * Helper function for ConfigureNotify handling.
780 * Get the new geometry of a window relative to the root window.
782 static void EVENT_GetGeometry( Window win, int *px, int *py,
783 unsigned int *pwidth, unsigned int *pheight )
785 Window root, parent, *children;
786 int xpos, ypos;
787 unsigned int width, height, border, depth, nb_children;
789 if (!TSXGetGeometry( display, win, &root, px, py, pwidth, pheight,
790 &border, &depth )) return;
791 if (win == rootWindow)
793 *px = *py = 0;
794 return;
797 for (;;)
799 if (!TSXQueryTree(display, win, &root, &parent, &children, &nb_children))
800 return;
801 TSXFree( children );
802 if (parent == rootWindow) break;
803 win = parent;
804 if (!TSXGetGeometry( display, win, &root, &xpos, &ypos,
805 &width, &height, &border, &depth )) return;
806 *px += xpos;
807 *py += ypos;
812 /**********************************************************************
813 * EVENT_ConfigureNotify
815 * The ConfigureNotify event is only selected on top-level windows
816 * when the -managed flag is used.
818 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event )
820 WINDOWPOS32 winpos;
821 RECT32 newWindowRect, newClientRect;
822 HRGN32 hrgnOldPos, hrgnNewPos;
823 Window above = event->above;
824 int x, y;
825 unsigned int width, height;
827 assert (pWnd->flags & WIN_MANAGED);
829 /* We don't rely on the event geometry info, because it is relative
830 * to parent and not to root, and it may be wrong (XFree sets x,y to 0,0
831 * if the window hasn't moved).
833 EVENT_GetGeometry( event->window, &x, &y, &width, &height );
835 /* Fill WINDOWPOS struct */
836 winpos.flags = SWP_NOACTIVATE | SWP_NOZORDER;
837 winpos.hwnd = pWnd->hwndSelf;
838 winpos.x = x;
839 winpos.y = y;
840 winpos.cx = width;
841 winpos.cy = height;
843 /* Check for unchanged attributes */
844 if (winpos.x == pWnd->rectWindow.left && winpos.y == pWnd->rectWindow.top)
845 winpos.flags |= SWP_NOMOVE;
846 if ((winpos.cx == pWnd->rectWindow.right - pWnd->rectWindow.left) &&
847 (winpos.cy == pWnd->rectWindow.bottom - pWnd->rectWindow.top))
848 winpos.flags |= SWP_NOSIZE;
849 else
851 RECT32 rect = { 0, 0, pWnd->rectWindow.right - pWnd->rectWindow.left,
852 pWnd->rectWindow.bottom - pWnd->rectWindow.top };
853 DCE_InvalidateDCE( pWnd, &rect );
856 /* Send WM_WINDOWPOSCHANGING */
857 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)&winpos );
859 /* Calculate new position and size */
860 newWindowRect.left = x;
861 newWindowRect.right = x + width;
862 newWindowRect.top = y;
863 newWindowRect.bottom = y + height;
865 WINPOS_SendNCCalcSize( winpos.hwnd, TRUE, &newWindowRect,
866 &pWnd->rectWindow, &pWnd->rectClient,
867 &winpos, &newClientRect );
869 hrgnOldPos = CreateRectRgnIndirect32( &pWnd->rectWindow );
870 hrgnNewPos = CreateRectRgnIndirect32( &newWindowRect );
871 CombineRgn32( hrgnOldPos, hrgnOldPos, hrgnNewPos, RGN_DIFF );
872 DeleteObject32(hrgnOldPos);
873 DeleteObject32(hrgnNewPos);
875 /* Set new size and position */
876 pWnd->rectWindow = newWindowRect;
877 pWnd->rectClient = newClientRect;
878 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)&winpos );
880 if (!IsWindow32( winpos.hwnd )) return;
881 if( above == None ) /* absolute bottom */
883 WIN_UnlinkWindow( winpos.hwnd );
884 WIN_LinkWindow( winpos.hwnd, HWND_BOTTOM);
886 else EVENT_QueryZOrder( pWnd ); /* try to outsmart window manager */
890 /***********************************************************************
891 * EVENT_SelectionRequest
893 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event )
895 XSelectionEvent result;
896 Atom rprop = None;
897 Window request = event->requestor;
899 if(event->target == XA_STRING)
901 HANDLE16 hText;
902 LPSTR text;
903 int size,i,j;
905 rprop = event->property;
907 if(rprop == None) rprop = event->target;
909 if(event->selection!=XA_PRIMARY) rprop = None;
910 else if(!CLIPBOARD_IsPresent(CF_OEMTEXT)) rprop = None;
911 else
913 /* open to make sure that clipboard is available */
915 BOOL32 couldOpen = OpenClipboard32( pWnd->hwndSelf );
916 char* lpstr = 0;
918 hText = GetClipboardData16(CF_TEXT);
919 text = GlobalLock16(hText);
920 size = GlobalSize16(hText);
922 /* remove carriage returns */
924 lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
925 for(i=0,j=0; i < size && text[i]; i++ )
927 if( text[i] == '\r' &&
928 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
929 lpstr[j++] = text[i];
931 lpstr[j]='\0';
933 TSXChangeProperty(display, request, rprop,
934 XA_STRING, 8, PropModeReplace,
935 lpstr, j);
936 HeapFree( GetProcessHeap(), 0, lpstr );
938 /* close only if we opened before */
940 if(couldOpen) CloseClipboard32();
944 if(rprop == None)
945 TRACE(event,"Request for %s ignored\n", TSXGetAtomName(display,event->target));
947 result.type = SelectionNotify;
948 result.display = display;
949 result.requestor = request;
950 result.selection = event->selection;
951 result.property = rprop;
952 result.target = event->target;
953 result.time = event->time;
954 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
958 /***********************************************************************
959 * EVENT_SelectionNotify
961 static void EVENT_SelectionNotify( XSelectionEvent *event )
963 if (event->selection != XA_PRIMARY) return;
965 if (event->target != XA_STRING) CLIPBOARD_ReadSelection( 0, None );
966 else CLIPBOARD_ReadSelection( event->requestor, event->property );
968 TRACE(clipboard,"\tSelectionNotify done!\n");
972 /***********************************************************************
973 * EVENT_SelectionClear
975 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event )
977 if (event->selection != XA_PRIMARY) return;
978 CLIPBOARD_ReleaseSelection( event->window, pWnd->hwndSelf );
982 /**********************************************************************
983 * EVENT_ClientMessage
985 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event )
987 if (event->message_type != None && event->format == 32)
989 if ((event->message_type == wmProtocols) &&
990 (((Atom) event->data.l[0]) == wmDeleteWindow))
991 SendMessage16( pWnd->hwndSelf, WM_SYSCOMMAND, SC_CLOSE, 0 );
992 else if ( event->message_type == dndProtocol &&
993 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
995 unsigned long data_length;
996 unsigned long aux_long;
997 unsigned char* p_data = NULL;
998 union {
999 Atom atom_aux;
1000 POINT32 pt_aux;
1001 int i;
1002 } u;
1003 int x, y;
1004 BOOL16 bAccept;
1005 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
1006 LPDRAGINFO lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
1007 SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
1008 Window w_aux_root, w_aux_child;
1009 WND* pDropWnd;
1011 if( !lpDragInfo || !spDragInfo ) return;
1013 TSXQueryPointer( display, pWnd->window, &w_aux_root, &w_aux_child,
1014 &x, &y, &u.pt_aux.x, &u.pt_aux.y, (unsigned int*)&aux_long);
1016 lpDragInfo->hScope = pWnd->hwndSelf;
1017 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1019 /* find out drop point and drop window */
1020 if( x < 0 || y < 0 ||
1021 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1022 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1023 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1024 else
1026 bAccept = DRAG_QueryUpdate( pWnd->hwndSelf, spDragInfo, TRUE );
1027 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1029 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1030 GlobalFree16( hDragInfo );
1032 if( bAccept )
1034 TSXGetWindowProperty( display, DefaultRootWindow(display),
1035 dndSelection, 0, 65535, FALSE,
1036 AnyPropertyType, &u.atom_aux, &u.pt_aux.y,
1037 &data_length, &aux_long, &p_data);
1039 if( !aux_long && p_data) /* don't bother if > 64K */
1041 char *p = (char*) p_data;
1042 char *p_drop;
1044 aux_long = 0;
1045 while( *p ) /* calculate buffer size */
1047 p_drop = p;
1048 if((u.i = *p) != -1 )
1049 u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
1050 if( u.i == -1 ) *p = -1; /* mark as "bad" */
1051 else
1053 INT32 len = GetShortPathName32A( p, NULL, 0 );
1054 if (len) aux_long += len + 1;
1055 else *p = -1;
1057 p += strlen(p) + 1;
1059 if( aux_long && aux_long < 65535 )
1061 HDROP16 hDrop;
1062 LPDROPFILESTRUCT lpDrop;
1064 aux_long += sizeof(DROPFILESTRUCT) + 1;
1065 hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
1066 lpDrop = (LPDROPFILESTRUCT) GlobalLock16( hDrop );
1068 if( lpDrop )
1070 lpDrop->wSize = sizeof(DROPFILESTRUCT);
1071 lpDrop->ptMousePos.x = (INT16)x;
1072 lpDrop->ptMousePos.y = (INT16)y;
1073 lpDrop->fInNonClientArea = (BOOL16)
1074 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1075 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1076 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1077 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1078 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT);
1079 p = p_data;
1080 while(*p)
1082 if( *p != -1 ) /* use only "good" entries */
1084 GetShortPathName32A( p, p_drop, 65535 );
1085 p_drop += strlen( p_drop ) + 1;
1087 p += strlen(p) + 1;
1089 *p_drop = '\0';
1090 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1091 (WPARAM16)hDrop, 0L );
1095 if( p_data ) TSXFree(p_data);
1097 } /* WS_EX_ACCEPTFILES */
1098 } /* dndProtocol */
1099 else
1100 TRACE(event, "unrecognized ClientMessage\n" );
1104 /**********************************************************************
1105 * EVENT_EnterNotify
1107 * Install colormap when Wine window is focused in
1108 * self-managed mode with private colormap
1111 void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
1113 if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
1114 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
1115 TSXInstallColormap( display, COLOR_GetColormap() );
1119 /**********************************************************************
1120 * EVENT_MapNotify
1122 void EVENT_MapNotify( HWND32 hWnd, XMapEvent *event )
1124 HWND32 hwndFocus = GetFocus32();
1126 if (hwndFocus && IsChild32( hWnd, hwndFocus ))
1127 FOCUS_SetXFocus( (HWND32)hwndFocus );
1129 return;
1132 /**********************************************************************
1133 * EVENT_Capture
1135 * We need this to be able to generate double click messages
1136 * when menu code captures mouse in the window without CS_DBLCLK style.
1138 HWND32 EVENT_Capture(HWND32 hwnd, INT16 ht)
1140 HWND32 capturePrev = captureWnd;
1142 if (!hwnd)
1144 captureWnd = 0L;
1145 captureHT = 0;
1147 else
1149 WND* wndPtr = WIN_FindWndPtr( hwnd );
1150 if (wndPtr)
1152 TRACE(win, "(0x%04x)\n", hwnd );
1153 captureWnd = hwnd;
1154 captureHT = ht;
1158 if( capturePrev && capturePrev != captureWnd )
1160 WND* wndPtr = WIN_FindWndPtr( capturePrev );
1161 if( wndPtr && (wndPtr->flags & WIN_ISWIN32) )
1162 SendMessage32A( capturePrev, WM_CAPTURECHANGED, 0L, hwnd);
1164 return capturePrev;
1167 /**********************************************************************
1168 * EVENT_GetCaptureInfo
1170 INT16 EVENT_GetCaptureInfo()
1172 return captureHT;
1175 /**********************************************************************
1176 * SetCapture16 (USER.18)
1178 HWND16 WINAPI SetCapture16( HWND16 hwnd )
1180 return (HWND16)EVENT_Capture( hwnd, HTCLIENT );
1184 /**********************************************************************
1185 * SetCapture32 (USER32.464)
1187 HWND32 WINAPI SetCapture32( HWND32 hwnd )
1189 return EVENT_Capture( hwnd, HTCLIENT );
1193 /**********************************************************************
1194 * ReleaseCapture (USER.19) (USER32.439)
1196 void WINAPI ReleaseCapture(void)
1198 TRACE(win, "captureWnd=%04x\n", captureWnd );
1199 if( captureWnd ) EVENT_Capture( 0, 0 );
1203 /**********************************************************************
1204 * GetCapture16 (USER.236)
1206 HWND16 WINAPI GetCapture16(void)
1208 return captureWnd;
1212 /**********************************************************************
1213 * GetCapture32 (USER32.208)
1215 HWND32 WINAPI GetCapture32(void)
1217 return captureWnd;
1221 /***********************************************************************
1222 * GetMouseEventProc (USER.337)
1224 FARPROC16 WINAPI GetMouseEventProc(void)
1226 HMODULE16 hmodule = GetModuleHandle16("USER");
1227 return NE_GetEntryPoint( hmodule, NE_GetOrdinal( hmodule, "Mouse_Event" ));
1231 /***********************************************************************
1232 * Mouse_Event (USER.299)
1234 void WINAPI Mouse_Event( CONTEXT *context )
1236 /* Register values:
1237 * AX = mouse event
1238 * BX = horizontal displacement if AX & ME_MOVE
1239 * CX = vertical displacement if AX & ME_MOVE
1240 * DX = button state (?)
1241 * SI = mouse event flags (?)
1243 Window root, child;
1244 int rootX, rootY, winX, winY;
1245 unsigned int state;
1247 if (AX_reg(context) & ME_MOVE)
1249 /* We have to actually move the cursor */
1250 TSXWarpPointer( display, rootWindow, None, 0, 0, 0, 0,
1251 (short)BX_reg(context), (short)CX_reg(context) );
1252 return;
1254 if (!TSXQueryPointer( display, rootWindow, &root, &child,
1255 &rootX, &rootY, &winX, &winY, &state )) return;
1256 if (AX_reg(context) & ME_LDOWN)
1257 hardware_event( WM_LBUTTONDOWN, EVENT_XStateToKeyState( state ),
1258 0L, winX, winY, GetTickCount(), 0 );
1259 if (AX_reg(context) & ME_LUP)
1260 hardware_event( WM_LBUTTONUP, EVENT_XStateToKeyState( state ),
1261 0L, winX, winY, GetTickCount(), 0 );
1262 if (AX_reg(context) & ME_RDOWN)
1263 hardware_event( WM_RBUTTONDOWN, EVENT_XStateToKeyState( state ),
1264 0L, winX, winY, GetTickCount(), 0 );
1265 if (AX_reg(context) & ME_RUP)
1266 hardware_event( WM_RBUTTONUP, EVENT_XStateToKeyState( state ),
1267 0L, winX, winY, GetTickCount(), 0 );
1271 /**********************************************************************
1272 * EnableHardwareInput (USER.331)
1274 BOOL16 WINAPI EnableHardwareInput(BOOL16 bEnable)
1276 BOOL16 bOldState = InputEnabled;
1277 FIXME(event,"(%d) - stub\n", bEnable);
1278 InputEnabled = bEnable;
1279 return bOldState;
1283 /***********************************************************************
1284 * SwapMouseButton16 (USER.186)
1286 BOOL16 WINAPI SwapMouseButton16( BOOL16 fSwap )
1288 BOOL16 ret = SwappedButtons;
1289 SwappedButtons = fSwap;
1290 return ret;
1294 /***********************************************************************
1295 * SwapMouseButton32 (USER32.537)
1297 BOOL32 WINAPI SwapMouseButton32( BOOL32 fSwap )
1299 BOOL32 ret = SwappedButtons;
1300 SwappedButtons = fSwap;
1301 return ret;