Release 980104
[wine/multimedia.git] / windows / event.c
bloba6888ac5a4cbc2025dd739bad169228b3113ee65
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 <X11/Xlib.h>
19 #include <X11/Xresource.h>
20 #include <X11/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 io_set[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 (XFindContext( 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 (XCheckTypedWindowEvent(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 = XInternAtom( display, "WM_PROTOCOLS", True );
268 if (wmDeleteWindow == None)
269 wmDeleteWindow = XInternAtom( display, "WM_DELETE_WINDOW", True );
270 if( dndProtocol == None )
271 dndProtocol = XInternAtom( display, "DndProtocol" , False );
272 if( dndSelection == None )
273 dndSelection = XInternAtom( display, "DndSelection" , False );
275 XSetWMProtocols( display, pWnd->window, &wmDeleteWindow, 1 );
277 if (!winContext) winContext = XUniqueContext();
278 XSaveContext( display, pWnd->window, winContext, (char *)pWnd );
281 /***********************************************************************
282 * EVENT_DestroyWindow
284 void EVENT_DestroyWindow( WND *pWnd )
286 XEvent xe;
288 XDeleteContext( display, pWnd->window, winContext );
289 XDestroyWindow( display, pWnd->window );
290 while( XCheckWindowEvent(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;
324 /* Wait for an event or a timeout. If maxWait is -1, we have no timeout;
325 * in this case, we fall through directly to the XNextEvent loop.
328 if ((maxWait != -1) && !XPending(display))
330 int num_pending;
331 struct timeval timeout;
332 fd_set read_set = __event_io_set[EVENT_IO_READ];
333 fd_set write_set = __event_io_set[EVENT_IO_WRITE];
334 fd_set except_set = __event_io_set[EVENT_IO_EXCEPT];
336 timeout.tv_usec = (maxWait % 1000) * 1000;
337 timeout.tv_sec = maxWait / 1000;
339 #ifdef CONFIG_IPC
340 sigsetjmp(env_wait_x, 1);
341 stop_wait_op= CONT;
343 if (DDE_GetRemoteMessage()) {
344 while(DDE_GetRemoteMessage())
346 return TRUE;
348 stop_wait_op = STOP_WAIT_X;
349 /* The code up to the next "stop_wait_op = CONT" must be reentrant */
350 num_pending = select( __event_max_fd, &read_set, NULL, NULL, &timeout );
351 if ( num_pending == 0 )
353 stop_wait_op = CONT;
354 TIMER_ExpireTimers();
355 return FALSE;
357 else stop_wait_op = CONT;
358 #else /* CONFIG_IPC */
359 num_pending = select( __event_max_fd,
360 &read_set, &write_set, &except_set, &timeout );
361 if ( num_pending == 0)
363 /* Timeout or error */
364 TIMER_ExpireTimers();
365 return FALSE;
367 #endif /* CONFIG_IPC */
369 /* Winsock asynchronous services */
371 if( FD_ISSET( __event_x_connection, &read_set) )
373 num_pending--;
374 if( num_pending )
375 WINSOCK_HandleIO( &__event_max_fd, num_pending, __event_io_set );
377 else /* no X events */
378 return WINSOCK_HandleIO( &__event_max_fd, num_pending, __event_io_set );
381 /* Process current X event (and possibly others that occurred in the meantime) */
386 #ifdef CONFIG_IPC
387 if (DDE_GetRemoteMessage())
389 while(DDE_GetRemoteMessage()) ;
390 return TRUE;
392 #endif /* CONFIG_IPC */
394 XNextEvent( display, &event );
396 if( peek )
398 WND* pWnd;
399 MESSAGEQUEUE* pQ;
401 if (XFindContext( display, ((XAnyEvent *)&event)->window, winContext,
402 (char **)&pWnd ) || (event.type == NoExpose))
403 continue;
405 /* Check only for those events which can be processed
406 * internally. */
408 if( event.type == MotionNotify ||
409 event.type == ButtonPress || event.type == ButtonRelease ||
410 event.type == KeyPress || event.type == KeyRelease ||
411 event.type == SelectionRequest || event.type == SelectionClear )
413 EVENT_ProcessEvent( &event );
414 continue;
417 if( pWnd )
419 if( (pQ = (MESSAGEQUEUE*)GlobalLock16(pWnd->hmemTaskQ)) )
421 pQ->flags |= QUEUE_FLAG_XEVENT;
422 PostEvent(pQ->hTask);
423 XPutBackEvent(display, &event);
424 break;
428 else EVENT_ProcessEvent( &event );
430 while (XPending( display ));
431 return TRUE;
435 /***********************************************************************
436 * EVENT_Synchronize
438 * Synchronize with the X server. Should not be used too often.
440 void EVENT_Synchronize()
442 XEvent event;
444 XSync( display, False );
445 while (XPending( display ))
447 XNextEvent( display, &event );
448 EVENT_ProcessEvent( &event );
452 /***********************************************************************
453 * EVENT_QueryZOrder
455 * Try to synchronize internal z-order with the window manager's.
457 static BOOL32 __check_query_condition( WND** pWndA, WND** pWndB )
459 /* return TRUE if we have at least two managed windows */
461 for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
462 if( (*pWndA)->flags & WIN_MANAGED &&
463 (*pWndA)->dwStyle & WS_VISIBLE ) break;
464 if( *pWndA )
465 for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
466 if( (*pWndB)->flags & WIN_MANAGED &&
467 (*pWndB)->dwStyle & WS_VISIBLE ) break;
468 return ((*pWndB) != NULL);
471 static Window __get_common_ancestor( Window A, Window B,
472 Window** children, unsigned* total )
474 /* find the real root window */
476 Window root, *childrenB;
477 unsigned totalB;
481 if( *children ) XFree( *children );
482 XQueryTree( display, A, &root, &A, children, total );
483 XQueryTree( display, B, &root, &B, &childrenB, &totalB );
484 if( childrenB ) XFree( childrenB );
485 } while( A != B && A && B );
486 return ( A && B ) ? A : 0 ;
489 static Window __get_top_decoration( Window w, Window ancestor )
491 Window* children, root, prev = w, parent = w;
492 unsigned total;
496 w = parent;
497 XQueryTree( display, w, &root, &parent, &children, &total );
498 if( children ) XFree( children );
499 } while( parent && parent != ancestor );
500 dprintf_event( stddeb, "\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
501 return ( parent ) ? w : 0 ;
504 static unsigned __td_lookup( Window w, Window* list, unsigned max )
506 unsigned i;
507 for( i = 0; i < max; i++ ) if( list[i] == w ) break;
508 return i;
511 static BOOL32 EVENT_QueryZOrder( WND* pWndCheck )
513 BOOL32 bRet = FALSE;
514 HWND32 hwndInsertAfter = HWND_TOP;
515 WND* pWnd, *pWndZ = WIN_GetDesktop()->child;
516 Window w, parent, *children = NULL;
517 unsigned total, check, pos, best;
519 if( !__check_query_condition(&pWndZ, &pWnd) ) return TRUE;
521 parent = __get_common_ancestor( pWndZ->window, pWnd->window,
522 &children, &total );
523 if( parent && children )
525 w = __get_top_decoration( pWndCheck->window, parent );
526 if( w != children[total - 1] )
528 check = __td_lookup( w, children, total );
529 best = total;
530 for( pWnd = pWndZ; pWnd; pWnd = pWnd->next )
532 if( pWnd != pWndCheck )
534 if( !(pWnd->flags & WIN_MANAGED) ||
535 !(w = __get_top_decoration( pWnd->window, parent )) )
536 continue;
537 pos = __td_lookup( w, children, total );
538 if( pos < best && pos > check )
540 best = pos;
541 hwndInsertAfter = pWnd->hwndSelf;
543 if( check - best == 1 ) break;
546 WIN_UnlinkWindow( pWndCheck->hwndSelf );
547 WIN_LinkWindow( pWndCheck->hwndSelf, hwndInsertAfter);
550 if( children ) XFree( children );
551 return bRet;
555 /***********************************************************************
556 * EVENT_XStateToKeyState
558 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
559 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
561 static WORD EVENT_XStateToKeyState( int state )
563 int kstate = 0;
565 if (state & Button1Mask) kstate |= MK_LBUTTON;
566 if (state & Button2Mask) kstate |= MK_MBUTTON;
567 if (state & Button3Mask) kstate |= MK_RBUTTON;
568 if (state & ShiftMask) kstate |= MK_SHIFT;
569 if (state & ControlMask) kstate |= MK_CONTROL;
570 return kstate;
574 /***********************************************************************
575 * EVENT_Expose
577 static void EVENT_Expose( WND *pWnd, XExposeEvent *event )
579 RECT32 rect;
581 /* Make position relative to client area instead of window */
582 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
583 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
584 rect.right = rect.left + event->width;
585 rect.bottom = rect.top + event->height;
587 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
588 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
589 (event->count ? 0 : RDW_ERASENOW), 0 );
593 /***********************************************************************
594 * EVENT_GraphicsExpose
596 * This is needed when scrolling area is partially obscured
597 * by non-Wine X window.
599 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event )
601 RECT32 rect;
603 /* Make position relative to client area instead of window */
604 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
605 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
606 rect.right = rect.left + event->width;
607 rect.bottom = rect.top + event->height;
609 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
610 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
611 (event->count ? 0 : RDW_ERASENOW), 0 );
615 /***********************************************************************
616 * EVENT_Key
618 * Handle a X key event
620 static void EVENT_Key( WND *pWnd, XKeyEvent *event )
622 KEYBOARD_HandleEvent( pWnd, event );
626 /***********************************************************************
627 * EVENT_MotionNotify
629 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event )
631 hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ), 0L,
632 pWnd->rectWindow.left + event->x,
633 pWnd->rectWindow.top + event->y,
634 event->time - MSG_WineStartTicks, pWnd->hwndSelf );
638 /***********************************************************************
639 * EVENT_DummyMotionNotify
641 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
643 void EVENT_DummyMotionNotify(void)
645 Window root, child;
646 int rootX, rootY, winX, winY;
647 unsigned int state;
649 if (XQueryPointer( display, rootWindow, &root, &child,
650 &rootX, &rootY, &winX, &winY, &state ))
652 hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( state ), 0L,
653 winX, winY, GetTickCount(), 0 );
658 /***********************************************************************
659 * EVENT_ButtonPress
661 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event )
663 static WORD messages[NB_BUTTONS] =
664 { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
665 int buttonNum = event->button - 1;
667 if (buttonNum >= NB_BUTTONS) return;
668 if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
669 MouseButtonsStates[buttonNum] = TRUE;
670 AsyncMouseButtonsStates[buttonNum] = TRUE;
671 hardware_event( messages[buttonNum],
672 EVENT_XStateToKeyState( event->state ), 0L,
673 pWnd->rectWindow.left + event->x,
674 pWnd->rectWindow.top + event->y,
675 event->time - MSG_WineStartTicks, pWnd->hwndSelf );
679 /***********************************************************************
680 * EVENT_ButtonRelease
682 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event )
684 static const WORD messages[NB_BUTTONS] =
685 { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
686 int buttonNum = event->button - 1;
688 if (buttonNum >= NB_BUTTONS) return;
689 if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
690 MouseButtonsStates[buttonNum] = FALSE;
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_FocusIn
702 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event )
704 if (Options.managed) EVENT_QueryZOrder( pWnd );
706 if (event->detail != NotifyPointer)
708 HWND32 hwnd = pWnd->hwndSelf;
710 if (hwnd != GetActiveWindow32())
711 WINPOS_ChangeActiveWindow( hwnd, FALSE );
712 if ((hwnd != GetFocus32()) && !IsChild32( hwnd, GetFocus32()))
713 SetFocus32( hwnd );
718 /**********************************************************************
719 * EVENT_FocusOut
721 * Note: only top-level override-redirect windows get FocusOut events.
723 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event )
725 if (event->detail != NotifyPointer)
727 HWND32 hwnd = pWnd->hwndSelf;
729 if (hwnd == GetActiveWindow32())
730 WINPOS_ChangeActiveWindow( 0, FALSE );
731 if ((hwnd == GetFocus32()) || IsChild32( hwnd, GetFocus32()))
732 SetFocus32( 0 );
736 /**********************************************************************
737 * EVENT_CheckFocus
739 BOOL32 EVENT_CheckFocus(void)
741 WND* pWnd;
742 Window xW;
743 int state;
745 XGetInputFocus(display, &xW, &state);
746 if( xW == None ||
747 XFindContext(display, xW, winContext, (char **)&pWnd) )
748 return FALSE;
749 return TRUE;
753 /**********************************************************************
754 * EVENT_GetGeometry
756 * Helper function for ConfigureNotify handling.
757 * Get the new geometry of a window relative to the root window.
759 static void EVENT_GetGeometry( Window win, int *px, int *py,
760 unsigned int *pwidth, unsigned int *pheight )
762 Window root, parent, *children;
763 int xpos, ypos;
764 unsigned int width, height, border, depth, nb_children;
766 if (!XGetGeometry( display, win, &root, px, py, pwidth, pheight,
767 &border, &depth )) return;
768 if (win == rootWindow)
770 *px = *py = 0;
771 return;
774 for (;;)
776 if (!XQueryTree(display, win, &root, &parent, &children, &nb_children))
777 return;
778 XFree( children );
779 if (parent == rootWindow) break;
780 win = parent;
781 if (!XGetGeometry( display, win, &root, &xpos, &ypos,
782 &width, &height, &border, &depth )) return;
783 *px += xpos;
784 *py += ypos;
789 /**********************************************************************
790 * EVENT_ConfigureNotify
792 * The ConfigureNotify event is only selected on top-level windows
793 * when the -managed flag is used.
795 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event )
797 WINDOWPOS32 winpos;
798 RECT32 newWindowRect, newClientRect;
799 HRGN32 hrgnOldPos, hrgnNewPos;
800 Window above = event->above;
801 int x, y;
802 unsigned int width, height;
804 assert (pWnd->flags & WIN_MANAGED);
806 /* We don't rely on the event geometry info, because it is relative
807 * to parent and not to root, and it may be wrong (XFree sets x,y to 0,0
808 * if the window hasn't moved).
810 EVENT_GetGeometry( event->window, &x, &y, &width, &height );
812 /* Fill WINDOWPOS struct */
813 winpos.flags = SWP_NOACTIVATE | SWP_NOZORDER;
814 winpos.hwnd = pWnd->hwndSelf;
815 winpos.x = x;
816 winpos.y = y;
817 winpos.cx = width;
818 winpos.cy = height;
820 /* Check for unchanged attributes */
821 if (winpos.x == pWnd->rectWindow.left && winpos.y == pWnd->rectWindow.top)
822 winpos.flags |= SWP_NOMOVE;
823 if ((winpos.cx == pWnd->rectWindow.right - pWnd->rectWindow.left) &&
824 (winpos.cy == pWnd->rectWindow.bottom - pWnd->rectWindow.top))
825 winpos.flags |= SWP_NOSIZE;
826 else
828 RECT32 rect = { 0, 0, pWnd->rectWindow.right - pWnd->rectWindow.left,
829 pWnd->rectWindow.bottom - pWnd->rectWindow.top };
830 DCE_InvalidateDCE( pWnd, &rect );
833 /* Send WM_WINDOWPOSCHANGING */
834 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)&winpos );
836 /* Calculate new position and size */
837 newWindowRect.left = x;
838 newWindowRect.right = x + width;
839 newWindowRect.top = y;
840 newWindowRect.bottom = y + height;
842 WINPOS_SendNCCalcSize( winpos.hwnd, TRUE, &newWindowRect,
843 &pWnd->rectWindow, &pWnd->rectClient,
844 &winpos, &newClientRect );
846 hrgnOldPos = CreateRectRgnIndirect32( &pWnd->rectWindow );
847 hrgnNewPos = CreateRectRgnIndirect32( &newWindowRect );
848 CombineRgn32( hrgnOldPos, hrgnOldPos, hrgnNewPos, RGN_DIFF );
849 DeleteObject32(hrgnOldPos);
850 DeleteObject32(hrgnNewPos);
852 /* Set new size and position */
853 pWnd->rectWindow = newWindowRect;
854 pWnd->rectClient = newClientRect;
855 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)&winpos );
857 if (!IsWindow32( winpos.hwnd )) return;
858 if( above == None ) /* absolute bottom */
860 WIN_UnlinkWindow( winpos.hwnd );
861 WIN_LinkWindow( winpos.hwnd, HWND_BOTTOM);
863 else EVENT_QueryZOrder( pWnd ); /* try to outsmart window manager */
867 /***********************************************************************
868 * EVENT_SelectionRequest
870 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event )
872 XSelectionEvent result;
873 Atom rprop = None;
874 Window request = event->requestor;
876 if(event->target == XA_STRING)
878 HANDLE16 hText;
879 LPSTR text;
880 int size,i,j;
882 rprop = event->property;
884 if(rprop == None) rprop = event->target;
886 if(event->selection!=XA_PRIMARY) rprop = None;
887 else if(!CLIPBOARD_IsPresent(CF_OEMTEXT)) rprop = None;
888 else
890 /* open to make sure that clipboard is available */
892 BOOL32 couldOpen = OpenClipboard32( pWnd->hwndSelf );
893 char* lpstr = 0;
895 hText = GetClipboardData16(CF_TEXT);
896 text = GlobalLock16(hText);
897 size = GlobalSize16(hText);
899 /* remove carriage returns */
901 lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
902 for(i=0,j=0; i < size && text[i]; i++ )
904 if( text[i] == '\r' &&
905 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
906 lpstr[j++] = text[i];
908 lpstr[j]='\0';
910 XChangeProperty(display, request, rprop,
911 XA_STRING, 8, PropModeReplace,
912 lpstr, j);
913 HeapFree( GetProcessHeap(), 0, lpstr );
915 /* close only if we opened before */
917 if(couldOpen) CloseClipboard32();
921 if(rprop == None)
922 dprintf_event(stddeb,"Request for %s ignored\n", XGetAtomName(display,event->target));
924 result.type = SelectionNotify;
925 result.display = display;
926 result.requestor = request;
927 result.selection = event->selection;
928 result.property = rprop;
929 result.target = event->target;
930 result.time = event->time;
931 XSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
935 /***********************************************************************
936 * EVENT_SelectionNotify
938 static void EVENT_SelectionNotify( XSelectionEvent *event )
940 if (event->selection != XA_PRIMARY) return;
942 if (event->target != XA_STRING) CLIPBOARD_ReadSelection( 0, None );
943 else CLIPBOARD_ReadSelection( event->requestor, event->property );
945 dprintf_clipboard(stddeb,"\tSelectionNotify done!\n");
949 /***********************************************************************
950 * EVENT_SelectionClear
952 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event )
954 if (event->selection != XA_PRIMARY) return;
955 CLIPBOARD_ReleaseSelection( event->window, pWnd->hwndSelf );
959 /**********************************************************************
960 * EVENT_ClientMessage
962 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event )
964 if (event->message_type != None && event->format == 32)
966 if ((event->message_type == wmProtocols) &&
967 (((Atom) event->data.l[0]) == wmDeleteWindow))
968 SendMessage16( pWnd->hwndSelf, WM_SYSCOMMAND, SC_CLOSE, 0 );
969 else if ( event->message_type == dndProtocol &&
970 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
972 unsigned long data_length;
973 unsigned long aux_long;
974 unsigned char* p_data = NULL;
975 union {
976 Atom atom_aux;
977 POINT32 pt_aux;
978 int i;
979 } u;
980 int x, y;
981 BOOL16 bAccept;
982 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
983 LPDRAGINFO lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
984 SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
985 Window w_aux_root, w_aux_child;
986 WND* pDropWnd;
988 if( !lpDragInfo || !spDragInfo ) return;
990 XQueryPointer( display, pWnd->window, &w_aux_root, &w_aux_child,
991 &x, &y, &u.pt_aux.x, &u.pt_aux.y, (unsigned int*)&aux_long);
993 lpDragInfo->hScope = pWnd->hwndSelf;
994 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
996 /* find out drop point and drop window */
997 if( x < 0 || y < 0 ||
998 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
999 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1000 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1001 else
1003 bAccept = DRAG_QueryUpdate( pWnd->hwndSelf, spDragInfo, TRUE );
1004 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1006 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1007 GlobalFree16( hDragInfo );
1009 if( bAccept )
1011 XGetWindowProperty( display, DefaultRootWindow(display),
1012 dndSelection, 0, 65535, FALSE,
1013 AnyPropertyType, &u.atom_aux, &u.pt_aux.y,
1014 &data_length, &aux_long, &p_data);
1016 if( !aux_long && p_data) /* don't bother if > 64K */
1018 char *p = (char*) p_data;
1019 char *p_drop;
1021 aux_long = 0;
1022 while( *p ) /* calculate buffer size */
1024 p_drop = p;
1025 if((u.i = *p) != -1 )
1026 u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
1027 if( u.i == -1 ) *p = -1; /* mark as "bad" */
1028 else
1030 INT32 len = GetShortPathName32A( p, NULL, 0 );
1031 if (len) aux_long += len + 1;
1032 else *p = -1;
1034 p += strlen(p) + 1;
1036 if( aux_long && aux_long < 65535 )
1038 HDROP16 hDrop;
1039 LPDROPFILESTRUCT lpDrop;
1041 aux_long += sizeof(DROPFILESTRUCT) + 1;
1042 hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
1043 lpDrop = (LPDROPFILESTRUCT) GlobalLock16( hDrop );
1045 if( lpDrop )
1047 lpDrop->wSize = sizeof(DROPFILESTRUCT);
1048 lpDrop->ptMousePos.x = (INT16)x;
1049 lpDrop->ptMousePos.y = (INT16)y;
1050 lpDrop->fInNonClientArea = (BOOL16)
1051 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1052 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1053 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1054 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1055 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT);
1056 p = p_data;
1057 while(*p)
1059 if( *p != -1 ) /* use only "good" entries */
1061 GetShortPathName32A( p, p_drop, 65535 );
1062 p_drop += strlen( p_drop ) + 1;
1064 p += strlen(p) + 1;
1066 *p_drop = '\0';
1067 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1068 (WPARAM16)hDrop, 0L );
1072 if( p_data ) XFree(p_data);
1074 } /* WS_EX_ACCEPTFILES */
1075 } /* dndProtocol */
1076 else
1077 dprintf_event( stddeb, "unrecognized ClientMessage\n" );
1081 /**********************************************************************
1082 * EVENT_EnterNotify
1084 * Install colormap when Wine window is focused in
1085 * self-managed mode with private colormap
1088 void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
1090 if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
1091 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
1092 XInstallColormap( display, COLOR_GetColormap() );
1096 /**********************************************************************
1097 * EVENT_MapNotify
1099 void EVENT_MapNotify( HWND32 hWnd, XMapEvent *event )
1101 HWND32 hwndFocus = GetFocus32();
1103 if (hwndFocus && IsChild32( hWnd, hwndFocus ))
1104 FOCUS_SetXFocus( (HWND32)hwndFocus );
1106 return;
1109 /**********************************************************************
1110 * EVENT_Capture
1112 * We need this to be able to generate double click messages
1113 * when menu code captures mouse in the window without CS_DBLCLK style.
1115 HWND32 EVENT_Capture(HWND32 hwnd, INT16 ht)
1117 Window win;
1118 HWND32 capturePrev = captureWnd;
1120 if (!hwnd)
1122 XUngrabPointer(display, CurrentTime );
1123 captureWnd = NULL; captureHT = 0;
1125 else if ((win = WIN_GetXWindow( hwnd )))
1127 WND* wndPtr = WIN_FindWndPtr( hwnd );
1129 if ( wndPtr &&
1130 (XGrabPointer(display, win, False,
1131 ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
1132 GrabModeAsync, GrabModeAsync,
1133 None, None, CurrentTime ) == GrabSuccess) )
1135 dprintf_win(stddeb, "SetCapture(0x%04x)\n", hwnd );
1136 captureWnd = hwnd;
1137 captureHT = ht;
1141 if( capturePrev && capturePrev != captureWnd )
1143 WND* wndPtr = WIN_FindWndPtr( capturePrev );
1144 if( wndPtr && (wndPtr->flags & WIN_ISWIN32) )
1145 SendMessage32A( capturePrev, WM_CAPTURECHANGED, 0L, hwnd);
1147 return capturePrev;
1150 /**********************************************************************
1151 * EVENT_GetCaptureInfo
1153 INT16 EVENT_GetCaptureInfo()
1155 return captureHT;
1158 /**********************************************************************
1159 * SetCapture16 (USER.18)
1161 HWND16 WINAPI SetCapture16( HWND16 hwnd )
1163 return (HWND16)EVENT_Capture( hwnd, HTCLIENT );
1167 /**********************************************************************
1168 * SetCapture32 (USER32.463)
1170 HWND32 WINAPI SetCapture32( HWND32 hwnd )
1172 return EVENT_Capture( hwnd, HTCLIENT );
1176 /**********************************************************************
1177 * ReleaseCapture (USER.19) (USER32.438)
1179 void WINAPI ReleaseCapture(void)
1181 dprintf_win(stddeb, "ReleaseCapture() [%04x]\n", captureWnd );
1182 if( captureWnd ) EVENT_Capture( 0, 0 );
1186 /**********************************************************************
1187 * GetCapture16 (USER.236)
1189 HWND16 WINAPI GetCapture16(void)
1191 return captureWnd;
1195 /**********************************************************************
1196 * GetCapture32 (USER32.207)
1198 HWND32 WINAPI GetCapture32(void)
1200 return captureWnd;
1204 /***********************************************************************
1205 * GetMouseEventProc (USER.337)
1207 FARPROC16 WINAPI GetMouseEventProc(void)
1209 HMODULE16 hmodule = GetModuleHandle16("USER");
1210 return MODULE_GetEntryPoint( hmodule,
1211 MODULE_GetOrdinal( hmodule, "Mouse_Event" ) );
1215 /***********************************************************************
1216 * Mouse_Event (USER.299)
1218 void WINAPI Mouse_Event( CONTEXT *context )
1220 /* Register values:
1221 * AX = mouse event
1222 * BX = horizontal displacement if AX & ME_MOVE
1223 * CX = vertical displacement if AX & ME_MOVE
1224 * DX = button state (?)
1225 * SI = mouse event flags (?)
1227 Window root, child;
1228 int rootX, rootY, winX, winY;
1229 unsigned int state;
1231 if (AX_reg(context) & ME_MOVE)
1233 /* We have to actually move the cursor */
1234 XWarpPointer( display, rootWindow, None, 0, 0, 0, 0,
1235 (short)BX_reg(context), (short)CX_reg(context) );
1236 return;
1238 if (!XQueryPointer( display, rootWindow, &root, &child,
1239 &rootX, &rootY, &winX, &winY, &state )) return;
1240 if (AX_reg(context) & ME_LDOWN)
1241 hardware_event( WM_LBUTTONDOWN, EVENT_XStateToKeyState( state ),
1242 0L, winX, winY, GetTickCount(), 0 );
1243 if (AX_reg(context) & ME_LUP)
1244 hardware_event( WM_LBUTTONUP, EVENT_XStateToKeyState( state ),
1245 0L, winX, winY, GetTickCount(), 0 );
1246 if (AX_reg(context) & ME_RDOWN)
1247 hardware_event( WM_RBUTTONDOWN, EVENT_XStateToKeyState( state ),
1248 0L, winX, winY, GetTickCount(), 0 );
1249 if (AX_reg(context) & ME_RUP)
1250 hardware_event( WM_RBUTTONUP, EVENT_XStateToKeyState( state ),
1251 0L, winX, winY, GetTickCount(), 0 );
1255 /**********************************************************************
1256 * EnableHardwareInput (USER.331)
1258 BOOL16 WINAPI EnableHardwareInput(BOOL16 bEnable)
1260 BOOL16 bOldState = InputEnabled;
1261 dprintf_event(stdnimp,"EnableHardwareInput(%d);\n", bEnable);
1262 InputEnabled = bEnable;
1263 return bOldState;
1267 /***********************************************************************
1268 * SwapMouseButton16 (USER.186)
1270 BOOL16 WINAPI SwapMouseButton16( BOOL16 fSwap )
1272 BOOL16 ret = SwappedButtons;
1273 SwappedButtons = fSwap;
1274 return ret;
1278 /***********************************************************************
1279 * SwapMouseButton32 (USER32.536)
1281 BOOL32 WINAPI SwapMouseButton32( BOOL32 fSwap )
1283 BOOL32 ret = SwappedButtons;
1284 SwappedButtons = fSwap;
1285 return ret;