Release 980315
[wine/multimedia.git] / windows / event.c
blobe55c048d8c188eda5262a5c7013fc3fc2aa79a6a
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 "debug.h"
41 #include "dde_proc.h"
44 #define NB_BUTTONS 3 /* Windows can handle 3 buttons */
46 #define DndNotDnd -1 /* OffiX drag&drop */
47 #define DndUnknown 0
48 #define DndRawData 1
49 #define DndFile 2
50 #define DndFiles 3
51 #define DndText 4
52 #define DndDir 5
53 #define DndLink 6
54 #define DndExe 7
56 #define DndEND 8
58 /* X context to associate a hwnd to an X window */
59 static XContext winContext = 0;
61 static INT16 captureHT = HTCLIENT;
62 static HWND32 captureWnd = 0;
63 static BOOL32 InputEnabled = TRUE;
64 static BOOL32 SwappedButtons = FALSE;
66 static Atom wmProtocols = None;
67 static Atom wmDeleteWindow = None;
68 static Atom dndProtocol = None;
69 static Atom dndSelection = None;
71 /* EVENT_WaitNetEvent() master fd sets */
73 static fd_set __event_io_set[3];
74 static int __event_max_fd = 0;
75 static int __event_x_connection = 0;
77 static const char * const event_names[] =
79 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
80 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
81 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
82 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
83 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
84 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
85 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
86 "ClientMessage", "MappingNotify"
89 /* Event handlers */
90 static void EVENT_Key( WND *pWnd, XKeyEvent *event );
91 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event );
92 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event );
93 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event );
94 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event );
95 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event );
96 static void EVENT_Expose( WND *pWnd, XExposeEvent *event );
97 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event );
98 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event );
99 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event);
100 static void EVENT_SelectionNotify( XSelectionEvent *event);
101 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event);
102 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event );
103 static void EVENT_MapNotify( HWND32 hwnd, XMapEvent *event );
105 /* Usable only with OLVWM - compile option perhaps?
106 static void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event );
109 extern void FOCUS_SetXFocus( HWND32 );
110 extern BOOL16 DRAG_QueryUpdate( HWND16, SEGPTR, BOOL32 );
111 extern BOOL32 WINSOCK_HandleIO( int* max_fd, int num_pending, fd_set p[3], fd_set e[3] );
113 /***********************************************************************
114 * EVENT_Init
116 * Initialize network IO.
118 BOOL32 EVENT_Init(void)
120 int i;
121 for( i = 0; i < 3; i++ )
122 FD_ZERO( __event_io_set + i );
124 __event_max_fd = __event_x_connection = ConnectionNumber(display);
125 FD_SET( __event_x_connection, &__event_io_set[EVENT_IO_READ] );
126 __event_max_fd++;
127 return TRUE;
130 /***********************************************************************
131 * EVENT_AddIO
133 void EVENT_AddIO( int fd, int io_type )
135 FD_SET( fd, &__event_io_set[io_type] );
136 if( __event_max_fd <= fd ) __event_max_fd = fd + 1;
139 void EVENT_DeleteIO( int fd, int io_type )
141 FD_CLR( fd, &__event_io_set[io_type] );
144 /***********************************************************************
145 * EVENT_ProcessEvent
147 * Process an X event.
149 void EVENT_ProcessEvent( XEvent *event )
151 WND *pWnd;
153 if (TSXFindContext( display, event->xany.window, winContext,
154 (char **)&pWnd ) != 0)
155 return; /* Not for a registered window */
157 TRACE(event, "Got event %s for hwnd %04x\n",
158 event_names[event->type], pWnd->hwndSelf );
160 switch(event->type)
162 case KeyPress:
163 case KeyRelease:
164 if (InputEnabled) EVENT_Key( pWnd, (XKeyEvent*)event );
165 break;
167 case ButtonPress:
168 if (InputEnabled)
169 EVENT_ButtonPress( pWnd, (XButtonEvent*)event );
170 break;
172 case ButtonRelease:
173 if (InputEnabled)
174 EVENT_ButtonRelease( pWnd, (XButtonEvent*)event );
175 break;
177 case MotionNotify:
178 /* Wine between two fast machines across the overloaded campus
179 ethernet gets very boged down in MotionEvents. The following
180 simply finds the last motion event in the queue and drops
181 the rest. On a good link events are servered before they build
182 up so this doesn't take place. On a slow link this may cause
183 problems if the event order is important. I'm not yet seen
184 of any problems. Jon 7/6/96.
186 if (InputEnabled)
188 while (TSXCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
189 MotionNotify, event));
190 EVENT_MotionNotify( pWnd, (XMotionEvent*)event );
192 break;
194 case FocusIn:
195 EVENT_FocusIn( pWnd, (XFocusChangeEvent*)event );
196 break;
198 case FocusOut:
199 EVENT_FocusOut( pWnd, (XFocusChangeEvent*)event );
200 break;
202 case Expose:
203 EVENT_Expose( pWnd, (XExposeEvent *)event );
204 break;
206 case GraphicsExpose:
207 EVENT_GraphicsExpose( pWnd, (XGraphicsExposeEvent *)event );
208 break;
210 case ConfigureNotify:
211 EVENT_ConfigureNotify( pWnd, (XConfigureEvent*)event );
212 break;
214 case SelectionRequest:
215 EVENT_SelectionRequest( pWnd, (XSelectionRequestEvent *)event );
216 break;
218 case SelectionNotify:
219 EVENT_SelectionNotify( (XSelectionEvent *)event );
220 break;
222 case SelectionClear:
223 EVENT_SelectionClear( pWnd, (XSelectionClearEvent*) event );
224 break;
226 case ClientMessage:
227 EVENT_ClientMessage( pWnd, (XClientMessageEvent *) event );
228 break;
230 /* case EnterNotify:
231 * EVENT_EnterNotify( pWnd, (XCrossingEvent *) event );
232 * break;
234 case NoExpose:
235 break;
237 /* We get all these because of StructureNotifyMask. */
238 case UnmapNotify:
239 case CirculateNotify:
240 case CreateNotify:
241 case DestroyNotify:
242 case GravityNotify:
243 case ReparentNotify:
244 break;
246 case MapNotify:
247 EVENT_MapNotify( pWnd->hwndSelf, (XMapEvent *)event );
248 break;
250 default:
251 WARN(event, "Unprocessed event %s for hwnd %04x\n",
252 event_names[event->type], pWnd->hwndSelf );
253 break;
258 /***********************************************************************
259 * EVENT_RegisterWindow
261 * Associate an X window to a HWND.
263 void EVENT_RegisterWindow( WND *pWnd )
265 if (wmProtocols == None)
266 wmProtocols = TSXInternAtom( display, "WM_PROTOCOLS", True );
267 if (wmDeleteWindow == None)
268 wmDeleteWindow = TSXInternAtom( display, "WM_DELETE_WINDOW", True );
269 if( dndProtocol == None )
270 dndProtocol = TSXInternAtom( display, "DndProtocol" , False );
271 if( dndSelection == None )
272 dndSelection = TSXInternAtom( display, "DndSelection" , False );
274 TSXSetWMProtocols( display, pWnd->window, &wmDeleteWindow, 1 );
276 if (!winContext) winContext = TSXUniqueContext();
277 TSXSaveContext( display, pWnd->window, winContext, (char *)pWnd );
280 /***********************************************************************
281 * EVENT_DestroyWindow
283 void EVENT_DestroyWindow( WND *pWnd )
285 XEvent xe;
287 TSXDeleteContext( display, pWnd->window, winContext );
288 TSXDestroyWindow( display, pWnd->window );
289 while( TSXCheckWindowEvent(display, pWnd->window, NoEventMask, &xe) );
293 /***********************************************************************
294 * IsUserIdle (USER.333)
296 * Check if we have pending X events.
298 BOOL16 WINAPI IsUserIdle(void)
300 struct timeval timeout = {0, 0};
301 fd_set check_set;
303 FD_ZERO(&check_set);
304 FD_SET(__event_x_connection, &check_set);
305 if( select(__event_x_connection + 1, &check_set, NULL, NULL, &timeout) > 0 )
306 return TRUE;
307 return FALSE;
311 /***********************************************************************
312 * EVENT_WaitNetEvent
314 * Wait for a network event, optionally sleeping until one arrives.
315 * Return TRUE if an event is pending, FALSE on timeout or error
316 * (for instance lost connection with the server).
318 BOOL32 EVENT_WaitNetEvent( BOOL32 sleep, BOOL32 peek )
320 XEvent event;
321 LONG maxWait = sleep ? TIMER_GetNextExpiration() : 0;
322 int pending = TSXPending(display);
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) && !pending)
330 int num_pending;
331 struct timeval timeout;
332 fd_set io_set[3];
334 memcpy( io_set, __event_io_set, sizeof(io_set) );
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, &io_set[EVENT_IO_READ],
351 &io_set[EVENT_IO_WRITE],
352 &io_set[EVENT_IO_EXCEPT], &timeout );
353 if ( num_pending == 0 )
355 stop_wait_op = CONT;
356 TIMER_ExpireTimers();
357 return FALSE;
359 else stop_wait_op = CONT;
360 #else /* CONFIG_IPC */
361 num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
362 &io_set[EVENT_IO_WRITE],
363 &io_set[EVENT_IO_EXCEPT], &timeout );
364 if ( num_pending == 0)
366 /* Timeout or error */
367 TIMER_ExpireTimers();
368 return FALSE;
370 #endif /* CONFIG_IPC */
372 /* Winsock asynchronous services */
374 if( FD_ISSET( __event_x_connection, &io_set[EVENT_IO_READ]) )
376 num_pending--;
377 if( num_pending )
378 WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
380 else /* no X events */
381 return WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
383 else if(!pending)
384 { /* Wait for X11 input. */
385 fd_set set;
387 FD_ZERO(&set);
388 FD_SET(__event_x_connection, &set);
389 select(__event_x_connection + 1, &set, 0, 0, 0 );
392 /* Process current X event (and possibly others that occurred in the meantime) */
397 #ifdef CONFIG_IPC
398 if (DDE_GetRemoteMessage())
400 while(DDE_GetRemoteMessage()) ;
401 return TRUE;
403 #endif /* CONFIG_IPC */
405 TSXNextEvent( display, &event );
407 if( peek )
409 WND* pWnd;
410 MESSAGEQUEUE* pQ;
412 if (TSXFindContext( display, ((XAnyEvent *)&event)->window, winContext,
413 (char **)&pWnd ) || (event.type == NoExpose))
414 continue;
416 /* Check only for those events which can be processed
417 * internally. */
419 if( event.type == MotionNotify ||
420 event.type == ButtonPress || event.type == ButtonRelease ||
421 event.type == KeyPress || event.type == KeyRelease ||
422 event.type == SelectionRequest || event.type == SelectionClear )
424 EVENT_ProcessEvent( &event );
425 continue;
428 if( pWnd )
430 if( (pQ = (MESSAGEQUEUE*)GlobalLock16(pWnd->hmemTaskQ)) )
432 pQ->flags |= QUEUE_FLAG_XEVENT;
433 PostEvent(pQ->hTask);
434 TSXPutBackEvent(display, &event);
435 break;
439 else EVENT_ProcessEvent( &event );
441 while (TSXPending( display ));
442 return TRUE;
446 /***********************************************************************
447 * EVENT_Synchronize
449 * Synchronize with the X server. Should not be used too often.
451 void EVENT_Synchronize()
453 XEvent event;
455 TSXSync( display, False );
456 while (TSXPending( display ))
458 TSXNextEvent( display, &event );
459 EVENT_ProcessEvent( &event );
463 /***********************************************************************
464 * EVENT_QueryZOrder
466 * Try to synchronize internal z-order with the window manager's.
467 * Probably a futile endeavor.
469 static BOOL32 __check_query_condition( WND** pWndA, WND** pWndB )
471 /* return TRUE if we have at least two managed windows */
473 for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
474 if( (*pWndA)->flags & WIN_MANAGED &&
475 (*pWndA)->dwStyle & WS_VISIBLE ) break;
476 if( *pWndA )
477 for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
478 if( (*pWndB)->flags & WIN_MANAGED &&
479 (*pWndB)->dwStyle & WS_VISIBLE ) break;
480 return ((*pWndB) != NULL);
483 static Window __get_common_ancestor( Window A, Window B,
484 Window** children, unsigned* total )
486 /* find the real root window */
488 Window root, *childrenB;
489 unsigned totalB;
493 if( *children ) TSXFree( *children );
494 TSXQueryTree( display, A, &root, &A, children, total );
495 TSXQueryTree( display, B, &root, &B, &childrenB, &totalB );
496 if( childrenB ) TSXFree( childrenB );
497 } while( A != B && A && B );
498 return ( A && B ) ? A : 0 ;
501 static Window __get_top_decoration( Window w, Window ancestor )
503 Window* children, root, prev = w, parent = w;
504 unsigned total;
508 w = parent;
509 TSXQueryTree( display, w, &root, &parent, &children, &total );
510 if( children ) TSXFree( children );
511 } while( parent && parent != ancestor );
512 TRACE(event, "\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
513 return ( parent ) ? w : 0 ;
516 static unsigned __td_lookup( Window w, Window* list, unsigned max )
518 unsigned i;
519 for( i = 0; i < max; i++ ) if( list[i] == w ) break;
520 return i;
523 static BOOL32 EVENT_QueryZOrder( WND* pWndCheck )
525 BOOL32 bRet = FALSE;
526 HWND32 hwndInsertAfter = HWND_TOP;
527 WND* pWnd, *pWndZ = WIN_GetDesktop()->child;
528 Window w, parent, *children = NULL;
529 unsigned total, check, pos, best;
531 if( !__check_query_condition(&pWndZ, &pWnd) ) return TRUE;
533 parent = __get_common_ancestor( pWndZ->window, pWnd->window,
534 &children, &total );
535 if( parent && children )
537 w = __get_top_decoration( pWndCheck->window, parent );
538 if( w != children[total - 1] )
540 check = __td_lookup( w, children, total );
541 best = total;
542 for( pWnd = pWndZ; pWnd; pWnd = pWnd->next )
544 if( pWnd != pWndCheck )
546 if( !(pWnd->flags & WIN_MANAGED) ||
547 !(w = __get_top_decoration( pWnd->window, parent )) )
548 continue;
549 pos = __td_lookup( w, children, total );
550 if( pos < best && pos > check )
552 best = pos;
553 hwndInsertAfter = pWnd->hwndSelf;
555 if( check - best == 1 ) break;
558 WIN_UnlinkWindow( pWndCheck->hwndSelf );
559 WIN_LinkWindow( pWndCheck->hwndSelf, hwndInsertAfter);
562 if( children ) TSXFree( children );
563 return bRet;
567 /***********************************************************************
568 * EVENT_XStateToKeyState
570 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
571 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
573 static WORD EVENT_XStateToKeyState( int state )
575 int kstate = 0;
577 if (state & Button1Mask) kstate |= MK_LBUTTON;
578 if (state & Button2Mask) kstate |= MK_MBUTTON;
579 if (state & Button3Mask) kstate |= MK_RBUTTON;
580 if (state & ShiftMask) kstate |= MK_SHIFT;
581 if (state & ControlMask) kstate |= MK_CONTROL;
582 return kstate;
586 /***********************************************************************
587 * EVENT_Expose
589 static void EVENT_Expose( WND *pWnd, XExposeEvent *event )
591 RECT32 rect;
593 /* Make position relative to client area instead of window */
594 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
595 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
596 rect.right = rect.left + event->width;
597 rect.bottom = rect.top + event->height;
599 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
600 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
601 (event->count ? 0 : RDW_ERASENOW), 0 );
605 /***********************************************************************
606 * EVENT_GraphicsExpose
608 * This is needed when scrolling area is partially obscured
609 * by non-Wine X window.
611 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event )
613 RECT32 rect;
615 /* Make position relative to client area instead of window */
616 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
617 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
618 rect.right = rect.left + event->width;
619 rect.bottom = rect.top + event->height;
621 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
622 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
623 (event->count ? 0 : RDW_ERASENOW), 0 );
627 /***********************************************************************
628 * EVENT_Key
630 * Handle a X key event
632 static void EVENT_Key( WND *pWnd, XKeyEvent *event )
634 KEYBOARD_HandleEvent( pWnd, event );
638 /***********************************************************************
639 * EVENT_MotionNotify
641 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event )
643 hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ), 0L,
644 pWnd->rectWindow.left + event->x,
645 pWnd->rectWindow.top + event->y,
646 event->time - MSG_WineStartTicks, pWnd->hwndSelf );
650 /***********************************************************************
651 * EVENT_DummyMotionNotify
653 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
655 void EVENT_DummyMotionNotify(void)
657 Window root, child;
658 int rootX, rootY, winX, winY;
659 unsigned int state;
661 if (TSXQueryPointer( display, rootWindow, &root, &child,
662 &rootX, &rootY, &winX, &winY, &state ))
664 hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( state ), 0L,
665 winX, winY, GetTickCount(), 0 );
670 /***********************************************************************
671 * EVENT_ButtonPress
673 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event )
675 static WORD messages[NB_BUTTONS] =
676 { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
677 int buttonNum = event->button - 1;
679 if (buttonNum >= NB_BUTTONS) return;
680 if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
681 MouseButtonsStates[buttonNum] = TRUE;
682 AsyncMouseButtonsStates[buttonNum] = TRUE;
683 hardware_event( messages[buttonNum],
684 EVENT_XStateToKeyState( event->state ), 0L,
685 pWnd->rectWindow.left + event->x,
686 pWnd->rectWindow.top + event->y,
687 event->time - MSG_WineStartTicks, pWnd->hwndSelf );
691 /***********************************************************************
692 * EVENT_ButtonRelease
694 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event )
696 static const WORD messages[NB_BUTTONS] =
697 { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
698 int buttonNum = event->button - 1;
700 if (buttonNum >= NB_BUTTONS) return;
701 if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
702 MouseButtonsStates[buttonNum] = FALSE;
703 hardware_event( messages[buttonNum],
704 EVENT_XStateToKeyState( event->state ), 0L,
705 pWnd->rectWindow.left + event->x,
706 pWnd->rectWindow.top + event->y,
707 event->time - MSG_WineStartTicks, pWnd->hwndSelf );
711 /**********************************************************************
712 * EVENT_FocusIn
714 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event )
716 if (Options.managed) EVENT_QueryZOrder( pWnd );
718 if (event->detail != NotifyPointer)
720 HWND32 hwnd = pWnd->hwndSelf;
722 if (hwnd != GetActiveWindow32())
723 WINPOS_ChangeActiveWindow( hwnd, FALSE );
724 if ((hwnd != GetFocus32()) && !IsChild32( hwnd, GetFocus32()))
725 SetFocus32( hwnd );
730 /**********************************************************************
731 * EVENT_FocusOut
733 * Note: only top-level override-redirect windows get FocusOut events.
735 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event )
737 if (event->detail != NotifyPointer)
739 HWND32 hwnd = pWnd->hwndSelf;
741 if (hwnd == GetActiveWindow32())
742 WINPOS_ChangeActiveWindow( 0, FALSE );
743 if ((hwnd == GetFocus32()) || IsChild32( hwnd, GetFocus32()))
744 SetFocus32( 0 );
748 /**********************************************************************
749 * EVENT_CheckFocus
751 BOOL32 EVENT_CheckFocus(void)
753 WND* pWnd;
754 Window xW;
755 int state;
757 TSXGetInputFocus(display, &xW, &state);
758 if( xW == None ||
759 TSXFindContext(display, xW, winContext, (char **)&pWnd) )
760 return FALSE;
761 return TRUE;
765 /**********************************************************************
766 * EVENT_GetGeometry
768 * Helper function for ConfigureNotify handling.
769 * Get the new geometry of a window relative to the root window.
771 static void EVENT_GetGeometry( Window win, int *px, int *py,
772 unsigned int *pwidth, unsigned int *pheight )
774 Window root, parent, *children;
775 int xpos, ypos;
776 unsigned int width, height, border, depth, nb_children;
778 if (!TSXGetGeometry( display, win, &root, px, py, pwidth, pheight,
779 &border, &depth )) return;
780 if (win == rootWindow)
782 *px = *py = 0;
783 return;
786 for (;;)
788 if (!TSXQueryTree(display, win, &root, &parent, &children, &nb_children))
789 return;
790 TSXFree( children );
791 if (parent == rootWindow) break;
792 win = parent;
793 if (!TSXGetGeometry( display, win, &root, &xpos, &ypos,
794 &width, &height, &border, &depth )) return;
795 *px += xpos;
796 *py += ypos;
801 /**********************************************************************
802 * EVENT_ConfigureNotify
804 * The ConfigureNotify event is only selected on top-level windows
805 * when the -managed flag is used.
807 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event )
809 WINDOWPOS32 winpos;
810 RECT32 newWindowRect, newClientRect;
811 HRGN32 hrgnOldPos, hrgnNewPos;
812 Window above = event->above;
813 int x, y;
814 unsigned int width, height;
816 assert (pWnd->flags & WIN_MANAGED);
818 /* We don't rely on the event geometry info, because it is relative
819 * to parent and not to root, and it may be wrong (XFree sets x,y to 0,0
820 * if the window hasn't moved).
822 EVENT_GetGeometry( event->window, &x, &y, &width, &height );
824 /* Fill WINDOWPOS struct */
825 winpos.flags = SWP_NOACTIVATE | SWP_NOZORDER;
826 winpos.hwnd = pWnd->hwndSelf;
827 winpos.x = x;
828 winpos.y = y;
829 winpos.cx = width;
830 winpos.cy = height;
832 /* Check for unchanged attributes */
833 if (winpos.x == pWnd->rectWindow.left && winpos.y == pWnd->rectWindow.top)
834 winpos.flags |= SWP_NOMOVE;
835 if ((winpos.cx == pWnd->rectWindow.right - pWnd->rectWindow.left) &&
836 (winpos.cy == pWnd->rectWindow.bottom - pWnd->rectWindow.top))
837 winpos.flags |= SWP_NOSIZE;
838 else
840 RECT32 rect = { 0, 0, pWnd->rectWindow.right - pWnd->rectWindow.left,
841 pWnd->rectWindow.bottom - pWnd->rectWindow.top };
842 DCE_InvalidateDCE( pWnd, &rect );
845 /* Send WM_WINDOWPOSCHANGING */
846 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)&winpos );
848 /* Calculate new position and size */
849 newWindowRect.left = x;
850 newWindowRect.right = x + width;
851 newWindowRect.top = y;
852 newWindowRect.bottom = y + height;
854 WINPOS_SendNCCalcSize( winpos.hwnd, TRUE, &newWindowRect,
855 &pWnd->rectWindow, &pWnd->rectClient,
856 &winpos, &newClientRect );
858 hrgnOldPos = CreateRectRgnIndirect32( &pWnd->rectWindow );
859 hrgnNewPos = CreateRectRgnIndirect32( &newWindowRect );
860 CombineRgn32( hrgnOldPos, hrgnOldPos, hrgnNewPos, RGN_DIFF );
861 DeleteObject32(hrgnOldPos);
862 DeleteObject32(hrgnNewPos);
864 /* Set new size and position */
865 pWnd->rectWindow = newWindowRect;
866 pWnd->rectClient = newClientRect;
867 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)&winpos );
869 if (!IsWindow32( winpos.hwnd )) return;
870 if( above == None ) /* absolute bottom */
872 WIN_UnlinkWindow( winpos.hwnd );
873 WIN_LinkWindow( winpos.hwnd, HWND_BOTTOM);
875 else EVENT_QueryZOrder( pWnd ); /* try to outsmart window manager */
879 /***********************************************************************
880 * EVENT_SelectionRequest
882 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event )
884 XSelectionEvent result;
885 Atom rprop = None;
886 Window request = event->requestor;
888 if(event->target == XA_STRING)
890 HANDLE16 hText;
891 LPSTR text;
892 int size,i,j;
894 rprop = event->property;
896 if(rprop == None) rprop = event->target;
898 if(event->selection!=XA_PRIMARY) rprop = None;
899 else if(!CLIPBOARD_IsPresent(CF_OEMTEXT)) rprop = None;
900 else
902 /* open to make sure that clipboard is available */
904 BOOL32 couldOpen = OpenClipboard32( pWnd->hwndSelf );
905 char* lpstr = 0;
907 hText = GetClipboardData16(CF_TEXT);
908 text = GlobalLock16(hText);
909 size = GlobalSize16(hText);
911 /* remove carriage returns */
913 lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
914 for(i=0,j=0; i < size && text[i]; i++ )
916 if( text[i] == '\r' &&
917 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
918 lpstr[j++] = text[i];
920 lpstr[j]='\0';
922 TSXChangeProperty(display, request, rprop,
923 XA_STRING, 8, PropModeReplace,
924 lpstr, j);
925 HeapFree( GetProcessHeap(), 0, lpstr );
927 /* close only if we opened before */
929 if(couldOpen) CloseClipboard32();
933 if(rprop == None)
934 TRACE(event,"Request for %s ignored\n", TSXGetAtomName(display,event->target));
936 result.type = SelectionNotify;
937 result.display = display;
938 result.requestor = request;
939 result.selection = event->selection;
940 result.property = rprop;
941 result.target = event->target;
942 result.time = event->time;
943 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
947 /***********************************************************************
948 * EVENT_SelectionNotify
950 static void EVENT_SelectionNotify( XSelectionEvent *event )
952 if (event->selection != XA_PRIMARY) return;
954 if (event->target != XA_STRING) CLIPBOARD_ReadSelection( 0, None );
955 else CLIPBOARD_ReadSelection( event->requestor, event->property );
957 TRACE(clipboard,"\tSelectionNotify done!\n");
961 /***********************************************************************
962 * EVENT_SelectionClear
964 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event )
966 if (event->selection != XA_PRIMARY) return;
967 CLIPBOARD_ReleaseSelection( event->window, pWnd->hwndSelf );
971 /**********************************************************************
972 * EVENT_ClientMessage
974 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event )
976 if (event->message_type != None && event->format == 32)
978 if ((event->message_type == wmProtocols) &&
979 (((Atom) event->data.l[0]) == wmDeleteWindow))
980 SendMessage16( pWnd->hwndSelf, WM_SYSCOMMAND, SC_CLOSE, 0 );
981 else if ( event->message_type == dndProtocol &&
982 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
984 unsigned long data_length;
985 unsigned long aux_long;
986 unsigned char* p_data = NULL;
987 union {
988 Atom atom_aux;
989 POINT32 pt_aux;
990 int i;
991 } u;
992 int x, y;
993 BOOL16 bAccept;
994 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
995 LPDRAGINFO lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
996 SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
997 Window w_aux_root, w_aux_child;
998 WND* pDropWnd;
1000 if( !lpDragInfo || !spDragInfo ) return;
1002 TSXQueryPointer( display, pWnd->window, &w_aux_root, &w_aux_child,
1003 &x, &y, &u.pt_aux.x, &u.pt_aux.y, (unsigned int*)&aux_long);
1005 lpDragInfo->hScope = pWnd->hwndSelf;
1006 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1008 /* find out drop point and drop window */
1009 if( x < 0 || y < 0 ||
1010 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1011 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1012 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1013 else
1015 bAccept = DRAG_QueryUpdate( pWnd->hwndSelf, spDragInfo, TRUE );
1016 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1018 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1019 GlobalFree16( hDragInfo );
1021 if( bAccept )
1023 TSXGetWindowProperty( display, DefaultRootWindow(display),
1024 dndSelection, 0, 65535, FALSE,
1025 AnyPropertyType, &u.atom_aux, &u.pt_aux.y,
1026 &data_length, &aux_long, &p_data);
1028 if( !aux_long && p_data) /* don't bother if > 64K */
1030 char *p = (char*) p_data;
1031 char *p_drop;
1033 aux_long = 0;
1034 while( *p ) /* calculate buffer size */
1036 p_drop = p;
1037 if((u.i = *p) != -1 )
1038 u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
1039 if( u.i == -1 ) *p = -1; /* mark as "bad" */
1040 else
1042 INT32 len = GetShortPathName32A( p, NULL, 0 );
1043 if (len) aux_long += len + 1;
1044 else *p = -1;
1046 p += strlen(p) + 1;
1048 if( aux_long && aux_long < 65535 )
1050 HDROP16 hDrop;
1051 LPDROPFILESTRUCT lpDrop;
1053 aux_long += sizeof(DROPFILESTRUCT) + 1;
1054 hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
1055 lpDrop = (LPDROPFILESTRUCT) GlobalLock16( hDrop );
1057 if( lpDrop )
1059 lpDrop->wSize = sizeof(DROPFILESTRUCT);
1060 lpDrop->ptMousePos.x = (INT16)x;
1061 lpDrop->ptMousePos.y = (INT16)y;
1062 lpDrop->fInNonClientArea = (BOOL16)
1063 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1064 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1065 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1066 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1067 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT);
1068 p = p_data;
1069 while(*p)
1071 if( *p != -1 ) /* use only "good" entries */
1073 GetShortPathName32A( p, p_drop, 65535 );
1074 p_drop += strlen( p_drop ) + 1;
1076 p += strlen(p) + 1;
1078 *p_drop = '\0';
1079 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1080 (WPARAM16)hDrop, 0L );
1084 if( p_data ) TSXFree(p_data);
1086 } /* WS_EX_ACCEPTFILES */
1087 } /* dndProtocol */
1088 else
1089 TRACE(event, "unrecognized ClientMessage\n" );
1093 /**********************************************************************
1094 * EVENT_EnterNotify
1096 * Install colormap when Wine window is focused in
1097 * self-managed mode with private colormap
1100 void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
1102 if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
1103 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
1104 TSXInstallColormap( display, COLOR_GetColormap() );
1108 /**********************************************************************
1109 * EVENT_MapNotify
1111 void EVENT_MapNotify( HWND32 hWnd, XMapEvent *event )
1113 HWND32 hwndFocus = GetFocus32();
1115 if (hwndFocus && IsChild32( hWnd, hwndFocus ))
1116 FOCUS_SetXFocus( (HWND32)hwndFocus );
1118 return;
1121 /**********************************************************************
1122 * EVENT_Capture
1124 * We need this to be able to generate double click messages
1125 * when menu code captures mouse in the window without CS_DBLCLK style.
1127 HWND32 EVENT_Capture(HWND32 hwnd, INT16 ht)
1129 Window win;
1130 HWND32 capturePrev = captureWnd;
1132 if (!hwnd)
1134 TSXUngrabPointer(display, CurrentTime );
1135 captureWnd = NULL; captureHT = 0;
1137 else if ((win = WIN_GetXWindow( hwnd )))
1139 WND* wndPtr = WIN_FindWndPtr( hwnd );
1141 if ( wndPtr &&
1142 (TSXGrabPointer(display, win, False,
1143 ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
1144 GrabModeAsync, GrabModeAsync,
1145 None, None, CurrentTime ) == GrabSuccess) )
1147 TRACE(win, "(0x%04x)\n", hwnd );
1148 captureWnd = hwnd;
1149 captureHT = ht;
1153 if( capturePrev && capturePrev != captureWnd )
1155 WND* wndPtr = WIN_FindWndPtr( capturePrev );
1156 if( wndPtr && (wndPtr->flags & WIN_ISWIN32) )
1157 SendMessage32A( capturePrev, WM_CAPTURECHANGED, 0L, hwnd);
1159 return capturePrev;
1162 /**********************************************************************
1163 * EVENT_GetCaptureInfo
1165 INT16 EVENT_GetCaptureInfo()
1167 return captureHT;
1170 /**********************************************************************
1171 * SetCapture16 (USER.18)
1173 HWND16 WINAPI SetCapture16( HWND16 hwnd )
1175 return (HWND16)EVENT_Capture( hwnd, HTCLIENT );
1179 /**********************************************************************
1180 * SetCapture32 (USER32.463)
1182 HWND32 WINAPI SetCapture32( HWND32 hwnd )
1184 return EVENT_Capture( hwnd, HTCLIENT );
1188 /**********************************************************************
1189 * ReleaseCapture (USER.19) (USER32.438)
1191 void WINAPI ReleaseCapture(void)
1193 TRACE(win, "captureWnd=%04x\n", captureWnd );
1194 if( captureWnd ) EVENT_Capture( 0, 0 );
1198 /**********************************************************************
1199 * GetCapture16 (USER.236)
1201 HWND16 WINAPI GetCapture16(void)
1203 return captureWnd;
1207 /**********************************************************************
1208 * GetCapture32 (USER32.207)
1210 HWND32 WINAPI GetCapture32(void)
1212 return captureWnd;
1216 /***********************************************************************
1217 * GetMouseEventProc (USER.337)
1219 FARPROC16 WINAPI GetMouseEventProc(void)
1221 HMODULE16 hmodule = GetModuleHandle16("USER");
1222 return MODULE_GetEntryPoint( hmodule,
1223 MODULE_GetOrdinal( hmodule, "Mouse_Event" ) );
1227 /***********************************************************************
1228 * Mouse_Event (USER.299)
1230 void WINAPI Mouse_Event( CONTEXT *context )
1232 /* Register values:
1233 * AX = mouse event
1234 * BX = horizontal displacement if AX & ME_MOVE
1235 * CX = vertical displacement if AX & ME_MOVE
1236 * DX = button state (?)
1237 * SI = mouse event flags (?)
1239 Window root, child;
1240 int rootX, rootY, winX, winY;
1241 unsigned int state;
1243 if (AX_reg(context) & ME_MOVE)
1245 /* We have to actually move the cursor */
1246 TSXWarpPointer( display, rootWindow, None, 0, 0, 0, 0,
1247 (short)BX_reg(context), (short)CX_reg(context) );
1248 return;
1250 if (!TSXQueryPointer( display, rootWindow, &root, &child,
1251 &rootX, &rootY, &winX, &winY, &state )) return;
1252 if (AX_reg(context) & ME_LDOWN)
1253 hardware_event( WM_LBUTTONDOWN, EVENT_XStateToKeyState( state ),
1254 0L, winX, winY, GetTickCount(), 0 );
1255 if (AX_reg(context) & ME_LUP)
1256 hardware_event( WM_LBUTTONUP, EVENT_XStateToKeyState( state ),
1257 0L, winX, winY, GetTickCount(), 0 );
1258 if (AX_reg(context) & ME_RDOWN)
1259 hardware_event( WM_RBUTTONDOWN, EVENT_XStateToKeyState( state ),
1260 0L, winX, winY, GetTickCount(), 0 );
1261 if (AX_reg(context) & ME_RUP)
1262 hardware_event( WM_RBUTTONUP, EVENT_XStateToKeyState( state ),
1263 0L, winX, winY, GetTickCount(), 0 );
1267 /**********************************************************************
1268 * EnableHardwareInput (USER.331)
1270 BOOL16 WINAPI EnableHardwareInput(BOOL16 bEnable)
1272 BOOL16 bOldState = InputEnabled;
1273 FIXME(event,"(%d) - stub\n", bEnable);
1274 InputEnabled = bEnable;
1275 return bOldState;
1279 /***********************************************************************
1280 * SwapMouseButton16 (USER.186)
1282 BOOL16 WINAPI SwapMouseButton16( BOOL16 fSwap )
1284 BOOL16 ret = SwappedButtons;
1285 SwappedButtons = fSwap;
1286 return ret;
1290 /***********************************************************************
1291 * SwapMouseButton32 (USER32.536)
1293 BOOL32 WINAPI SwapMouseButton32( BOOL32 fSwap )
1295 BOOL32 ret = SwappedButtons;
1296 SwappedButtons = fSwap;
1297 return ret;