Release 980215
[wine.git] / windows / event.c
blob84bc271005c51717aaa91ca794cbfff38859b91e
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 <stdio.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <sys/time.h>
15 #include <sys/types.h>
16 #include <errno.h>
17 #include <X11/keysym.h>
18 #include "ts_xlib.h"
19 #include "ts_xresource.h"
20 #include "ts_xutil.h"
21 #include <X11/Xatom.h>
23 #include "windows.h"
24 #include "winnt.h"
25 #include "gdi.h"
26 #include "heap.h"
27 #include "queue.h"
28 #include "win.h"
29 #include "class.h"
30 #include "clipboard.h"
31 #include "dce.h"
32 #include "message.h"
33 #include "module.h"
34 #include "options.h"
35 #include "queue.h"
36 #include "winpos.h"
37 #include "drive.h"
38 #include "shell.h"
39 #include "keyboard.h"
40 #include "stddebug.h"
41 #include "debug.h"
42 #include "dde_proc.h"
45 #define NB_BUTTONS 3 /* Windows can handle 3 buttons */
47 #define DndNotDnd -1 /* OffiX drag&drop */
48 #define DndUnknown 0
49 #define DndRawData 1
50 #define DndFile 2
51 #define DndFiles 3
52 #define DndText 4
53 #define DndDir 5
54 #define DndLink 6
55 #define DndExe 7
57 #define DndEND 8
59 /* X context to associate a hwnd to an X window */
60 static XContext winContext = 0;
62 static INT16 captureHT = HTCLIENT;
63 static HWND32 captureWnd = 0;
64 static BOOL32 InputEnabled = TRUE;
65 static BOOL32 SwappedButtons = FALSE;
67 static Atom wmProtocols = None;
68 static Atom wmDeleteWindow = None;
69 static Atom dndProtocol = None;
70 static Atom dndSelection = None;
72 /* EVENT_WaitNetEvent() master fd sets */
74 static fd_set __event_io_set[3];
75 static int __event_max_fd = 0;
76 static int __event_x_connection = 0;
78 static const char * const event_names[] =
80 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
81 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
82 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
83 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
84 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
85 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
86 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
87 "ClientMessage", "MappingNotify"
90 /* Event handlers */
91 static void EVENT_Key( WND *pWnd, XKeyEvent *event );
92 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event );
93 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event );
94 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event );
95 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event );
96 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event );
97 static void EVENT_Expose( WND *pWnd, XExposeEvent *event );
98 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event );
99 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event );
100 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event);
101 static void EVENT_SelectionNotify( XSelectionEvent *event);
102 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event);
103 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event );
104 static void EVENT_MapNotify( HWND32 hwnd, XMapEvent *event );
106 /* Usable only with OLVWM - compile option perhaps?
107 static void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event );
110 extern void FOCUS_SetXFocus( HWND32 );
111 extern BOOL16 DRAG_QueryUpdate( HWND16, SEGPTR, BOOL32 );
112 extern BOOL32 WINSOCK_HandleIO( int* max_fd, int num_pending, fd_set p[3], fd_set e[3] );
114 /***********************************************************************
115 * EVENT_Init
117 * Initialize network IO.
119 BOOL32 EVENT_Init(void)
121 int i;
122 for( i = 0; i < 3; i++ )
123 FD_ZERO( __event_io_set + i );
125 __event_max_fd = __event_x_connection = ConnectionNumber(display);
126 FD_SET( __event_x_connection, &__event_io_set[EVENT_IO_READ] );
127 __event_max_fd++;
128 return TRUE;
131 /***********************************************************************
132 * EVENT_AddIO
134 void EVENT_AddIO( int fd, int io_type )
136 FD_SET( fd, &__event_io_set[io_type] );
137 if( __event_max_fd <= fd ) __event_max_fd = fd + 1;
140 void EVENT_DeleteIO( int fd, int io_type )
142 FD_CLR( fd, &__event_io_set[io_type] );
145 /***********************************************************************
146 * EVENT_ProcessEvent
148 * Process an X event.
150 void EVENT_ProcessEvent( XEvent *event )
152 WND *pWnd;
154 if (TSXFindContext( display, event->xany.window, winContext,
155 (char **)&pWnd ) != 0)
156 return; /* Not for a registered window */
158 dprintf_event( stddeb, "Got event %s for hwnd %04x\n",
159 event_names[event->type], pWnd->hwndSelf );
161 switch(event->type)
163 case KeyPress:
164 case KeyRelease:
165 if (InputEnabled) EVENT_Key( pWnd, (XKeyEvent*)event );
166 break;
168 case ButtonPress:
169 if (InputEnabled)
170 EVENT_ButtonPress( pWnd, (XButtonEvent*)event );
171 break;
173 case ButtonRelease:
174 if (InputEnabled)
175 EVENT_ButtonRelease( pWnd, (XButtonEvent*)event );
176 break;
178 case MotionNotify:
179 /* Wine between two fast machines across the overloaded campus
180 ethernet gets very boged down in MotionEvents. The following
181 simply finds the last motion event in the queue and drops
182 the rest. On a good link events are servered before they build
183 up so this doesn't take place. On a slow link this may cause
184 problems if the event order is important. I'm not yet seen
185 of any problems. Jon 7/6/96.
187 if (InputEnabled)
189 while (TSXCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
190 MotionNotify, event));
191 EVENT_MotionNotify( pWnd, (XMotionEvent*)event );
193 break;
195 case FocusIn:
196 EVENT_FocusIn( pWnd, (XFocusChangeEvent*)event );
197 break;
199 case FocusOut:
200 EVENT_FocusOut( pWnd, (XFocusChangeEvent*)event );
201 break;
203 case Expose:
204 EVENT_Expose( pWnd, (XExposeEvent *)event );
205 break;
207 case GraphicsExpose:
208 EVENT_GraphicsExpose( pWnd, (XGraphicsExposeEvent *)event );
209 break;
211 case ConfigureNotify:
212 EVENT_ConfigureNotify( pWnd, (XConfigureEvent*)event );
213 break;
215 case SelectionRequest:
216 EVENT_SelectionRequest( pWnd, (XSelectionRequestEvent *)event );
217 break;
219 case SelectionNotify:
220 EVENT_SelectionNotify( (XSelectionEvent *)event );
221 break;
223 case SelectionClear:
224 EVENT_SelectionClear( pWnd, (XSelectionClearEvent*) event );
225 break;
227 case ClientMessage:
228 EVENT_ClientMessage( pWnd, (XClientMessageEvent *) event );
229 break;
231 /* case EnterNotify:
232 * EVENT_EnterNotify( pWnd, (XCrossingEvent *) event );
233 * break;
235 case NoExpose:
236 break;
238 /* We get all these because of StructureNotifyMask. */
239 case UnmapNotify:
240 case CirculateNotify:
241 case CreateNotify:
242 case DestroyNotify:
243 case GravityNotify:
244 case ReparentNotify:
245 break;
247 case MapNotify:
248 EVENT_MapNotify( pWnd->hwndSelf, (XMapEvent *)event );
249 break;
251 default:
252 dprintf_event(stddeb, "Unprocessed event %s for hwnd %04x\n",
253 event_names[event->type], pWnd->hwndSelf );
254 break;
259 /***********************************************************************
260 * EVENT_RegisterWindow
262 * Associate an X window to a HWND.
264 void EVENT_RegisterWindow( WND *pWnd )
266 if (wmProtocols == None)
267 wmProtocols = TSXInternAtom( display, "WM_PROTOCOLS", True );
268 if (wmDeleteWindow == None)
269 wmDeleteWindow = TSXInternAtom( display, "WM_DELETE_WINDOW", True );
270 if( dndProtocol == None )
271 dndProtocol = TSXInternAtom( display, "DndProtocol" , False );
272 if( dndSelection == None )
273 dndSelection = TSXInternAtom( display, "DndSelection" , False );
275 TSXSetWMProtocols( display, pWnd->window, &wmDeleteWindow, 1 );
277 if (!winContext) winContext = TSXUniqueContext();
278 TSXSaveContext( display, pWnd->window, winContext, (char *)pWnd );
281 /***********************************************************************
282 * EVENT_DestroyWindow
284 void EVENT_DestroyWindow( WND *pWnd )
286 XEvent xe;
288 TSXDeleteContext( display, pWnd->window, winContext );
289 TSXDestroyWindow( display, pWnd->window );
290 while( TSXCheckWindowEvent(display, pWnd->window, NoEventMask, &xe) );
294 /***********************************************************************
295 * IsUserIdle (USER.333)
297 * Check if we have pending X events.
299 BOOL16 WINAPI IsUserIdle(void)
301 struct timeval timeout = {0, 0};
302 fd_set check_set;
304 FD_ZERO(&check_set);
305 FD_SET(__event_x_connection, &check_set);
306 if( select(__event_x_connection + 1, &check_set, NULL, NULL, &timeout) > 0 )
307 return TRUE;
308 return FALSE;
312 /***********************************************************************
313 * EVENT_WaitNetEvent
315 * Wait for a network event, optionally sleeping until one arrives.
316 * Return TRUE if an event is pending, FALSE on timeout or error
317 * (for instance lost connection with the server).
319 BOOL32 EVENT_WaitNetEvent( BOOL32 sleep, BOOL32 peek )
321 XEvent event;
322 LONG maxWait = sleep ? TIMER_GetNextExpiration() : 0;
323 int pending = TSXPending(display);
325 /* Wait for an event or a timeout. If maxWait is -1, we have no timeout;
326 * in this case, we fall through directly to the XNextEvent loop.
329 if ((maxWait != -1) && !pending)
331 int num_pending;
332 struct timeval timeout;
333 fd_set io_set[3];
335 memcpy( io_set, __event_io_set, sizeof(io_set) );
337 timeout.tv_usec = (maxWait % 1000) * 1000;
338 timeout.tv_sec = maxWait / 1000;
340 #ifdef CONFIG_IPC
341 sigsetjmp(env_wait_x, 1);
342 stop_wait_op= CONT;
344 if (DDE_GetRemoteMessage()) {
345 while(DDE_GetRemoteMessage())
347 return TRUE;
349 stop_wait_op = STOP_WAIT_X;
350 /* The code up to the next "stop_wait_op = CONT" must be reentrant */
351 num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
352 &io_set[EVENT_IO_WRITE],
353 &io_set[EVENT_IO_EXCEPT], &timeout );
354 if ( num_pending == 0 )
356 stop_wait_op = CONT;
357 TIMER_ExpireTimers();
358 return FALSE;
360 else stop_wait_op = CONT;
361 #else /* CONFIG_IPC */
362 num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
363 &io_set[EVENT_IO_WRITE],
364 &io_set[EVENT_IO_EXCEPT], &timeout );
365 if ( num_pending == 0)
367 /* Timeout or error */
368 TIMER_ExpireTimers();
369 return FALSE;
371 #endif /* CONFIG_IPC */
373 /* Winsock asynchronous services */
375 if( FD_ISSET( __event_x_connection, &io_set[EVENT_IO_READ]) )
377 num_pending--;
378 if( num_pending )
379 WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
381 else /* no X events */
382 return WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
384 else if(!pending)
385 { /* Wait for X11 input. */
386 fd_set set;
388 FD_ZERO(&set);
389 FD_SET(__event_x_connection, &set);
390 select(__event_x_connection + 1, &set, 0, 0, 0 );
393 /* Process current X event (and possibly others that occurred in the meantime) */
398 #ifdef CONFIG_IPC
399 if (DDE_GetRemoteMessage())
401 while(DDE_GetRemoteMessage()) ;
402 return TRUE;
404 #endif /* CONFIG_IPC */
406 TSXNextEvent( display, &event );
408 if( peek )
410 WND* pWnd;
411 MESSAGEQUEUE* pQ;
413 if (TSXFindContext( display, ((XAnyEvent *)&event)->window, winContext,
414 (char **)&pWnd ) || (event.type == NoExpose))
415 continue;
417 /* Check only for those events which can be processed
418 * internally. */
420 if( event.type == MotionNotify ||
421 event.type == ButtonPress || event.type == ButtonRelease ||
422 event.type == KeyPress || event.type == KeyRelease ||
423 event.type == SelectionRequest || event.type == SelectionClear )
425 EVENT_ProcessEvent( &event );
426 continue;
429 if( pWnd )
431 if( (pQ = (MESSAGEQUEUE*)GlobalLock16(pWnd->hmemTaskQ)) )
433 pQ->flags |= QUEUE_FLAG_XEVENT;
434 PostEvent(pQ->hTask);
435 TSXPutBackEvent(display, &event);
436 break;
440 else EVENT_ProcessEvent( &event );
442 while (TSXPending( display ));
443 return TRUE;
447 /***********************************************************************
448 * EVENT_Synchronize
450 * Synchronize with the X server. Should not be used too often.
452 void EVENT_Synchronize()
454 XEvent event;
456 TSXSync( display, False );
457 while (TSXPending( display ))
459 TSXNextEvent( display, &event );
460 EVENT_ProcessEvent( &event );
464 /***********************************************************************
465 * EVENT_QueryZOrder
467 * Try to synchronize internal z-order with the window manager's.
468 * Probably a futile endeavor.
470 static BOOL32 __check_query_condition( WND** pWndA, WND** pWndB )
472 /* return TRUE if we have at least two managed windows */
474 for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
475 if( (*pWndA)->flags & WIN_MANAGED &&
476 (*pWndA)->dwStyle & WS_VISIBLE ) break;
477 if( *pWndA )
478 for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
479 if( (*pWndB)->flags & WIN_MANAGED &&
480 (*pWndB)->dwStyle & WS_VISIBLE ) break;
481 return ((*pWndB) != NULL);
484 static Window __get_common_ancestor( Window A, Window B,
485 Window** children, unsigned* total )
487 /* find the real root window */
489 Window root, *childrenB;
490 unsigned totalB;
494 if( *children ) TSXFree( *children );
495 TSXQueryTree( display, A, &root, &A, children, total );
496 TSXQueryTree( display, B, &root, &B, &childrenB, &totalB );
497 if( childrenB ) TSXFree( childrenB );
498 } while( A != B && A && B );
499 return ( A && B ) ? A : 0 ;
502 static Window __get_top_decoration( Window w, Window ancestor )
504 Window* children, root, prev = w, parent = w;
505 unsigned total;
509 w = parent;
510 TSXQueryTree( display, w, &root, &parent, &children, &total );
511 if( children ) TSXFree( children );
512 } while( parent && parent != ancestor );
513 dprintf_event( stddeb, "\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
514 return ( parent ) ? w : 0 ;
517 static unsigned __td_lookup( Window w, Window* list, unsigned max )
519 unsigned i;
520 for( i = 0; i < max; i++ ) if( list[i] == w ) break;
521 return i;
524 static BOOL32 EVENT_QueryZOrder( WND* pWndCheck )
526 BOOL32 bRet = FALSE;
527 HWND32 hwndInsertAfter = HWND_TOP;
528 WND* pWnd, *pWndZ = WIN_GetDesktop()->child;
529 Window w, parent, *children = NULL;
530 unsigned total, check, pos, best;
532 if( !__check_query_condition(&pWndZ, &pWnd) ) return TRUE;
534 parent = __get_common_ancestor( pWndZ->window, pWnd->window,
535 &children, &total );
536 if( parent && children )
538 w = __get_top_decoration( pWndCheck->window, parent );
539 if( w != children[total - 1] )
541 check = __td_lookup( w, children, total );
542 best = total;
543 for( pWnd = pWndZ; pWnd; pWnd = pWnd->next )
545 if( pWnd != pWndCheck )
547 if( !(pWnd->flags & WIN_MANAGED) ||
548 !(w = __get_top_decoration( pWnd->window, parent )) )
549 continue;
550 pos = __td_lookup( w, children, total );
551 if( pos < best && pos > check )
553 best = pos;
554 hwndInsertAfter = pWnd->hwndSelf;
556 if( check - best == 1 ) break;
559 WIN_UnlinkWindow( pWndCheck->hwndSelf );
560 WIN_LinkWindow( pWndCheck->hwndSelf, hwndInsertAfter);
563 if( children ) TSXFree( children );
564 return bRet;
568 /***********************************************************************
569 * EVENT_XStateToKeyState
571 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
572 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
574 static WORD EVENT_XStateToKeyState( int state )
576 int kstate = 0;
578 if (state & Button1Mask) kstate |= MK_LBUTTON;
579 if (state & Button2Mask) kstate |= MK_MBUTTON;
580 if (state & Button3Mask) kstate |= MK_RBUTTON;
581 if (state & ShiftMask) kstate |= MK_SHIFT;
582 if (state & ControlMask) kstate |= MK_CONTROL;
583 return kstate;
587 /***********************************************************************
588 * EVENT_Expose
590 static void EVENT_Expose( WND *pWnd, XExposeEvent *event )
592 RECT32 rect;
594 /* Make position relative to client area instead of window */
595 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
596 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
597 rect.right = rect.left + event->width;
598 rect.bottom = rect.top + event->height;
600 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
601 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
602 (event->count ? 0 : RDW_ERASENOW), 0 );
606 /***********************************************************************
607 * EVENT_GraphicsExpose
609 * This is needed when scrolling area is partially obscured
610 * by non-Wine X window.
612 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event )
614 RECT32 rect;
616 /* Make position relative to client area instead of window */
617 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
618 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
619 rect.right = rect.left + event->width;
620 rect.bottom = rect.top + event->height;
622 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
623 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
624 (event->count ? 0 : RDW_ERASENOW), 0 );
628 /***********************************************************************
629 * EVENT_Key
631 * Handle a X key event
633 static void EVENT_Key( WND *pWnd, XKeyEvent *event )
635 KEYBOARD_HandleEvent( pWnd, event );
639 /***********************************************************************
640 * EVENT_MotionNotify
642 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event )
644 hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ), 0L,
645 pWnd->rectWindow.left + event->x,
646 pWnd->rectWindow.top + event->y,
647 event->time - MSG_WineStartTicks, pWnd->hwndSelf );
651 /***********************************************************************
652 * EVENT_DummyMotionNotify
654 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
656 void EVENT_DummyMotionNotify(void)
658 Window root, child;
659 int rootX, rootY, winX, winY;
660 unsigned int state;
662 if (TSXQueryPointer( display, rootWindow, &root, &child,
663 &rootX, &rootY, &winX, &winY, &state ))
665 hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( state ), 0L,
666 winX, winY, GetTickCount(), 0 );
671 /***********************************************************************
672 * EVENT_ButtonPress
674 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event )
676 static WORD messages[NB_BUTTONS] =
677 { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
678 int buttonNum = event->button - 1;
680 if (buttonNum >= NB_BUTTONS) return;
681 if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
682 MouseButtonsStates[buttonNum] = TRUE;
683 AsyncMouseButtonsStates[buttonNum] = TRUE;
684 hardware_event( messages[buttonNum],
685 EVENT_XStateToKeyState( event->state ), 0L,
686 pWnd->rectWindow.left + event->x,
687 pWnd->rectWindow.top + event->y,
688 event->time - MSG_WineStartTicks, pWnd->hwndSelf );
692 /***********************************************************************
693 * EVENT_ButtonRelease
695 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event )
697 static const WORD messages[NB_BUTTONS] =
698 { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
699 int buttonNum = event->button - 1;
701 if (buttonNum >= NB_BUTTONS) return;
702 if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
703 MouseButtonsStates[buttonNum] = FALSE;
704 hardware_event( messages[buttonNum],
705 EVENT_XStateToKeyState( event->state ), 0L,
706 pWnd->rectWindow.left + event->x,
707 pWnd->rectWindow.top + event->y,
708 event->time - MSG_WineStartTicks, pWnd->hwndSelf );
712 /**********************************************************************
713 * EVENT_FocusIn
715 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event )
717 if (Options.managed) EVENT_QueryZOrder( pWnd );
719 if (event->detail != NotifyPointer)
721 HWND32 hwnd = pWnd->hwndSelf;
723 if (hwnd != GetActiveWindow32())
724 WINPOS_ChangeActiveWindow( hwnd, FALSE );
725 if ((hwnd != GetFocus32()) && !IsChild32( hwnd, GetFocus32()))
726 SetFocus32( hwnd );
731 /**********************************************************************
732 * EVENT_FocusOut
734 * Note: only top-level override-redirect windows get FocusOut events.
736 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event )
738 if (event->detail != NotifyPointer)
740 HWND32 hwnd = pWnd->hwndSelf;
742 if (hwnd == GetActiveWindow32())
743 WINPOS_ChangeActiveWindow( 0, FALSE );
744 if ((hwnd == GetFocus32()) || IsChild32( hwnd, GetFocus32()))
745 SetFocus32( 0 );
749 /**********************************************************************
750 * EVENT_CheckFocus
752 BOOL32 EVENT_CheckFocus(void)
754 WND* pWnd;
755 Window xW;
756 int state;
758 TSXGetInputFocus(display, &xW, &state);
759 if( xW == None ||
760 TSXFindContext(display, xW, winContext, (char **)&pWnd) )
761 return FALSE;
762 return TRUE;
766 /**********************************************************************
767 * EVENT_GetGeometry
769 * Helper function for ConfigureNotify handling.
770 * Get the new geometry of a window relative to the root window.
772 static void EVENT_GetGeometry( Window win, int *px, int *py,
773 unsigned int *pwidth, unsigned int *pheight )
775 Window root, parent, *children;
776 int xpos, ypos;
777 unsigned int width, height, border, depth, nb_children;
779 if (!TSXGetGeometry( display, win, &root, px, py, pwidth, pheight,
780 &border, &depth )) return;
781 if (win == rootWindow)
783 *px = *py = 0;
784 return;
787 for (;;)
789 if (!TSXQueryTree(display, win, &root, &parent, &children, &nb_children))
790 return;
791 TSXFree( children );
792 if (parent == rootWindow) break;
793 win = parent;
794 if (!TSXGetGeometry( display, win, &root, &xpos, &ypos,
795 &width, &height, &border, &depth )) return;
796 *px += xpos;
797 *py += ypos;
802 /**********************************************************************
803 * EVENT_ConfigureNotify
805 * The ConfigureNotify event is only selected on top-level windows
806 * when the -managed flag is used.
808 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event )
810 WINDOWPOS32 winpos;
811 RECT32 newWindowRect, newClientRect;
812 HRGN32 hrgnOldPos, hrgnNewPos;
813 Window above = event->above;
814 int x, y;
815 unsigned int width, height;
817 assert (pWnd->flags & WIN_MANAGED);
819 /* We don't rely on the event geometry info, because it is relative
820 * to parent and not to root, and it may be wrong (XFree sets x,y to 0,0
821 * if the window hasn't moved).
823 EVENT_GetGeometry( event->window, &x, &y, &width, &height );
825 /* Fill WINDOWPOS struct */
826 winpos.flags = SWP_NOACTIVATE | SWP_NOZORDER;
827 winpos.hwnd = pWnd->hwndSelf;
828 winpos.x = x;
829 winpos.y = y;
830 winpos.cx = width;
831 winpos.cy = height;
833 /* Check for unchanged attributes */
834 if (winpos.x == pWnd->rectWindow.left && winpos.y == pWnd->rectWindow.top)
835 winpos.flags |= SWP_NOMOVE;
836 if ((winpos.cx == pWnd->rectWindow.right - pWnd->rectWindow.left) &&
837 (winpos.cy == pWnd->rectWindow.bottom - pWnd->rectWindow.top))
838 winpos.flags |= SWP_NOSIZE;
839 else
841 RECT32 rect = { 0, 0, pWnd->rectWindow.right - pWnd->rectWindow.left,
842 pWnd->rectWindow.bottom - pWnd->rectWindow.top };
843 DCE_InvalidateDCE( pWnd, &rect );
846 /* Send WM_WINDOWPOSCHANGING */
847 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)&winpos );
849 /* Calculate new position and size */
850 newWindowRect.left = x;
851 newWindowRect.right = x + width;
852 newWindowRect.top = y;
853 newWindowRect.bottom = y + height;
855 WINPOS_SendNCCalcSize( winpos.hwnd, TRUE, &newWindowRect,
856 &pWnd->rectWindow, &pWnd->rectClient,
857 &winpos, &newClientRect );
859 hrgnOldPos = CreateRectRgnIndirect32( &pWnd->rectWindow );
860 hrgnNewPos = CreateRectRgnIndirect32( &newWindowRect );
861 CombineRgn32( hrgnOldPos, hrgnOldPos, hrgnNewPos, RGN_DIFF );
862 DeleteObject32(hrgnOldPos);
863 DeleteObject32(hrgnNewPos);
865 /* Set new size and position */
866 pWnd->rectWindow = newWindowRect;
867 pWnd->rectClient = newClientRect;
868 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)&winpos );
870 if (!IsWindow32( winpos.hwnd )) return;
871 if( above == None ) /* absolute bottom */
873 WIN_UnlinkWindow( winpos.hwnd );
874 WIN_LinkWindow( winpos.hwnd, HWND_BOTTOM);
876 else EVENT_QueryZOrder( pWnd ); /* try to outsmart window manager */
880 /***********************************************************************
881 * EVENT_SelectionRequest
883 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event )
885 XSelectionEvent result;
886 Atom rprop = None;
887 Window request = event->requestor;
889 if(event->target == XA_STRING)
891 HANDLE16 hText;
892 LPSTR text;
893 int size,i,j;
895 rprop = event->property;
897 if(rprop == None) rprop = event->target;
899 if(event->selection!=XA_PRIMARY) rprop = None;
900 else if(!CLIPBOARD_IsPresent(CF_OEMTEXT)) rprop = None;
901 else
903 /* open to make sure that clipboard is available */
905 BOOL32 couldOpen = OpenClipboard32( pWnd->hwndSelf );
906 char* lpstr = 0;
908 hText = GetClipboardData16(CF_TEXT);
909 text = GlobalLock16(hText);
910 size = GlobalSize16(hText);
912 /* remove carriage returns */
914 lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
915 for(i=0,j=0; i < size && text[i]; i++ )
917 if( text[i] == '\r' &&
918 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
919 lpstr[j++] = text[i];
921 lpstr[j]='\0';
923 TSXChangeProperty(display, request, rprop,
924 XA_STRING, 8, PropModeReplace,
925 lpstr, j);
926 HeapFree( GetProcessHeap(), 0, lpstr );
928 /* close only if we opened before */
930 if(couldOpen) CloseClipboard32();
934 if(rprop == None)
935 dprintf_event(stddeb,"Request for %s ignored\n", TSXGetAtomName(display,event->target));
937 result.type = SelectionNotify;
938 result.display = display;
939 result.requestor = request;
940 result.selection = event->selection;
941 result.property = rprop;
942 result.target = event->target;
943 result.time = event->time;
944 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
948 /***********************************************************************
949 * EVENT_SelectionNotify
951 static void EVENT_SelectionNotify( XSelectionEvent *event )
953 if (event->selection != XA_PRIMARY) return;
955 if (event->target != XA_STRING) CLIPBOARD_ReadSelection( 0, None );
956 else CLIPBOARD_ReadSelection( event->requestor, event->property );
958 dprintf_clipboard(stddeb,"\tSelectionNotify done!\n");
962 /***********************************************************************
963 * EVENT_SelectionClear
965 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event )
967 if (event->selection != XA_PRIMARY) return;
968 CLIPBOARD_ReleaseSelection( event->window, pWnd->hwndSelf );
972 /**********************************************************************
973 * EVENT_ClientMessage
975 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event )
977 if (event->message_type != None && event->format == 32)
979 if ((event->message_type == wmProtocols) &&
980 (((Atom) event->data.l[0]) == wmDeleteWindow))
981 SendMessage16( pWnd->hwndSelf, WM_SYSCOMMAND, SC_CLOSE, 0 );
982 else if ( event->message_type == dndProtocol &&
983 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
985 unsigned long data_length;
986 unsigned long aux_long;
987 unsigned char* p_data = NULL;
988 union {
989 Atom atom_aux;
990 POINT32 pt_aux;
991 int i;
992 } u;
993 int x, y;
994 BOOL16 bAccept;
995 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
996 LPDRAGINFO lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
997 SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
998 Window w_aux_root, w_aux_child;
999 WND* pDropWnd;
1001 if( !lpDragInfo || !spDragInfo ) return;
1003 TSXQueryPointer( display, pWnd->window, &w_aux_root, &w_aux_child,
1004 &x, &y, &u.pt_aux.x, &u.pt_aux.y, (unsigned int*)&aux_long);
1006 lpDragInfo->hScope = pWnd->hwndSelf;
1007 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1009 /* find out drop point and drop window */
1010 if( x < 0 || y < 0 ||
1011 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1012 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1013 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1014 else
1016 bAccept = DRAG_QueryUpdate( pWnd->hwndSelf, spDragInfo, TRUE );
1017 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1019 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1020 GlobalFree16( hDragInfo );
1022 if( bAccept )
1024 TSXGetWindowProperty( display, DefaultRootWindow(display),
1025 dndSelection, 0, 65535, FALSE,
1026 AnyPropertyType, &u.atom_aux, &u.pt_aux.y,
1027 &data_length, &aux_long, &p_data);
1029 if( !aux_long && p_data) /* don't bother if > 64K */
1031 char *p = (char*) p_data;
1032 char *p_drop;
1034 aux_long = 0;
1035 while( *p ) /* calculate buffer size */
1037 p_drop = p;
1038 if((u.i = *p) != -1 )
1039 u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
1040 if( u.i == -1 ) *p = -1; /* mark as "bad" */
1041 else
1043 INT32 len = GetShortPathName32A( p, NULL, 0 );
1044 if (len) aux_long += len + 1;
1045 else *p = -1;
1047 p += strlen(p) + 1;
1049 if( aux_long && aux_long < 65535 )
1051 HDROP16 hDrop;
1052 LPDROPFILESTRUCT lpDrop;
1054 aux_long += sizeof(DROPFILESTRUCT) + 1;
1055 hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
1056 lpDrop = (LPDROPFILESTRUCT) GlobalLock16( hDrop );
1058 if( lpDrop )
1060 lpDrop->wSize = sizeof(DROPFILESTRUCT);
1061 lpDrop->ptMousePos.x = (INT16)x;
1062 lpDrop->ptMousePos.y = (INT16)y;
1063 lpDrop->fInNonClientArea = (BOOL16)
1064 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1065 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1066 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1067 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1068 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT);
1069 p = p_data;
1070 while(*p)
1072 if( *p != -1 ) /* use only "good" entries */
1074 GetShortPathName32A( p, p_drop, 65535 );
1075 p_drop += strlen( p_drop ) + 1;
1077 p += strlen(p) + 1;
1079 *p_drop = '\0';
1080 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1081 (WPARAM16)hDrop, 0L );
1085 if( p_data ) TSXFree(p_data);
1087 } /* WS_EX_ACCEPTFILES */
1088 } /* dndProtocol */
1089 else
1090 dprintf_event( stddeb, "unrecognized ClientMessage\n" );
1094 /**********************************************************************
1095 * EVENT_EnterNotify
1097 * Install colormap when Wine window is focused in
1098 * self-managed mode with private colormap
1101 void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
1103 if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
1104 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
1105 TSXInstallColormap( display, COLOR_GetColormap() );
1109 /**********************************************************************
1110 * EVENT_MapNotify
1112 void EVENT_MapNotify( HWND32 hWnd, XMapEvent *event )
1114 HWND32 hwndFocus = GetFocus32();
1116 if (hwndFocus && IsChild32( hWnd, hwndFocus ))
1117 FOCUS_SetXFocus( (HWND32)hwndFocus );
1119 return;
1122 /**********************************************************************
1123 * EVENT_Capture
1125 * We need this to be able to generate double click messages
1126 * when menu code captures mouse in the window without CS_DBLCLK style.
1128 HWND32 EVENT_Capture(HWND32 hwnd, INT16 ht)
1130 Window win;
1131 HWND32 capturePrev = captureWnd;
1133 if (!hwnd)
1135 TSXUngrabPointer(display, CurrentTime );
1136 captureWnd = NULL; captureHT = 0;
1138 else if ((win = WIN_GetXWindow( hwnd )))
1140 WND* wndPtr = WIN_FindWndPtr( hwnd );
1142 if ( wndPtr &&
1143 (TSXGrabPointer(display, win, False,
1144 ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
1145 GrabModeAsync, GrabModeAsync,
1146 None, None, CurrentTime ) == GrabSuccess) )
1148 dprintf_win(stddeb, "SetCapture(0x%04x)\n", hwnd );
1149 captureWnd = hwnd;
1150 captureHT = ht;
1154 if( capturePrev && capturePrev != captureWnd )
1156 WND* wndPtr = WIN_FindWndPtr( capturePrev );
1157 if( wndPtr && (wndPtr->flags & WIN_ISWIN32) )
1158 SendMessage32A( capturePrev, WM_CAPTURECHANGED, 0L, hwnd);
1160 return capturePrev;
1163 /**********************************************************************
1164 * EVENT_GetCaptureInfo
1166 INT16 EVENT_GetCaptureInfo()
1168 return captureHT;
1171 /**********************************************************************
1172 * SetCapture16 (USER.18)
1174 HWND16 WINAPI SetCapture16( HWND16 hwnd )
1176 return (HWND16)EVENT_Capture( hwnd, HTCLIENT );
1180 /**********************************************************************
1181 * SetCapture32 (USER32.463)
1183 HWND32 WINAPI SetCapture32( HWND32 hwnd )
1185 return EVENT_Capture( hwnd, HTCLIENT );
1189 /**********************************************************************
1190 * ReleaseCapture (USER.19) (USER32.438)
1192 void WINAPI ReleaseCapture(void)
1194 dprintf_win(stddeb, "ReleaseCapture() [%04x]\n", captureWnd );
1195 if( captureWnd ) EVENT_Capture( 0, 0 );
1199 /**********************************************************************
1200 * GetCapture16 (USER.236)
1202 HWND16 WINAPI GetCapture16(void)
1204 return captureWnd;
1208 /**********************************************************************
1209 * GetCapture32 (USER32.207)
1211 HWND32 WINAPI GetCapture32(void)
1213 return captureWnd;
1217 /***********************************************************************
1218 * GetMouseEventProc (USER.337)
1220 FARPROC16 WINAPI GetMouseEventProc(void)
1222 HMODULE16 hmodule = GetModuleHandle16("USER");
1223 return MODULE_GetEntryPoint( hmodule,
1224 MODULE_GetOrdinal( hmodule, "Mouse_Event" ) );
1228 /***********************************************************************
1229 * Mouse_Event (USER.299)
1231 void WINAPI Mouse_Event( CONTEXT *context )
1233 /* Register values:
1234 * AX = mouse event
1235 * BX = horizontal displacement if AX & ME_MOVE
1236 * CX = vertical displacement if AX & ME_MOVE
1237 * DX = button state (?)
1238 * SI = mouse event flags (?)
1240 Window root, child;
1241 int rootX, rootY, winX, winY;
1242 unsigned int state;
1244 if (AX_reg(context) & ME_MOVE)
1246 /* We have to actually move the cursor */
1247 TSXWarpPointer( display, rootWindow, None, 0, 0, 0, 0,
1248 (short)BX_reg(context), (short)CX_reg(context) );
1249 return;
1251 if (!TSXQueryPointer( display, rootWindow, &root, &child,
1252 &rootX, &rootY, &winX, &winY, &state )) return;
1253 if (AX_reg(context) & ME_LDOWN)
1254 hardware_event( WM_LBUTTONDOWN, EVENT_XStateToKeyState( state ),
1255 0L, winX, winY, GetTickCount(), 0 );
1256 if (AX_reg(context) & ME_LUP)
1257 hardware_event( WM_LBUTTONUP, EVENT_XStateToKeyState( state ),
1258 0L, winX, winY, GetTickCount(), 0 );
1259 if (AX_reg(context) & ME_RDOWN)
1260 hardware_event( WM_RBUTTONDOWN, EVENT_XStateToKeyState( state ),
1261 0L, winX, winY, GetTickCount(), 0 );
1262 if (AX_reg(context) & ME_RUP)
1263 hardware_event( WM_RBUTTONUP, EVENT_XStateToKeyState( state ),
1264 0L, winX, winY, GetTickCount(), 0 );
1268 /**********************************************************************
1269 * EnableHardwareInput (USER.331)
1271 BOOL16 WINAPI EnableHardwareInput(BOOL16 bEnable)
1273 BOOL16 bOldState = InputEnabled;
1274 dprintf_event(stdnimp,"EnableHardwareInput(%d);\n", bEnable);
1275 InputEnabled = bEnable;
1276 return bOldState;
1280 /***********************************************************************
1281 * SwapMouseButton16 (USER.186)
1283 BOOL16 WINAPI SwapMouseButton16( BOOL16 fSwap )
1285 BOOL16 ret = SwappedButtons;
1286 SwappedButtons = fSwap;
1287 return ret;
1291 /***********************************************************************
1292 * SwapMouseButton32 (USER32.536)
1294 BOOL32 WINAPI SwapMouseButton32( BOOL32 fSwap )
1296 BOOL32 ret = SwappedButtons;
1297 SwappedButtons = fSwap;
1298 return ret;