Release 970914
[wine.git] / windows / event.c
blobc843ec9bb43d9994f572cdcd36ddc7f303fadae8
1 /*
2 * X events handling functions
3 *
4 * Copyright 1993 Alexandre Julliard
5 *
6 */
8 #include <ctype.h>
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <sys/time.h>
14 #include <sys/types.h>
15 #include <errno.h>
16 #include <X11/keysym.h>
17 #include <X11/Xlib.h>
18 #include <X11/Xresource.h>
19 #include <X11/Xutil.h>
20 #include <X11/Xatom.h>
22 #include "windows.h"
23 #include "winnt.h"
24 #include "gdi.h"
25 #include "heap.h"
26 #include "queue.h"
27 #include "win.h"
28 #include "class.h"
29 #include "clipboard.h"
30 #include "message.h"
31 #include "module.h"
32 #include "options.h"
33 #include "queue.h"
34 #include "winpos.h"
35 #include "drive.h"
36 #include "shell.h"
37 #include "xmalloc.h"
38 #include "keyboard.h"
39 #include "stddebug.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( 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( HWND32 hwnd, 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 io_set[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 (XFindContext( display, event->xany.window, winContext,
154 (char **)&pWnd ) != 0)
155 return; /* Not for a registered window */
157 dprintf_event( stddeb, "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)
165 EVENT_Key( (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->hwndSelf, (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 )
418 if( (pQ = (MESSAGEQUEUE*)GlobalLock16(pWnd->hmemTaskQ)) )
420 pQ->flags |= QUEUE_FLAG_XEVENT;
421 PostEvent(pQ->hTask);
422 XPutBackEvent(display, &event);
423 break;
426 else
427 EVENT_ProcessEvent( &event );
429 while (XPending( display ));
430 return TRUE;
434 /***********************************************************************
435 * EVENT_Synchronize
437 * Synchronize with the X server. Should not be used too often.
439 void EVENT_Synchronize()
441 XEvent event;
443 XSync( display, False );
444 while (XPending( display ))
446 XNextEvent( display, &event );
447 EVENT_ProcessEvent( &event );
451 /***********************************************************************
452 * EVENT_QueryZOrder
454 * Try to synchronize internal z-order with the window manager's.
456 static BOOL32 __check_query_condition( WND** pWndA, WND** pWndB )
458 /* return TRUE if we have at least two managed windows */
460 for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
461 if( (*pWndA)->flags & WIN_MANAGED &&
462 (*pWndA)->dwStyle & WS_VISIBLE ) break;
463 if( *pWndA )
464 for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
465 if( (*pWndB)->flags & WIN_MANAGED &&
466 (*pWndB)->dwStyle & WS_VISIBLE ) break;
467 return ((*pWndB) != NULL);
470 static Window __get_common_ancestor( Window A, Window B,
471 Window** children, unsigned* total )
473 /* find the real root window */
475 Window root, *childrenB;
476 unsigned totalB;
480 if( *children ) XFree( *children );
481 XQueryTree( display, A, &root, &A, children, total );
482 XQueryTree( display, B, &root, &B, &childrenB, &totalB );
483 if( childrenB ) XFree( childrenB );
484 } while( A != B && A && B );
485 return ( A && B ) ? A : 0 ;
488 static Window __get_top_decoration( Window w, Window ancestor )
490 Window* children, root, prev = w, parent = w;
491 unsigned total;
495 w = parent;
496 XQueryTree( display, w, &root, &parent, &children, &total );
497 if( children ) XFree( children );
498 } while( parent && parent != ancestor );
499 dprintf_event( stddeb, "\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
500 return ( parent ) ? w : 0 ;
503 static unsigned __td_lookup( Window w, Window* list, unsigned max )
505 unsigned i;
506 for( i = 0; i < max; i++ ) if( list[i] == w ) break;
507 return i;
510 static BOOL32 EVENT_QueryZOrder( WND* pWndCheck )
512 BOOL32 bRet = FALSE;
513 HWND32 hwndInsertAfter = HWND_TOP;
514 WND* pWnd, *pWndZ = WIN_GetDesktop()->child;
515 Window w, parent, *children = NULL;
516 unsigned total, check, pos, best;
518 if( !__check_query_condition(&pWndZ, &pWnd) ) return TRUE;
520 parent = __get_common_ancestor( pWndZ->window, pWnd->window,
521 &children, &total );
522 if( parent && children )
524 w = __get_top_decoration( pWndCheck->window, parent );
525 if( w != children[total - 1] )
527 check = __td_lookup( w, children, total );
528 best = total;
529 for( pWnd = pWndZ; pWnd; pWnd = pWnd->next )
531 if( pWnd != pWndCheck )
533 if( !(pWnd->flags & WIN_MANAGED) ||
534 !(w = __get_top_decoration( pWnd->window, parent )) )
535 continue;
536 pos = __td_lookup( w, children, total );
537 if( pos < best && pos > check )
539 best = pos;
540 hwndInsertAfter = pWnd->hwndSelf;
542 if( check - best == 1 ) break;
545 WIN_UnlinkWindow( pWndCheck->hwndSelf );
546 WIN_LinkWindow( pWndCheck->hwndSelf, hwndInsertAfter);
549 if( children ) XFree( children );
550 return bRet;
554 /***********************************************************************
555 * EVENT_XStateToKeyState
557 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
558 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
560 static WORD EVENT_XStateToKeyState( int state )
562 int kstate = 0;
564 if (state & Button1Mask) kstate |= MK_LBUTTON;
565 if (state & Button2Mask) kstate |= MK_MBUTTON;
566 if (state & Button3Mask) kstate |= MK_RBUTTON;
567 if (state & ShiftMask) kstate |= MK_SHIFT;
568 if (state & ControlMask) kstate |= MK_CONTROL;
569 return kstate;
573 /***********************************************************************
574 * EVENT_Expose
576 static void EVENT_Expose( WND *pWnd, XExposeEvent *event )
578 RECT32 rect;
580 /* Make position relative to client area instead of window */
581 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
582 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
583 rect.right = rect.left + event->width;
584 rect.bottom = rect.top + event->height;
586 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
587 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
588 (event->count ? 0 : RDW_ERASENOW), 0 );
592 /***********************************************************************
593 * EVENT_GraphicsExpose
595 * This is needed when scrolling area is partially obscured
596 * by non-Wine X window.
598 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event )
600 RECT32 rect;
602 /* Make position relative to client area instead of window */
603 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
604 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
605 rect.right = rect.left + event->width;
606 rect.bottom = rect.top + event->height;
608 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
609 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
610 (event->count ? 0 : RDW_ERASENOW), 0 );
614 /***********************************************************************
615 * EVENT_Key
617 * Handle a X key event
619 static void EVENT_Key( XKeyEvent *event )
621 KEYBOARD_HandleEvent( event );
625 /***********************************************************************
626 * EVENT_MotionNotify
628 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event )
630 hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ), 0L,
631 event->x_root - desktopX, event->y_root - desktopY,
632 event->time - MSG_WineStartTicks, (DWORD)pWnd->hwndSelf );
636 /***********************************************************************
637 * EVENT_DummyMotionNotify
639 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
641 void EVENT_DummyMotionNotify(void)
643 Window root, child;
644 int rootX, rootY, childX, childY;
645 unsigned int state;
647 if (XQueryPointer( display, rootWindow, &root, &child,
648 &rootX, &rootY, &childX, &childY, &state ))
650 hardware_event(WM_MOUSEMOVE, EVENT_XStateToKeyState( state ), 0L,
651 rootX - desktopX, rootY - desktopY, GetTickCount(), 0 );
656 /***********************************************************************
657 * EVENT_ButtonPress
659 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event )
661 static WORD messages[NB_BUTTONS] =
662 { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
663 int buttonNum = event->button - 1;
665 if (buttonNum >= NB_BUTTONS) return;
666 if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
667 MouseButtonsStates[buttonNum] = 0x8000;
668 AsyncMouseButtonsStates[buttonNum] = 0x8000;
669 hardware_event( messages[buttonNum],
670 EVENT_XStateToKeyState( event->state ), 0L,
671 event->x_root - desktopX, event->y_root - desktopY,
672 event->time - MSG_WineStartTicks, (DWORD)pWnd->hwndSelf );
676 /***********************************************************************
677 * EVENT_ButtonRelease
679 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event )
681 static const WORD messages[NB_BUTTONS] =
682 { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
683 int buttonNum = event->button - 1;
685 if (buttonNum >= NB_BUTTONS) return;
686 if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
687 MouseButtonsStates[buttonNum] = FALSE;
688 hardware_event( messages[buttonNum],
689 EVENT_XStateToKeyState( event->state ), 0L,
690 event->x_root - desktopX, event->y_root - desktopY,
691 event->time - MSG_WineStartTicks, (DWORD)pWnd->hwndSelf );
695 /**********************************************************************
696 * EVENT_FocusIn
698 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event )
700 if (Options.managed) EVENT_QueryZOrder( pWnd );
702 if (event->detail != NotifyPointer)
704 HWND32 hwnd = pWnd->hwndSelf;
706 if (hwnd != GetActiveWindow32())
707 WINPOS_ChangeActiveWindow( hwnd, FALSE );
708 if ((hwnd != GetFocus32()) && !IsChild32( hwnd, GetFocus32()))
709 SetFocus32( hwnd );
714 /**********************************************************************
715 * EVENT_FocusOut
717 * Note: only top-level override-redirect windows get FocusOut events.
719 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event )
721 if (event->detail != NotifyPointer)
723 HWND32 hwnd = pWnd->hwndSelf;
725 if (hwnd == GetActiveWindow32())
726 WINPOS_ChangeActiveWindow( 0, FALSE );
727 if ((hwnd == GetFocus32()) || IsChild32( hwnd, GetFocus32()))
728 SetFocus32( 0 );
732 /**********************************************************************
733 * EVENT_CheckFocus
735 BOOL32 EVENT_CheckFocus(void)
737 WND* pWnd;
738 Window xW;
739 int state;
741 XGetInputFocus(display, &xW, &state);
742 if( xW == None ||
743 XFindContext(display, xW, winContext, (char **)&pWnd) )
744 return FALSE;
745 return TRUE;
748 /**********************************************************************
749 * EVENT_ConfigureNotify
751 * The ConfigureNotify event is only selected on the desktop window
752 * and on top-level windows when the -managed flag is used.
754 static void EVENT_ConfigureNotify( HWND32 hwnd, XConfigureEvent *event )
756 /* FIXME: with -desktop xxx we get this event _before_ desktop
757 * window structure is created. WIN_GetDesktop() check is a hack.
760 if ( !WIN_GetDesktop() || hwnd == GetDesktopWindow32())
762 desktopX = event->x;
763 desktopY = event->y;
765 else
767 WND *wndPtr = WIN_FindWndPtr( hwnd );
768 WINDOWPOS32 winpos;
769 RECT32 newWindowRect, newClientRect;
770 HRGN32 hrgnOldPos, hrgnNewPos;
771 Window above = event->above;
773 if (!wndPtr || !(wndPtr->flags & WIN_MANAGED)) return;
775 /* Fill WINDOWPOS struct */
776 winpos.flags = SWP_NOACTIVATE | SWP_NOZORDER;
777 winpos.hwnd = hwnd;
778 winpos.x = event->x;
779 winpos.y = event->y;
780 winpos.cx = event->width;
781 winpos.cy = event->height;
783 /* Check for unchanged attributes */
784 if(winpos.x == wndPtr->rectWindow.left &&
785 winpos.y == wndPtr->rectWindow.top)
786 winpos.flags |= SWP_NOMOVE;
787 if(winpos.cx == wndPtr->rectWindow.right - wndPtr->rectWindow.left &&
788 winpos.cy == wndPtr->rectWindow.bottom - wndPtr->rectWindow.top)
789 winpos.flags |= SWP_NOSIZE;
791 /* Send WM_WINDOWPOSCHANGING */
792 SendMessage32A( hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)&winpos );
794 /* Calculate new position and size */
795 newWindowRect.left = event->x;
796 newWindowRect.right = event->x + event->width;
797 newWindowRect.top = event->y;
798 newWindowRect.bottom = event->y + event->height;
800 WINPOS_SendNCCalcSize( winpos.hwnd, TRUE, &newWindowRect,
801 &wndPtr->rectWindow, &wndPtr->rectClient,
802 &winpos, &newClientRect );
804 hrgnOldPos = CreateRectRgnIndirect32( &wndPtr->rectWindow );
805 hrgnNewPos = CreateRectRgnIndirect32( &newWindowRect );
806 CombineRgn32( hrgnOldPos, hrgnOldPos, hrgnNewPos, RGN_DIFF );
808 /* Set new size and position */
809 wndPtr->rectWindow = newWindowRect;
810 wndPtr->rectClient = newClientRect;
811 SendMessage32A( hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)&winpos );
813 if( IsWindow32( hwnd ) )
814 if( above == None ) /* absolute bottom */
816 WIN_UnlinkWindow( hwnd );
817 WIN_LinkWindow( hwnd, HWND_BOTTOM);
819 else EVENT_QueryZOrder( wndPtr ); /* try to outsmart window manager */
821 DeleteObject32(hrgnOldPos);
822 DeleteObject32(hrgnNewPos);
827 /***********************************************************************
828 * EVENT_SelectionRequest
830 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event )
832 XSelectionEvent result;
833 Atom rprop = None;
834 Window request = event->requestor;
836 if(event->target == XA_STRING)
838 HANDLE16 hText;
839 LPSTR text;
840 int size,i,j;
842 rprop = event->property;
844 if(rprop == None) rprop = event->target;
846 if(event->selection!=XA_PRIMARY) rprop = None;
847 else if(!CLIPBOARD_IsPresent(CF_OEMTEXT)) rprop = None;
848 else
850 /* open to make sure that clipboard is available */
852 BOOL32 couldOpen = OpenClipboard32( pWnd->hwndSelf );
853 char* lpstr = 0;
855 hText = GetClipboardData16(CF_TEXT);
856 text = GlobalLock16(hText);
857 size = GlobalSize16(hText);
859 /* remove carriage returns */
861 lpstr = (char*)xmalloc(size--);
862 for(i=0,j=0; i < size && text[i]; i++ )
864 if( text[i] == '\r' &&
865 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
866 lpstr[j++] = text[i];
868 lpstr[j]='\0';
870 XChangeProperty(display, request, rprop,
871 XA_STRING, 8, PropModeReplace,
872 lpstr, j);
873 free(lpstr);
875 /* close only if we opened before */
877 if(couldOpen) CloseClipboard32();
881 if(rprop == None)
882 dprintf_event(stddeb,"Request for %s ignored\n", XGetAtomName(display,event->target));
884 result.type = SelectionNotify;
885 result.display = display;
886 result.requestor = request;
887 result.selection = event->selection;
888 result.property = rprop;
889 result.target = event->target;
890 result.time = event->time;
891 XSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
895 /***********************************************************************
896 * EVENT_SelectionNotify
898 static void EVENT_SelectionNotify( XSelectionEvent *event )
900 if (event->selection != XA_PRIMARY) return;
902 if (event->target != XA_STRING) CLIPBOARD_ReadSelection( 0, None );
903 else CLIPBOARD_ReadSelection( event->requestor, event->property );
905 dprintf_clipboard(stddeb,"\tSelectionNotify done!\n");
909 /***********************************************************************
910 * EVENT_SelectionClear
912 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event )
914 if (event->selection != XA_PRIMARY) return;
915 CLIPBOARD_ReleaseSelection( event->window, pWnd->hwndSelf );
919 /**********************************************************************
920 * EVENT_ClientMessage
922 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event )
924 if (event->message_type != None && event->format == 32)
926 if ((event->message_type == wmProtocols) &&
927 (((Atom) event->data.l[0]) == wmDeleteWindow))
928 SendMessage16( pWnd->hwndSelf, WM_SYSCOMMAND, SC_CLOSE, 0 );
929 else if ( event->message_type == dndProtocol &&
930 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
932 unsigned long data_length;
933 unsigned long aux_long;
934 unsigned char* p_data = NULL;
935 union {
936 Atom atom_aux;
937 POINT32 pt_aux;
938 int i;
939 } u;
940 int x, y;
941 BOOL16 bAccept;
942 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
943 LPDRAGINFO lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
944 SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
945 Window w_aux_root, w_aux_child;
946 WND* pDropWnd;
948 if( !lpDragInfo || !spDragInfo ) return;
950 XQueryPointer( display, pWnd->window, &w_aux_root, &w_aux_child,
951 &x, &y, &u.pt_aux.x, &u.pt_aux.y, (unsigned int*)&aux_long);
953 lpDragInfo->hScope = pWnd->hwndSelf;
954 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
956 /* find out drop point and drop window */
957 if( x < 0 || y < 0 ||
958 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
959 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
960 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
961 else
963 bAccept = DRAG_QueryUpdate( pWnd->hwndSelf, spDragInfo, TRUE );
964 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
966 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
967 GlobalFree16( hDragInfo );
969 if( bAccept )
971 XGetWindowProperty( display, DefaultRootWindow(display),
972 dndSelection, 0, 65535, FALSE,
973 AnyPropertyType, &u.atom_aux, &u.pt_aux.y,
974 &data_length, &aux_long, &p_data);
976 if( !aux_long && p_data) /* don't bother if > 64K */
978 char *p = (char*) p_data;
979 char *p_drop;
981 aux_long = 0;
982 while( *p ) /* calculate buffer size */
984 p_drop = p;
985 if((u.i = *p) != -1 )
986 u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
987 if( u.i == -1 ) *p = -1; /* mark as "bad" */
988 else
990 INT32 len = GetShortPathName32A( p, NULL, 0 );
991 if (len) aux_long += len + 1;
992 else *p = -1;
994 p += strlen(p) + 1;
996 if( aux_long && aux_long < 65535 )
998 HDROP16 hDrop;
999 LPDROPFILESTRUCT lpDrop;
1001 aux_long += sizeof(DROPFILESTRUCT) + 1;
1002 hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
1003 lpDrop = (LPDROPFILESTRUCT) GlobalLock16( hDrop );
1005 if( lpDrop )
1007 lpDrop->wSize = sizeof(DROPFILESTRUCT);
1008 lpDrop->ptMousePos.x = (INT16)x;
1009 lpDrop->ptMousePos.y = (INT16)y;
1010 lpDrop->fInNonClientArea = (BOOL16)
1011 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1012 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1013 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1014 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1015 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT);
1016 p = p_data;
1017 while(*p)
1019 if( *p != -1 ) /* use only "good" entries */
1021 GetShortPathName32A( p, p_drop, 65535 );
1022 p_drop += strlen( p_drop ) + 1;
1024 p += strlen(p) + 1;
1026 *p_drop = '\0';
1027 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1028 (WPARAM16)hDrop, 0L );
1032 if( p_data ) XFree(p_data);
1034 } /* WS_EX_ACCEPTFILES */
1035 } /* dndProtocol */
1036 else
1037 dprintf_event( stddeb, "unrecognized ClientMessage\n" );
1041 /**********************************************************************
1042 * EVENT_EnterNotify
1044 * Install colormap when Wine window is focused in
1045 * self-managed mode with private colormap
1048 void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
1050 if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
1051 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
1052 XInstallColormap( display, COLOR_GetColormap() );
1056 /**********************************************************************
1057 * EVENT_MapNotify
1059 void EVENT_MapNotify( HWND32 hWnd, XMapEvent *event )
1061 HWND32 hwndFocus = GetFocus32();
1063 if (hwndFocus && IsChild32( hWnd, hwndFocus ))
1064 FOCUS_SetXFocus( (HWND32)hwndFocus );
1066 return;
1069 /**********************************************************************
1070 * EVENT_Capture
1072 * We need this to be able to generate double click messages
1073 * when menu code captures mouse in the window without CS_DBLCLK style.
1075 HWND32 EVENT_Capture(HWND32 hwnd, INT16 ht)
1077 Window win;
1078 HWND32 capturePrev = captureWnd;
1080 if (!hwnd)
1082 XUngrabPointer(display, CurrentTime );
1083 captureWnd = NULL; captureHT = 0;
1085 else if ((win = WIN_GetXWindow( hwnd )))
1087 WND* wndPtr = WIN_FindWndPtr( hwnd );
1089 if ( wndPtr &&
1090 (XGrabPointer(display, win, False,
1091 ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
1092 GrabModeAsync, GrabModeAsync,
1093 None, None, CurrentTime ) == GrabSuccess) )
1095 dprintf_win(stddeb, "SetCapture(0x%04x)\n", hwnd );
1096 captureWnd = hwnd;
1097 captureHT = ht;
1101 if( capturePrev && capturePrev != captureWnd )
1103 WND* wndPtr = WIN_FindWndPtr( capturePrev );
1104 if( wndPtr && (wndPtr->flags & WIN_ISWIN32) )
1105 SendMessage32A( capturePrev, WM_CAPTURECHANGED, 0L, hwnd);
1107 return capturePrev;
1110 /**********************************************************************
1111 * EVENT_GetCaptureInfo
1113 INT16 EVENT_GetCaptureInfo()
1115 return captureHT;
1118 /**********************************************************************
1119 * SetCapture16 (USER.18)
1121 HWND16 WINAPI SetCapture16( HWND16 hwnd )
1123 return (HWND16)EVENT_Capture( hwnd, HTCLIENT );
1127 /**********************************************************************
1128 * SetCapture32 (USER32.463)
1130 HWND32 WINAPI SetCapture32( HWND32 hwnd )
1132 return EVENT_Capture( hwnd, HTCLIENT );
1136 /**********************************************************************
1137 * ReleaseCapture (USER.19) (USER32.438)
1139 void WINAPI ReleaseCapture(void)
1141 dprintf_win(stddeb, "ReleaseCapture() [%04x]\n", captureWnd );
1142 if( captureWnd ) EVENT_Capture( 0, 0 );
1146 /**********************************************************************
1147 * GetCapture16 (USER.236)
1149 HWND16 WINAPI GetCapture16(void)
1151 return captureWnd;
1155 /**********************************************************************
1156 * GetCapture32 (USER32.207)
1158 HWND32 WINAPI GetCapture32(void)
1160 return captureWnd;
1164 /***********************************************************************
1165 * GetMouseEventProc (USER.337)
1167 FARPROC16 WINAPI GetMouseEventProc(void)
1169 HMODULE16 hmodule = GetModuleHandle16("USER");
1170 return MODULE_GetEntryPoint( hmodule,
1171 MODULE_GetOrdinal( hmodule, "Mouse_Event" ) );
1175 /***********************************************************************
1176 * Mouse_Event (USER.299)
1178 void WINAPI Mouse_Event( CONTEXT *context )
1180 /* Register values:
1181 * AX = mouse event
1182 * BX = horizontal displacement if AX & ME_MOVE
1183 * CX = vertical displacement if AX & ME_MOVE
1184 * DX = button state (?)
1185 * SI = mouse event flags (?)
1187 Window root, child;
1188 int rootX, rootY, childX, childY;
1189 unsigned int state;
1191 if (AX_reg(context) & ME_MOVE)
1193 /* We have to actually move the cursor */
1194 XWarpPointer( display, rootWindow, None, 0, 0, 0, 0,
1195 (short)BX_reg(context), (short)CX_reg(context) );
1196 return;
1198 if (!XQueryPointer( display, rootWindow, &root, &child,
1199 &rootX, &rootY, &childX, &childY, &state )) return;
1200 if (AX_reg(context) & ME_LDOWN)
1201 hardware_event( WM_LBUTTONDOWN, EVENT_XStateToKeyState( state ), 0L,
1202 rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
1203 if (AX_reg(context) & ME_LUP)
1204 hardware_event( WM_LBUTTONUP, EVENT_XStateToKeyState( state ), 0L,
1205 rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
1206 if (AX_reg(context) & ME_RDOWN)
1207 hardware_event( WM_RBUTTONDOWN, EVENT_XStateToKeyState( state ), 0L,
1208 rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
1209 if (AX_reg(context) & ME_RUP)
1210 hardware_event( WM_RBUTTONUP, EVENT_XStateToKeyState( state ), 0L,
1211 rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
1215 /**********************************************************************
1216 * EnableHardwareInput (USER.331)
1218 BOOL16 WINAPI EnableHardwareInput(BOOL16 bEnable)
1220 BOOL16 bOldState = InputEnabled;
1221 dprintf_event(stdnimp,"EnableHardwareInput(%d);\n", bEnable);
1222 InputEnabled = bEnable;
1223 return bOldState;
1227 /***********************************************************************
1228 * SwapMouseButton16 (USER.186)
1230 BOOL16 WINAPI SwapMouseButton16( BOOL16 fSwap )
1232 BOOL16 ret = SwappedButtons;
1233 SwappedButtons = fSwap;
1234 return ret;
1238 /***********************************************************************
1239 * SwapMouseButton32 (USER32.536)
1241 BOOL32 WINAPI SwapMouseButton32( BOOL32 fSwap )
1243 BOOL32 ret = SwappedButtons;
1244 SwappedButtons = fSwap;
1245 return ret;