Added the TEXT() and MAKELRESULT() definitions.
[wine/multimedia.git] / windows / event.c
blob3c96220399d0597407cdf3ceba2f23aa8e7f6359
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 "mouse.h"
40 #include "debug.h"
41 #include "dde_proc.h"
42 #include "winsock.h"
43 #include "mouse.h"
44 #include "x11drv.h"
46 #define NB_BUTTONS 3 /* Windows can handle 3 buttons */
48 #define DndNotDnd -1 /* OffiX drag&drop */
49 #define DndUnknown 0
50 #define DndRawData 1
51 #define DndFile 2
52 #define DndFiles 3
53 #define DndText 4
54 #define DndDir 5
55 #define DndLink 6
56 #define DndExe 7
58 #define DndEND 8
60 #define DndURL 128 /* KDE drag&drop */
63 /* X context to associate a hwnd to an X window */
64 static XContext winContext = 0;
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 int 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 static void EVENT_GetGeometry( Window win, int *px, int *py,
110 unsigned int *pwidth, unsigned int *pheight );
112 /***********************************************************************
113 * EVENT_Init
115 * Initialize network IO.
117 BOOL32 EVENT_Init(void)
119 int i;
120 for( i = 0; i < 3; i++ )
121 FD_ZERO( __event_io_set + i );
123 __event_max_fd = __event_x_connection = ConnectionNumber(display);
124 FD_SET( __event_x_connection, &__event_io_set[EVENT_IO_READ] );
125 __event_max_fd++;
126 return TRUE;
129 /***********************************************************************
130 * EVENT_AddIO
132 void EVENT_AddIO( int fd, unsigned io_type )
134 FD_SET( fd, &__event_io_set[io_type] );
135 if( __event_max_fd <= fd ) __event_max_fd = fd + 1;
138 void EVENT_DeleteIO( int fd, unsigned io_type )
140 FD_CLR( fd, &__event_io_set[io_type] );
143 /***********************************************************************
144 * EVENT_ProcessEvent
146 * Process an X event.
148 void EVENT_ProcessEvent( XEvent *event )
150 WND *pWnd;
152 if ( TSXFindContext( display, event->xany.window, winContext,
153 (char **)&pWnd ) != 0) {
154 if ( event->type == ClientMessage) {
155 /* query window (drag&drop event contains only drag window) */
156 Window root, child;
157 int root_x, root_y, child_x, child_y;
158 unsigned u;
159 TSXQueryPointer( display, rootWindow, &root, &child,
160 &root_x, &root_y, &child_x, &child_y, &u);
161 if (TSXFindContext( display, child, winContext, (char **)&pWnd ) != 0)
162 return;
163 } else {
164 pWnd = NULL; /* Not for a registered window */
168 TRACE(event, "Got event %s for hwnd %04x\n",
169 event_names[event->type], pWnd? pWnd->hwndSelf : 0 );
171 switch(event->type)
173 case KeyPress:
174 case KeyRelease:
175 EVENT_Key( pWnd, (XKeyEvent*)event );
176 break;
178 case ButtonPress:
179 EVENT_ButtonPress( pWnd, (XButtonEvent*)event );
180 break;
182 case ButtonRelease:
183 EVENT_ButtonRelease( pWnd, (XButtonEvent*)event );
184 break;
186 case MotionNotify:
187 /* Wine between two fast machines across the overloaded campus
188 ethernet gets very boged down in MotionEvents. The following
189 simply finds the last motion event in the queue and drops
190 the rest. On a good link events are servered before they build
191 up so this doesn't take place. On a slow link this may cause
192 problems if the event order is important. I'm not yet seen
193 of any problems. Jon 7/6/96.
195 while (TSXCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
196 MotionNotify, event));
197 EVENT_MotionNotify( pWnd, (XMotionEvent*)event );
198 break;
200 case FocusIn:
201 if (!pWnd) return;
202 EVENT_FocusIn( pWnd, (XFocusChangeEvent*)event );
203 break;
205 case FocusOut:
206 if (!pWnd) return;
207 EVENT_FocusOut( pWnd, (XFocusChangeEvent*)event );
208 break;
210 case Expose:
211 if (!pWnd) return;
212 if (EVENT_Expose( pWnd, (XExposeEvent *)event )) {
213 /* need to process ConfigureNotify first */
214 XEvent new_event;
216 /* attempt to find and process the ConfigureNotify event now */
217 if (TSXCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
218 ConfigureNotify, &new_event)) {
219 EVENT_ProcessEvent( &new_event );
220 if (!EVENT_Expose( pWnd, (XExposeEvent *)event ))
221 break;
224 /* no luck at this time, defer Expose event for later */
225 /* use "type" for an event counter, it is never rechecked */
226 if (!pWnd->expose_event) {
227 pWnd->expose_event = malloc( sizeof(XExposeEvent) );
228 pWnd->expose_event[0] = *(XExposeEvent *)event;
229 pWnd->expose_event[0].type = 1;
230 } else {
231 int i;
233 i = ++pWnd->expose_event[0].type;
234 pWnd->expose_event = realloc( pWnd->expose_event,
235 i * sizeof(XExposeEvent) );
236 pWnd->expose_event[i-1] = *(XExposeEvent *)event;
237 FIXME(x11, "Try and combine Expose events? %d queued.\n", i);
240 break;
242 case GraphicsExpose:
243 if (!pWnd) return;
244 EVENT_GraphicsExpose( pWnd, (XGraphicsExposeEvent *)event );
245 break;
247 case ConfigureNotify:
248 if (!pWnd) return;
249 EVENT_ConfigureNotify( pWnd, (XConfigureEvent*)event );
250 if (pWnd->expose_event) {
251 /* process deferred Expose event(s) */
252 int i;
254 for (i=0; i<pWnd->expose_event[0].type; i++) {
255 if(EVENT_Expose( pWnd, &pWnd->expose_event[i] ))
256 ERR(x11, "Unprocessed expose event discarded\n");
258 free( pWnd->expose_event );
259 pWnd->expose_event = NULL;
261 break;
263 case SelectionRequest:
264 if (!pWnd) return;
265 EVENT_SelectionRequest( pWnd, (XSelectionRequestEvent *)event );
266 break;
268 case SelectionNotify:
269 if (!pWnd) return;
270 EVENT_SelectionNotify( (XSelectionEvent *)event );
271 break;
273 case SelectionClear:
274 if (!pWnd) return;
275 EVENT_SelectionClear( pWnd, (XSelectionClearEvent*) event );
276 break;
278 case ClientMessage:
279 if (!pWnd) return;
280 EVENT_ClientMessage( pWnd, (XClientMessageEvent *) event );
281 break;
283 /* case EnterNotify:
284 * EVENT_EnterNotify( pWnd, (XCrossingEvent *) event );
285 * break;
287 case NoExpose:
288 break;
290 /* We get all these because of StructureNotifyMask. */
291 case UnmapNotify:
292 case CirculateNotify:
293 case CreateNotify:
294 case DestroyNotify:
295 case GravityNotify:
296 case ReparentNotify:
297 break;
299 case MapNotify:
300 if (!pWnd) return;
301 EVENT_MapNotify( pWnd->hwndSelf, (XMapEvent *)event );
302 break;
304 default:
305 WARN(event, "Unprocessed event %s for hwnd %04x\n",
306 event_names[event->type], pWnd? pWnd->hwndSelf : 0 );
307 break;
312 /***********************************************************************
313 * EVENT_RegisterWindow
315 * Associate an X window to a HWND.
317 void EVENT_RegisterWindow( WND *pWnd )
319 if (wmProtocols == None)
320 wmProtocols = TSXInternAtom( display, "WM_PROTOCOLS", True );
321 if (wmDeleteWindow == None)
322 wmDeleteWindow = TSXInternAtom( display, "WM_DELETE_WINDOW", True );
323 if( dndProtocol == None )
324 dndProtocol = TSXInternAtom( display, "DndProtocol" , False );
325 if( dndSelection == None )
326 dndSelection = TSXInternAtom( display, "DndSelection" , False );
328 TSXSetWMProtocols( display, pWnd->window, &wmDeleteWindow, 1 );
330 if (!winContext) winContext = TSXUniqueContext();
331 TSXSaveContext( display, pWnd->window, winContext, (char *)pWnd );
334 /***********************************************************************
335 * EVENT_DestroyWindow
337 void EVENT_DestroyWindow( WND *pWnd )
339 XEvent xe;
341 if (pWnd->expose_event) {
342 free( pWnd->expose_event );
343 pWnd->expose_event = NULL;
345 TSXDeleteContext( display, pWnd->window, winContext );
346 TSXDestroyWindow( display, pWnd->window );
347 while( TSXCheckWindowEvent(display, pWnd->window, NoEventMask, &xe) );
351 /***********************************************************************
352 * IsUserIdle (USER.333)
354 * Check if we have pending X events.
356 BOOL16 WINAPI IsUserIdle(void)
358 struct timeval timeout = {0, 0};
359 fd_set check_set;
361 FD_ZERO(&check_set);
362 FD_SET(__event_x_connection, &check_set);
363 if( select(__event_x_connection + 1, &check_set, NULL, NULL, &timeout) > 0 )
364 return TRUE;
365 return FALSE;
369 /***********************************************************************
370 * EVENT_WaitNetEvent
372 * Wait for a network event, optionally sleeping until one arrives.
373 * Return TRUE if an event is pending, FALSE on timeout or error
374 * (for instance lost connection with the server).
376 BOOL32 EVENT_WaitNetEvent( BOOL32 sleep, BOOL32 peek )
378 XEvent event;
379 LONG maxWait = sleep ? TIMER_GetNextExpiration() : 0;
380 int pending = TSXPending(display);
382 /* Wait for an event or a timeout. If maxWait is -1, we have no timeout;
383 * in this case, we fall through directly to the XNextEvent loop.
386 if ((maxWait != -1) && !pending)
388 int num_pending;
389 struct timeval timeout;
390 fd_set io_set[3];
392 memcpy( io_set, __event_io_set, sizeof(io_set) );
394 timeout.tv_usec = (maxWait % 1000) * 1000;
395 timeout.tv_sec = maxWait / 1000;
397 #ifdef CONFIG_IPC
398 sigsetjmp(env_wait_x, 1);
399 stop_wait_op= CONT;
401 if (DDE_GetRemoteMessage()) {
402 while(DDE_GetRemoteMessage())
404 return TRUE;
406 stop_wait_op = STOP_WAIT_X;
407 /* The code up to the next "stop_wait_op = CONT" must be reentrant */
408 num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
409 &io_set[EVENT_IO_WRITE],
410 &io_set[EVENT_IO_EXCEPT], &timeout );
411 if ( num_pending == 0 )
413 stop_wait_op = CONT;
414 TIMER_ExpireTimers();
415 return FALSE;
417 else stop_wait_op = CONT;
418 #else /* CONFIG_IPC */
419 num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
420 &io_set[EVENT_IO_WRITE],
421 &io_set[EVENT_IO_EXCEPT], &timeout );
422 if ( num_pending == 0)
424 /* Timeout or error */
425 TIMER_ExpireTimers();
426 return FALSE;
428 #endif /* CONFIG_IPC */
430 /* Winsock asynchronous services */
432 if( FD_ISSET( __event_x_connection, &io_set[EVENT_IO_READ]) )
434 num_pending--;
435 if( num_pending )
436 WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
438 else /* no X events */
439 return WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
441 else if(!pending)
442 { /* Wait for X11 input. */
443 fd_set set;
445 FD_ZERO(&set);
446 FD_SET(__event_x_connection, &set);
447 select(__event_x_connection + 1, &set, 0, 0, 0 );
450 /* Process current X event (and possibly others that occurred in the meantime) */
452 EnterCriticalSection(&X11DRV_CritSection);
453 while (XPending( display ))
456 #ifdef CONFIG_IPC
457 if (DDE_GetRemoteMessage())
459 LeaveCriticalSection(&X11DRV_CritSection);
460 while(DDE_GetRemoteMessage()) ;
461 return TRUE;
463 #endif /* CONFIG_IPC */
465 XNextEvent( display, &event );
467 LeaveCriticalSection(&X11DRV_CritSection);
468 if( peek )
470 WND* pWnd;
471 MESSAGEQUEUE* pQ;
474 /* Check only for those events which can be processed
475 * internally. */
477 if( event.type == MotionNotify ||
478 event.type == ButtonPress || event.type == ButtonRelease ||
479 event.type == KeyPress || event.type == KeyRelease ||
480 event.type == SelectionRequest || event.type == SelectionClear ||
481 event.type == ClientMessage )
483 EVENT_ProcessEvent( &event );
484 continue;
487 if (TSXFindContext( display, ((XAnyEvent *)&event)->window, winContext,
488 (char **)&pWnd ) || (event.type == NoExpose))
489 pWnd = NULL;
491 if( pWnd )
493 if( (pQ = (MESSAGEQUEUE*)GlobalLock16(pWnd->hmemTaskQ)) )
495 pQ->flags |= QUEUE_FLAG_XEVENT;
496 PostEvent(pQ->hTask);
497 TSXPutBackEvent(display, &event);
498 break;
502 else EVENT_ProcessEvent( &event );
503 EnterCriticalSection(&X11DRV_CritSection);
505 LeaveCriticalSection(&X11DRV_CritSection);
506 return TRUE;
510 /***********************************************************************
511 * EVENT_Synchronize
513 * Synchronize with the X server. Should not be used too often.
515 void EVENT_Synchronize()
517 XEvent event;
519 /* Use of the X critical section is needed or we have a small
520 * race between XPending() and XNextEvent().
522 EnterCriticalSection( &X11DRV_CritSection );
523 XSync( display, False );
524 while (XPending( display ))
526 XNextEvent( display, &event );
527 /* unlock X critsection for EVENT_ProcessEvent() might switch tasks */
528 LeaveCriticalSection( &X11DRV_CritSection );
529 EVENT_ProcessEvent( &event );
530 EnterCriticalSection( &X11DRV_CritSection );
532 LeaveCriticalSection( &X11DRV_CritSection );
535 /***********************************************************************
536 * EVENT_QueryZOrder
538 * Try to synchronize internal z-order with the window manager's.
539 * Probably a futile endeavor.
541 static BOOL32 __check_query_condition( WND** pWndA, WND** pWndB )
543 /* return TRUE if we have at least two managed windows */
545 for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
546 if( (*pWndA)->flags & WIN_MANAGED &&
547 (*pWndA)->dwStyle & WS_VISIBLE ) break;
548 if( *pWndA )
549 for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
550 if( (*pWndB)->flags & WIN_MANAGED &&
551 (*pWndB)->dwStyle & WS_VISIBLE ) break;
552 return ((*pWndB) != NULL);
555 static Window __get_common_ancestor( Window A, Window B,
556 Window** children, unsigned* total )
558 /* find the real root window */
560 Window root, *childrenB;
561 unsigned totalB;
565 if( *children ) TSXFree( *children );
566 TSXQueryTree( display, A, &root, &A, children, total );
567 TSXQueryTree( display, B, &root, &B, &childrenB, &totalB );
568 if( childrenB ) TSXFree( childrenB );
569 } while( A != B && A && B );
570 return ( A && B ) ? A : 0 ;
573 static Window __get_top_decoration( Window w, Window ancestor )
575 Window* children, root, prev = w, parent = w;
576 unsigned total;
580 w = parent;
581 TSXQueryTree( display, w, &root, &parent, &children, &total );
582 if( children ) TSXFree( children );
583 } while( parent && parent != ancestor );
584 TRACE(event, "\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
585 return ( parent ) ? w : 0 ;
588 static unsigned __td_lookup( Window w, Window* list, unsigned max )
590 unsigned i;
591 for( i = 0; i < max; i++ ) if( list[i] == w ) break;
592 return i;
595 static BOOL32 EVENT_QueryZOrder( WND* pWndCheck )
597 BOOL32 bRet = FALSE;
598 HWND32 hwndInsertAfter = HWND_TOP;
599 WND* pWnd, *pWndZ = WIN_GetDesktop()->child;
600 Window w, parent, *children = NULL;
601 unsigned total, check, pos, best;
603 if( !__check_query_condition(&pWndZ, &pWnd) ) return TRUE;
605 parent = __get_common_ancestor( pWndZ->window, pWnd->window,
606 &children, &total );
607 if( parent && children )
609 w = __get_top_decoration( pWndCheck->window, parent );
610 if( w != children[total - 1] )
612 check = __td_lookup( w, children, total );
613 best = total;
614 for( pWnd = pWndZ; pWnd; pWnd = pWnd->next )
616 if( pWnd != pWndCheck )
618 if( !(pWnd->flags & WIN_MANAGED) ||
619 !(w = __get_top_decoration( pWnd->window, parent )) )
620 continue;
621 pos = __td_lookup( w, children, total );
622 if( pos < best && pos > check )
624 best = pos;
625 hwndInsertAfter = pWnd->hwndSelf;
627 if( check - best == 1 ) break;
630 WIN_UnlinkWindow( pWndCheck->hwndSelf );
631 WIN_LinkWindow( pWndCheck->hwndSelf, hwndInsertAfter);
634 if( children ) TSXFree( children );
635 return bRet;
639 /***********************************************************************
640 * EVENT_XStateToKeyState
642 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
643 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
645 static WORD EVENT_XStateToKeyState( int state )
647 int kstate = 0;
649 if (state & Button1Mask) kstate |= MK_LBUTTON;
650 if (state & Button2Mask) kstate |= MK_MBUTTON;
651 if (state & Button3Mask) kstate |= MK_RBUTTON;
652 if (state & ShiftMask) kstate |= MK_SHIFT;
653 if (state & ControlMask) kstate |= MK_CONTROL;
654 return kstate;
657 /***********************************************************************
658 * EVENT_QueryPointer
660 BOOL32 EVENT_QueryPointer( DWORD *posX, DWORD *posY, DWORD *state )
662 Window root, child;
663 int rootX, rootY, winX, winY;
664 unsigned int xstate;
666 if (!TSXQueryPointer( display, rootWindow, &root, &child,
667 &rootX, &rootY, &winX, &winY, &xstate ))
668 return FALSE;
670 *posX = (DWORD)winX;
671 *posY = (DWORD)winY;
672 *state = EVENT_XStateToKeyState( xstate );
674 return TRUE;
677 /***********************************************************************
678 * EVENT_Expose
680 static int EVENT_Expose( WND *pWnd, XExposeEvent *event )
682 RECT32 rect;
683 int x, y;
684 unsigned int width, height;
686 /* When scrolling, many (fvwm2-based) window managers send the Expose
687 * event before sending the ConfigureNotify event, and we don't like
688 * that, so before processing the Expose event, we check whether the
689 * geometry has changed, and if so, we defer the Expose event until
690 * we get the ConfigureNotify event. -Ove KÃ¥ven */
691 EVENT_GetGeometry( event->window, &x, &y, &width, &height );
693 if ( x != pWnd->rectWindow.left || y != pWnd->rectWindow.top ||
694 (width != pWnd->rectWindow.right - pWnd->rectWindow.left) ||
695 (height != pWnd->rectWindow.bottom - pWnd->rectWindow.top))
696 return 1; /* tell EVENT_ProcessEvent() to defer it */
698 /* Make position relative to client area instead of window */
699 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
700 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
701 rect.right = rect.left + event->width;
702 rect.bottom = rect.top + event->height;
704 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
705 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
706 (event->count ? 0 : RDW_ERASENOW), 0 );
707 return 0;
711 /***********************************************************************
712 * EVENT_GraphicsExpose
714 * This is needed when scrolling area is partially obscured
715 * by non-Wine X window.
717 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event )
719 RECT32 rect;
721 /* Make position relative to client area instead of window */
722 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
723 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
724 rect.right = rect.left + event->width;
725 rect.bottom = rect.top + event->height;
727 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
728 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
729 (event->count ? 0 : RDW_ERASENOW), 0 );
733 /***********************************************************************
734 * EVENT_Key
736 * Handle a X key event
738 static void EVENT_Key( WND *pWnd, XKeyEvent *event )
740 KEYBOARD_HandleEvent( pWnd, event );
744 /***********************************************************************
745 * EVENT_MotionNotify
747 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event )
749 int xOffset = pWnd? pWnd->rectWindow.left : 0;
750 int yOffset = pWnd? pWnd->rectWindow.top : 0;
752 MOUSE_SendEvent( MOUSEEVENTF_MOVE,
753 xOffset + event->x, yOffset + event->y,
754 EVENT_XStateToKeyState( event->state ),
755 event->time - MSG_WineStartTicks,
756 pWnd? pWnd->hwndSelf : 0 );
760 /***********************************************************************
761 * EVENT_DummyMotionNotify
763 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
765 void EVENT_DummyMotionNotify(void)
767 DWORD winX, winY, state;
769 if ( EVENT_QueryPointer( &winX, &winY, &state ) )
771 MOUSE_SendEvent( MOUSEEVENTF_MOVE, winX, winY, state,
772 GetTickCount(), 0 );
777 /***********************************************************************
778 * EVENT_ButtonPress
780 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event )
782 static WORD statusCodes[NB_BUTTONS] =
783 { MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_RIGHTDOWN };
784 int buttonNum = event->button - 1;
786 int xOffset = pWnd? pWnd->rectWindow.left : 0;
787 int yOffset = pWnd? pWnd->rectWindow.top : 0;
789 if (buttonNum >= NB_BUTTONS) return;
791 MOUSE_SendEvent( statusCodes[buttonNum],
792 xOffset + event->x, yOffset + event->y,
793 EVENT_XStateToKeyState( event->state ),
794 event->time - MSG_WineStartTicks,
795 pWnd? pWnd->hwndSelf : 0 );
799 /***********************************************************************
800 * EVENT_ButtonRelease
802 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event )
804 static WORD statusCodes[NB_BUTTONS] =
805 { MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_RIGHTUP };
806 int buttonNum = event->button - 1;
808 int xOffset = pWnd? pWnd->rectWindow.left : 0;
809 int yOffset = pWnd? pWnd->rectWindow.top : 0;
811 if (buttonNum >= NB_BUTTONS) return;
813 MOUSE_SendEvent( statusCodes[buttonNum],
814 xOffset + event->x, yOffset + event->y,
815 EVENT_XStateToKeyState( event->state ),
816 event->time - MSG_WineStartTicks,
817 pWnd? pWnd->hwndSelf : 0 );
821 /**********************************************************************
822 * EVENT_FocusIn
824 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event )
826 if (Options.managed) EVENT_QueryZOrder( pWnd );
828 if (event->detail != NotifyPointer)
830 HWND32 hwnd = pWnd->hwndSelf;
832 if (hwnd != GetActiveWindow32())
834 WINPOS_ChangeActiveWindow( hwnd, FALSE );
835 KEYBOARD_UpdateState();
837 if ((hwnd != GetFocus32()) && !IsChild32( hwnd, GetFocus32()))
838 SetFocus32( hwnd );
843 /**********************************************************************
844 * EVENT_FocusOut
846 * Note: only top-level override-redirect windows get FocusOut events.
848 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event )
850 if (event->detail != NotifyPointer)
852 HWND32 hwnd = pWnd->hwndSelf;
854 if (hwnd == GetActiveWindow32())
855 WINPOS_ChangeActiveWindow( 0, FALSE );
856 if ((hwnd == GetFocus32()) || IsChild32( hwnd, GetFocus32()))
857 SetFocus32( 0 );
861 /**********************************************************************
862 * EVENT_CheckFocus
864 BOOL32 EVENT_CheckFocus(void)
866 WND* pWnd;
867 Window xW;
868 int state;
870 TSXGetInputFocus(display, &xW, &state);
871 if( xW == None ||
872 TSXFindContext(display, xW, winContext, (char **)&pWnd) )
873 return FALSE;
874 return TRUE;
878 /**********************************************************************
879 * EVENT_GetGeometry
881 * Helper function for ConfigureNotify handling.
882 * Get the new geometry of a window relative to the root window.
884 static void EVENT_GetGeometry( Window win, int *px, int *py,
885 unsigned int *pwidth, unsigned int *pheight )
887 Window root, parent, *children;
888 int xpos, ypos;
889 unsigned int width, height, border, depth, nb_children;
891 if (!TSXGetGeometry( display, win, &root, px, py, pwidth, pheight,
892 &border, &depth )) return;
893 if (win == rootWindow)
895 *px = *py = 0;
896 return;
899 for (;;)
901 if (!TSXQueryTree(display, win, &root, &parent, &children, &nb_children))
902 return;
903 TSXFree( children );
904 if (parent == rootWindow) break;
905 win = parent;
906 if (!TSXGetGeometry( display, win, &root, &xpos, &ypos,
907 &width, &height, &border, &depth )) return;
908 *px += xpos;
909 *py += ypos;
914 /**********************************************************************
915 * EVENT_ConfigureNotify
917 * The ConfigureNotify event is only selected on top-level windows
918 * when the -managed flag is used.
920 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event )
922 WINDOWPOS32 winpos;
923 RECT32 newWindowRect, newClientRect;
924 HRGN32 hrgnOldPos, hrgnNewPos;
925 Window above = event->above;
926 int x, y;
927 unsigned int width, height;
929 assert (pWnd->flags & WIN_MANAGED);
931 /* We don't rely on the event geometry info, because it is relative
932 * to parent and not to root, and it may be wrong (XFree sets x,y to 0,0
933 * if the window hasn't moved).
935 EVENT_GetGeometry( event->window, &x, &y, &width, &height );
937 /* Fill WINDOWPOS struct */
938 winpos.flags = SWP_NOACTIVATE | SWP_NOZORDER;
939 winpos.hwnd = pWnd->hwndSelf;
940 winpos.x = x;
941 winpos.y = y;
942 winpos.cx = width;
943 winpos.cy = height;
945 /* Check for unchanged attributes */
946 if (winpos.x == pWnd->rectWindow.left && winpos.y == pWnd->rectWindow.top)
947 winpos.flags |= SWP_NOMOVE;
948 if ((winpos.cx == pWnd->rectWindow.right - pWnd->rectWindow.left) &&
949 (winpos.cy == pWnd->rectWindow.bottom - pWnd->rectWindow.top))
950 winpos.flags |= SWP_NOSIZE;
951 else
953 RECT32 rect = { 0, 0, pWnd->rectWindow.right - pWnd->rectWindow.left,
954 pWnd->rectWindow.bottom - pWnd->rectWindow.top };
955 DCE_InvalidateDCE( pWnd, &rect );
958 /* Send WM_WINDOWPOSCHANGING */
959 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)&winpos );
961 /* Calculate new position and size */
962 newWindowRect.left = x;
963 newWindowRect.right = x + width;
964 newWindowRect.top = y;
965 newWindowRect.bottom = y + height;
967 WINPOS_SendNCCalcSize( winpos.hwnd, TRUE, &newWindowRect,
968 &pWnd->rectWindow, &pWnd->rectClient,
969 &winpos, &newClientRect );
971 hrgnOldPos = CreateRectRgnIndirect32( &pWnd->rectWindow );
972 hrgnNewPos = CreateRectRgnIndirect32( &newWindowRect );
973 CombineRgn32( hrgnOldPos, hrgnOldPos, hrgnNewPos, RGN_DIFF );
974 DeleteObject32(hrgnOldPos);
975 DeleteObject32(hrgnNewPos);
977 /* Set new size and position */
978 pWnd->rectWindow = newWindowRect;
979 pWnd->rectClient = newClientRect;
980 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)&winpos );
982 if (!IsWindow32( winpos.hwnd )) return;
983 if( above == None ) /* absolute bottom */
985 WIN_UnlinkWindow( winpos.hwnd );
986 WIN_LinkWindow( winpos.hwnd, HWND_BOTTOM);
988 else EVENT_QueryZOrder( pWnd ); /* try to outsmart window manager */
992 /***********************************************************************
993 * EVENT_SelectionRequest
995 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event )
997 XSelectionEvent result;
998 Atom rprop = None;
999 Window request = event->requestor;
1001 if(event->target == XA_STRING)
1003 HANDLE16 hText;
1004 LPSTR text;
1005 int size,i,j;
1007 rprop = event->property;
1009 if(rprop == None) rprop = event->target;
1011 if(event->selection!=XA_PRIMARY) rprop = None;
1012 else if(!CLIPBOARD_IsPresent(CF_OEMTEXT)) rprop = None;
1013 else
1015 /* open to make sure that clipboard is available */
1017 BOOL32 couldOpen = OpenClipboard32( pWnd->hwndSelf );
1018 char* lpstr = 0;
1020 hText = GetClipboardData16(CF_TEXT);
1021 text = GlobalLock16(hText);
1022 size = GlobalSize16(hText);
1024 /* remove carriage returns */
1026 lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
1027 for(i=0,j=0; i < size && text[i]; i++ )
1029 if( text[i] == '\r' &&
1030 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
1031 lpstr[j++] = text[i];
1033 lpstr[j]='\0';
1035 TSXChangeProperty(display, request, rprop,
1036 XA_STRING, 8, PropModeReplace,
1037 lpstr, j);
1038 HeapFree( GetProcessHeap(), 0, lpstr );
1040 /* close only if we opened before */
1042 if(couldOpen) CloseClipboard32();
1046 if(rprop == None)
1047 TRACE(event,"Request for %s ignored\n", TSXGetAtomName(display,event->target));
1049 result.type = SelectionNotify;
1050 result.display = display;
1051 result.requestor = request;
1052 result.selection = event->selection;
1053 result.property = rprop;
1054 result.target = event->target;
1055 result.time = event->time;
1056 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
1060 /***********************************************************************
1061 * EVENT_SelectionNotify
1063 static void EVENT_SelectionNotify( XSelectionEvent *event )
1065 if (event->selection != XA_PRIMARY) return;
1067 if (event->target != XA_STRING) CLIPBOARD_ReadSelection( 0, None );
1068 else CLIPBOARD_ReadSelection( event->requestor, event->property );
1070 TRACE(clipboard,"\tSelectionNotify done!\n");
1074 /***********************************************************************
1075 * EVENT_SelectionClear
1077 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event )
1079 if (event->selection != XA_PRIMARY) return;
1080 CLIPBOARD_ReleaseSelection( event->window, pWnd->hwndSelf );
1084 /**********************************************************************
1085 * EVENT_DropFromOffix
1087 * don't know if it still works (last Changlog is from 96/11/04)
1089 static void EVENT_DropFromOffiX( WND *pWnd, XClientMessageEvent *event )
1091 unsigned long data_length;
1092 unsigned long aux_long;
1093 unsigned char* p_data = NULL;
1094 union {
1095 Atom atom_aux;
1096 POINT32 pt_aux;
1097 int i;
1098 } u;
1099 int x, y;
1100 BOOL16 bAccept;
1101 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
1102 LPDRAGINFO lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
1103 SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
1104 Window w_aux_root, w_aux_child;
1105 WND* pDropWnd;
1107 if( !lpDragInfo || !spDragInfo ) return;
1109 TSXQueryPointer( display, pWnd->window, &w_aux_root, &w_aux_child,
1110 &x, &y, &u.pt_aux.x, &u.pt_aux.y, (unsigned int*)&aux_long);
1112 lpDragInfo->hScope = pWnd->hwndSelf;
1113 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1115 /* find out drop point and drop window */
1116 if( x < 0 || y < 0 ||
1117 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1118 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1119 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1120 else
1122 bAccept = DRAG_QueryUpdate( pWnd->hwndSelf, spDragInfo, TRUE );
1123 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1125 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1126 GlobalFree16( hDragInfo );
1128 if( bAccept )
1130 TSXGetWindowProperty( display, DefaultRootWindow(display),
1131 dndSelection, 0, 65535, FALSE,
1132 AnyPropertyType, &u.atom_aux, &u.pt_aux.y,
1133 &data_length, &aux_long, &p_data);
1135 if( !aux_long && p_data) /* don't bother if > 64K */
1137 char *p = (char*) p_data;
1138 char *p_drop;
1140 aux_long = 0;
1141 while( *p ) /* calculate buffer size */
1143 p_drop = p;
1144 if((u.i = *p) != -1 )
1145 u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
1146 if( u.i == -1 ) *p = -1; /* mark as "bad" */
1147 else
1149 INT32 len = GetShortPathName32A( p, NULL, 0 );
1150 if (len) aux_long += len + 1;
1151 else *p = -1;
1153 p += strlen(p) + 1;
1155 if( aux_long && aux_long < 65535 )
1157 HDROP16 hDrop;
1158 LPDROPFILESTRUCT16 lpDrop;
1160 aux_long += sizeof(DROPFILESTRUCT16) + 1;
1161 hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
1162 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop );
1164 if( lpDrop )
1166 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1167 lpDrop->ptMousePos.x = (INT16)x;
1168 lpDrop->ptMousePos.y = (INT16)y;
1169 lpDrop->fInNonClientArea = (BOOL16)
1170 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1171 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1172 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1173 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1174 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1175 p = p_data;
1176 while(*p)
1178 if( *p != -1 ) /* use only "good" entries */
1180 GetShortPathName32A( p, p_drop, 65535 );
1181 p_drop += strlen( p_drop ) + 1;
1183 p += strlen(p) + 1;
1185 *p_drop = '\0';
1186 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1187 (WPARAM16)hDrop, 0L );
1191 if( p_data ) TSXFree(p_data);
1193 } /* WS_EX_ACCEPTFILES */
1196 /**********************************************************************
1197 * EVENT_DropURLs
1199 * drop items are separated by \n
1200 * each item is prefixed by its mime type
1202 * event->data.l[3], event->data.l[4] contains drop x,y position
1204 static void EVENT_DropURLs( WND *pWnd, XClientMessageEvent *event )
1206 WND *pDropWnd;
1207 unsigned long data_length;
1208 unsigned long aux_long, drop_len = 0;
1209 unsigned char *p_data = NULL; /* property data */
1210 char *p_drop = NULL;
1211 char *p, *next;
1212 int x, y, drop32 = FALSE ;
1213 union {
1214 Atom atom_aux;
1215 POINT32 pt_aux;
1216 int i;
1217 Window w_aux;
1218 } u; /* unused */
1219 union {
1220 HDROP16 h16;
1221 HDROP32 h32;
1222 } hDrop;
1224 drop32 = pWnd->flags & WIN_ISWIN32;
1226 if (!(pWnd->dwExStyle & WS_EX_ACCEPTFILES))
1227 return;
1229 TSXGetWindowProperty( display, DefaultRootWindow(display),
1230 dndSelection, 0, 65535, FALSE,
1231 AnyPropertyType, &u.atom_aux, &u.i,
1232 &data_length, &aux_long, &p_data);
1233 if (aux_long)
1234 WARN(event,"property too large, truncated!\n");
1235 TRACE(event,"urls=%s\n", p_data);
1237 if( !aux_long && p_data) { /* don't bother if > 64K */
1238 /* calculate length */
1239 p = p_data;
1240 next = strchr(p, '\n');
1241 while (p) {
1242 if (next) *next=0;
1243 if (strncmp(p,"file:",5) == 0 ) {
1244 INT32 len = GetShortPathName32A( p+5, NULL, 0 );
1245 if (len) drop_len += len + 1;
1247 if (next) {
1248 *next = '\n';
1249 p = next + 1;
1250 next = strchr(p, '\n');
1251 } else {
1252 p = NULL;
1256 if( drop_len && drop_len < 65535 ) {
1257 TSXQueryPointer( display, rootWindow, &u.w_aux, &u.w_aux,
1258 &x, &y, &u.i, &u.i, &u.i);
1259 pDropWnd = WIN_FindWndPtr( pWnd->hwndSelf );
1261 if (drop32) {
1262 LPDROPFILESTRUCT32 lpDrop;
1263 drop_len += sizeof(DROPFILESTRUCT32) + 1;
1264 hDrop.h32 = (HDROP32)GlobalAlloc32( GMEM_SHARE, drop_len );
1265 lpDrop = (LPDROPFILESTRUCT32) GlobalLock32( hDrop.h32 );
1267 if( lpDrop ) {
1268 lpDrop->lSize = sizeof(DROPFILESTRUCT32);
1269 lpDrop->ptMousePos.x = (INT32)x;
1270 lpDrop->ptMousePos.y = (INT32)y;
1271 lpDrop->fInNonClientArea = (BOOL32)
1272 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1273 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1274 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1275 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1276 lpDrop->fWideChar = FALSE;
1277 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT32);
1279 } else {
1280 LPDROPFILESTRUCT16 lpDrop;
1281 drop_len += sizeof(DROPFILESTRUCT16) + 1;
1282 hDrop.h16 = (HDROP16)GlobalAlloc16( GMEM_SHARE, drop_len );
1283 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop.h16 );
1285 if( lpDrop ) {
1286 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1287 lpDrop->ptMousePos.x = (INT16)x;
1288 lpDrop->ptMousePos.y = (INT16)y;
1289 lpDrop->fInNonClientArea = (BOOL16)
1290 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1291 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1292 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1293 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1294 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1298 /* create message content */
1299 if (p_drop) {
1300 p = p_data;
1301 next = strchr(p, '\n');
1302 while (p) {
1303 if (next) *next=0;
1304 if (strncmp(p,"file:",5) == 0 ) {
1305 INT32 len = GetShortPathName32A( p+5, p_drop, 65535 );
1306 if (len) {
1307 TRACE(event, "drop file %s as %s\n", p+5, p_drop);
1308 p_drop += len+1;
1309 } else {
1310 WARN(event, "can't convert file %s to dos name \n", p+5);
1312 } else {
1313 WARN(event, "unknown mime type %s\n", p);
1315 if (next) {
1316 *next = '\n';
1317 p = next + 1;
1318 next = strchr(p, '\n');
1319 } else {
1320 p = NULL;
1322 *p_drop = '\0';
1325 if (drop32) {
1326 /* can not use PostMessage32A because it is currently based on
1327 * PostMessage16 and WPARAM32 would be truncated to WPARAM16
1329 GlobalUnlock32(hDrop.h32);
1330 SendMessage32A( pWnd->hwndSelf, WM_DROPFILES,
1331 (WPARAM32)hDrop.h32, 0L );
1332 } else {
1333 GlobalUnlock16(hDrop.h16);
1334 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1335 (WPARAM16)hDrop.h16, 0L );
1339 if( p_data ) TSXFree(p_data);
1343 /**********************************************************************
1344 * EVENT_ClientMessage
1346 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event )
1348 if (event->message_type != None && event->format == 32) {
1349 if ((event->message_type == wmProtocols) &&
1350 (((Atom) event->data.l[0]) == wmDeleteWindow))
1351 SendMessage16( pWnd->hwndSelf, WM_SYSCOMMAND, SC_CLOSE, 0 );
1352 else if ( event->message_type == dndProtocol &&
1353 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
1354 EVENT_DropFromOffiX(pWnd, event);
1355 else if ( event->message_type == dndProtocol &&
1356 event->data.l[0] == DndURL )
1357 EVENT_DropURLs(pWnd, event);
1358 else {
1359 #if 0
1360 /* enable this if you want to see the message */
1361 unsigned char* p_data = NULL;
1362 union {
1363 unsigned long l;
1364 int i;
1365 Atom atom;
1366 } u; /* unused */
1367 TSXGetWindowProperty( display, DefaultRootWindow(display),
1368 dndSelection, 0, 65535, FALSE,
1369 AnyPropertyType, &u.atom, &u.i,
1370 &u.l, &u.l, &p_data);
1371 TRACE(event, "message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1372 event->message_type, event->data.l[0], event->data.l[1],
1373 event->data.l[2], event->data.l[3], event->data.l[4],
1374 p_data);
1375 #endif
1376 TRACE(event, "unrecognized ClientMessage\n" );
1381 /**********************************************************************
1382 * EVENT_EnterNotify
1384 * Install colormap when Wine window is focused in
1385 * self-managed mode with private colormap
1388 void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
1390 if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
1391 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
1392 TSXInstallColormap( display, COLOR_GetColormap() );
1396 /**********************************************************************
1397 * EVENT_MapNotify
1399 void EVENT_MapNotify( HWND32 hWnd, XMapEvent *event )
1401 HWND32 hwndFocus = GetFocus32();
1403 if (hwndFocus && IsChild32( hWnd, hwndFocus ))
1404 FOCUS_SetXFocus( (HWND32)hwndFocus );
1406 return;