2 * X events handling functions
4 * Copyright 1993 Alexandre Julliard
14 #include <sys/types.h>
16 #include <X11/keysym.h>
18 #include "ts_xresource.h"
20 #include <X11/Xatom.h>
29 #include "clipboard.h"
45 #define NB_BUTTONS 3 /* Windows can handle 3 buttons */
47 #define DndNotDnd -1 /* OffiX drag&drop */
59 #define DndURL 128 /* KDE drag&drop */
62 /* X context to associate a hwnd to an X window */
63 static XContext winContext = 0;
65 static INT16 captureHT = HTCLIENT;
66 static HWND32 captureWnd = 0;
67 static BOOL32 InputEnabled = TRUE;
68 static BOOL32 SwappedButtons = FALSE;
70 static Atom wmProtocols = None;
71 static Atom wmDeleteWindow = None;
72 static Atom dndProtocol = None;
73 static Atom dndSelection = None;
75 /* EVENT_WaitNetEvent() master fd sets */
77 static fd_set __event_io_set[3];
78 static int __event_max_fd = 0;
79 static int __event_x_connection = 0;
81 static const char * const event_names[] =
83 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
84 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
85 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
86 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
87 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
88 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
89 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
90 "ClientMessage", "MappingNotify"
94 static void EVENT_Key( WND *pWnd, XKeyEvent *event );
95 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event );
96 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event );
97 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event );
98 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event );
99 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event );
100 static void EVENT_Expose( WND *pWnd, XExposeEvent *event );
101 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event );
102 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event );
103 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event);
104 static void EVENT_SelectionNotify( XSelectionEvent *event);
105 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event);
106 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event );
107 static void EVENT_MapNotify( HWND32 hwnd, XMapEvent *event );
109 /* Usable only with OLVWM - compile option perhaps?
110 static void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event );
113 static void EVENT_SendMouseEvent( WORD mouseStatus, WORD deltaX, WORD deltaY,
114 WORD buttonCount, DWORD extraInfo );
116 /***********************************************************************
119 * Initialize network IO.
121 BOOL32 EVENT_Init(void)
124 for( i = 0; i < 3; i++ )
125 FD_ZERO( __event_io_set + i );
127 __event_max_fd = __event_x_connection = ConnectionNumber(display);
128 FD_SET( __event_x_connection, &__event_io_set[EVENT_IO_READ] );
133 /***********************************************************************
136 void EVENT_AddIO( int fd, unsigned io_type )
138 FD_SET( fd, &__event_io_set[io_type] );
139 if( __event_max_fd <= fd ) __event_max_fd = fd + 1;
142 void EVENT_DeleteIO( int fd, unsigned io_type )
144 FD_CLR( fd, &__event_io_set[io_type] );
147 /***********************************************************************
150 * Process an X event.
152 void EVENT_ProcessEvent( XEvent *event )
156 if ( TSXFindContext( display, event->xany.window, winContext,
157 (char **)&pWnd ) != 0) {
158 if ( event->type == ClientMessage) {
159 /* query window (drag&drop event contains only drag window) */
161 int root_x, root_y, child_x, child_y;
163 TSXQueryPointer( display, rootWindow, &root, &child,
164 &root_x, &root_y, &child_x, &child_y, &u);
165 if (TSXFindContext( display, child, winContext, (char **)&pWnd ) != 0)
168 return; /* Not for a registered window */
172 TRACE(event, "Got event %s for hwnd %04x\n",
173 event_names[event->type], pWnd->hwndSelf );
179 if (InputEnabled) EVENT_Key( pWnd, (XKeyEvent*)event );
184 EVENT_ButtonPress( pWnd, (XButtonEvent*)event );
189 EVENT_ButtonRelease( pWnd, (XButtonEvent*)event );
193 /* Wine between two fast machines across the overloaded campus
194 ethernet gets very boged down in MotionEvents. The following
195 simply finds the last motion event in the queue and drops
196 the rest. On a good link events are servered before they build
197 up so this doesn't take place. On a slow link this may cause
198 problems if the event order is important. I'm not yet seen
199 of any problems. Jon 7/6/96.
203 while (TSXCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
204 MotionNotify, event));
205 EVENT_MotionNotify( pWnd, (XMotionEvent*)event );
210 EVENT_FocusIn( pWnd, (XFocusChangeEvent*)event );
214 EVENT_FocusOut( pWnd, (XFocusChangeEvent*)event );
218 EVENT_Expose( pWnd, (XExposeEvent *)event );
222 EVENT_GraphicsExpose( pWnd, (XGraphicsExposeEvent *)event );
225 case ConfigureNotify:
226 EVENT_ConfigureNotify( pWnd, (XConfigureEvent*)event );
229 case SelectionRequest:
230 EVENT_SelectionRequest( pWnd, (XSelectionRequestEvent *)event );
233 case SelectionNotify:
234 EVENT_SelectionNotify( (XSelectionEvent *)event );
238 EVENT_SelectionClear( pWnd, (XSelectionClearEvent*) event );
242 EVENT_ClientMessage( pWnd, (XClientMessageEvent *) event );
246 * EVENT_EnterNotify( pWnd, (XCrossingEvent *) event );
252 /* We get all these because of StructureNotifyMask. */
254 case CirculateNotify:
262 EVENT_MapNotify( pWnd->hwndSelf, (XMapEvent *)event );
266 WARN(event, "Unprocessed event %s for hwnd %04x\n",
267 event_names[event->type], pWnd->hwndSelf );
273 /***********************************************************************
274 * EVENT_RegisterWindow
276 * Associate an X window to a HWND.
278 void EVENT_RegisterWindow( WND *pWnd )
280 if (wmProtocols == None)
281 wmProtocols = TSXInternAtom( display, "WM_PROTOCOLS", True );
282 if (wmDeleteWindow == None)
283 wmDeleteWindow = TSXInternAtom( display, "WM_DELETE_WINDOW", True );
284 if( dndProtocol == None )
285 dndProtocol = TSXInternAtom( display, "DndProtocol" , False );
286 if( dndSelection == None )
287 dndSelection = TSXInternAtom( display, "DndSelection" , False );
289 TSXSetWMProtocols( display, pWnd->window, &wmDeleteWindow, 1 );
291 if (!winContext) winContext = TSXUniqueContext();
292 TSXSaveContext( display, pWnd->window, winContext, (char *)pWnd );
295 /***********************************************************************
296 * EVENT_DestroyWindow
298 void EVENT_DestroyWindow( WND *pWnd )
302 TSXDeleteContext( display, pWnd->window, winContext );
303 TSXDestroyWindow( display, pWnd->window );
304 while( TSXCheckWindowEvent(display, pWnd->window, NoEventMask, &xe) );
308 /***********************************************************************
309 * IsUserIdle (USER.333)
311 * Check if we have pending X events.
313 BOOL16 WINAPI IsUserIdle(void)
315 struct timeval timeout = {0, 0};
319 FD_SET(__event_x_connection, &check_set);
320 if( select(__event_x_connection + 1, &check_set, NULL, NULL, &timeout) > 0 )
326 /***********************************************************************
329 * Wait for a network event, optionally sleeping until one arrives.
330 * Return TRUE if an event is pending, FALSE on timeout or error
331 * (for instance lost connection with the server).
333 BOOL32 EVENT_WaitNetEvent( BOOL32 sleep, BOOL32 peek )
336 LONG maxWait = sleep ? TIMER_GetNextExpiration() : 0;
337 int pending = TSXPending(display);
339 /* Wait for an event or a timeout. If maxWait is -1, we have no timeout;
340 * in this case, we fall through directly to the XNextEvent loop.
343 if ((maxWait != -1) && !pending)
346 struct timeval timeout;
349 memcpy( io_set, __event_io_set, sizeof(io_set) );
351 timeout.tv_usec = (maxWait % 1000) * 1000;
352 timeout.tv_sec = maxWait / 1000;
355 sigsetjmp(env_wait_x, 1);
358 if (DDE_GetRemoteMessage()) {
359 while(DDE_GetRemoteMessage())
363 stop_wait_op = STOP_WAIT_X;
364 /* The code up to the next "stop_wait_op = CONT" must be reentrant */
365 num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
366 &io_set[EVENT_IO_WRITE],
367 &io_set[EVENT_IO_EXCEPT], &timeout );
368 if ( num_pending == 0 )
371 TIMER_ExpireTimers();
374 else stop_wait_op = CONT;
375 #else /* CONFIG_IPC */
376 num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
377 &io_set[EVENT_IO_WRITE],
378 &io_set[EVENT_IO_EXCEPT], &timeout );
379 if ( num_pending == 0)
381 /* Timeout or error */
382 TIMER_ExpireTimers();
385 #endif /* CONFIG_IPC */
387 /* Winsock asynchronous services */
389 if( FD_ISSET( __event_x_connection, &io_set[EVENT_IO_READ]) )
393 WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
395 else /* no X events */
396 return WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
399 { /* Wait for X11 input. */
403 FD_SET(__event_x_connection, &set);
404 select(__event_x_connection + 1, &set, 0, 0, 0 );
407 /* Process current X event (and possibly others that occurred in the meantime) */
409 EnterCriticalSection(&X11DRV_CritSection);
410 while (XPending( display ))
414 if (DDE_GetRemoteMessage())
416 LeaveCriticalSection(&X11DRV_CritSection);
417 while(DDE_GetRemoteMessage()) ;
420 #endif /* CONFIG_IPC */
422 XNextEvent( display, &event );
424 LeaveCriticalSection(&X11DRV_CritSection);
431 /* Check only for those events which can be processed
434 if( event.type == MotionNotify ||
435 event.type == ButtonPress || event.type == ButtonRelease ||
436 event.type == KeyPress || event.type == KeyRelease ||
437 event.type == SelectionRequest || event.type == SelectionClear ||
438 event.type == ClientMessage )
440 EVENT_ProcessEvent( &event );
444 if (TSXFindContext( display, ((XAnyEvent *)&event)->window, winContext,
445 (char **)&pWnd ) || (event.type == NoExpose))
450 if( (pQ = (MESSAGEQUEUE*)GlobalLock16(pWnd->hmemTaskQ)) )
452 pQ->flags |= QUEUE_FLAG_XEVENT;
453 PostEvent(pQ->hTask);
454 TSXPutBackEvent(display, &event);
459 else EVENT_ProcessEvent( &event );
460 EnterCriticalSection(&X11DRV_CritSection);
462 LeaveCriticalSection(&X11DRV_CritSection);
467 /***********************************************************************
470 * Synchronize with the X server. Should not be used too often.
472 void EVENT_Synchronize()
476 /* Use of the X critical section is needed or we have a small
477 * race between XPending() and XNextEvent().
479 EnterCriticalSection( &X11DRV_CritSection );
480 XSync( display, False );
481 while (XPending( display ))
483 XNextEvent( display, &event );
484 /* unlock X critsection for EVENT_ProcessEvent() might switch tasks */
485 LeaveCriticalSection( &X11DRV_CritSection );
486 EVENT_ProcessEvent( &event );
487 EnterCriticalSection( &X11DRV_CritSection );
489 LeaveCriticalSection( &X11DRV_CritSection );
492 /***********************************************************************
495 * Try to synchronize internal z-order with the window manager's.
496 * Probably a futile endeavor.
498 static BOOL32 __check_query_condition( WND** pWndA, WND** pWndB )
500 /* return TRUE if we have at least two managed windows */
502 for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
503 if( (*pWndA)->flags & WIN_MANAGED &&
504 (*pWndA)->dwStyle & WS_VISIBLE ) break;
506 for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
507 if( (*pWndB)->flags & WIN_MANAGED &&
508 (*pWndB)->dwStyle & WS_VISIBLE ) break;
509 return ((*pWndB) != NULL);
512 static Window __get_common_ancestor( Window A, Window B,
513 Window** children, unsigned* total )
515 /* find the real root window */
517 Window root, *childrenB;
522 if( *children ) TSXFree( *children );
523 TSXQueryTree( display, A, &root, &A, children, total );
524 TSXQueryTree( display, B, &root, &B, &childrenB, &totalB );
525 if( childrenB ) TSXFree( childrenB );
526 } while( A != B && A && B );
527 return ( A && B ) ? A : 0 ;
530 static Window __get_top_decoration( Window w, Window ancestor )
532 Window* children, root, prev = w, parent = w;
538 TSXQueryTree( display, w, &root, &parent, &children, &total );
539 if( children ) TSXFree( children );
540 } while( parent && parent != ancestor );
541 TRACE(event, "\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
542 return ( parent ) ? w : 0 ;
545 static unsigned __td_lookup( Window w, Window* list, unsigned max )
548 for( i = 0; i < max; i++ ) if( list[i] == w ) break;
552 static BOOL32 EVENT_QueryZOrder( WND* pWndCheck )
555 HWND32 hwndInsertAfter = HWND_TOP;
556 WND* pWnd, *pWndZ = WIN_GetDesktop()->child;
557 Window w, parent, *children = NULL;
558 unsigned total, check, pos, best;
560 if( !__check_query_condition(&pWndZ, &pWnd) ) return TRUE;
562 parent = __get_common_ancestor( pWndZ->window, pWnd->window,
564 if( parent && children )
566 w = __get_top_decoration( pWndCheck->window, parent );
567 if( w != children[total - 1] )
569 check = __td_lookup( w, children, total );
571 for( pWnd = pWndZ; pWnd; pWnd = pWnd->next )
573 if( pWnd != pWndCheck )
575 if( !(pWnd->flags & WIN_MANAGED) ||
576 !(w = __get_top_decoration( pWnd->window, parent )) )
578 pos = __td_lookup( w, children, total );
579 if( pos < best && pos > check )
582 hwndInsertAfter = pWnd->hwndSelf;
584 if( check - best == 1 ) break;
587 WIN_UnlinkWindow( pWndCheck->hwndSelf );
588 WIN_LinkWindow( pWndCheck->hwndSelf, hwndInsertAfter);
591 if( children ) TSXFree( children );
596 /***********************************************************************
597 * EVENT_XStateToKeyState
599 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
600 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
602 static WORD EVENT_XStateToKeyState( int state )
606 if (state & Button1Mask) kstate |= MK_LBUTTON;
607 if (state & Button2Mask) kstate |= MK_MBUTTON;
608 if (state & Button3Mask) kstate |= MK_RBUTTON;
609 if (state & ShiftMask) kstate |= MK_SHIFT;
610 if (state & ControlMask) kstate |= MK_CONTROL;
615 /***********************************************************************
618 static void EVENT_Expose( WND *pWnd, XExposeEvent *event )
622 /* Make position relative to client area instead of window */
623 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
624 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
625 rect.right = rect.left + event->width;
626 rect.bottom = rect.top + event->height;
628 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
629 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
630 (event->count ? 0 : RDW_ERASENOW), 0 );
634 /***********************************************************************
635 * EVENT_GraphicsExpose
637 * This is needed when scrolling area is partially obscured
638 * by non-Wine X window.
640 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event )
644 /* Make position relative to client area instead of window */
645 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
646 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
647 rect.right = rect.left + event->width;
648 rect.bottom = rect.top + event->height;
650 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
651 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
652 (event->count ? 0 : RDW_ERASENOW), 0 );
656 /***********************************************************************
659 * Handle a X key event
661 static void EVENT_Key( WND *pWnd, XKeyEvent *event )
663 KEYBOARD_HandleEvent( pWnd, event );
667 /***********************************************************************
670 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event )
672 hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ), 0L,
673 pWnd->rectWindow.left + event->x,
674 pWnd->rectWindow.top + event->y,
675 event->time - MSG_WineStartTicks, pWnd->hwndSelf );
677 EVENT_SendMouseEvent( ME_MOVE,
678 pWnd->rectWindow.left + event->x,
679 pWnd->rectWindow.top + event->y,
684 /***********************************************************************
685 * EVENT_DummyMotionNotify
687 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
689 void EVENT_DummyMotionNotify(void)
692 int rootX, rootY, winX, winY;
695 if (TSXQueryPointer( display, rootWindow, &root, &child,
696 &rootX, &rootY, &winX, &winY, &state ))
698 hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( state ), 0L,
699 winX, winY, GetTickCount(), 0 );
704 /***********************************************************************
707 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event )
709 static WORD messages[NB_BUTTONS] =
710 { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
711 static WORD statusCodes[NB_BUTTONS] =
712 { ME_LDOWN, 0, ME_RDOWN };
713 int buttonNum = event->button - 1;
715 if (buttonNum >= NB_BUTTONS) return;
716 if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
717 MouseButtonsStates[buttonNum] = TRUE;
718 AsyncMouseButtonsStates[buttonNum] = TRUE;
719 hardware_event( messages[buttonNum],
720 EVENT_XStateToKeyState( event->state ), 0L,
721 pWnd->rectWindow.left + event->x,
722 pWnd->rectWindow.top + event->y,
723 event->time - MSG_WineStartTicks, pWnd->hwndSelf );
725 EVENT_SendMouseEvent( statusCodes[buttonNum],
726 pWnd->rectWindow.left + event->x,
727 pWnd->rectWindow.top + event->y,
732 /***********************************************************************
733 * EVENT_ButtonRelease
735 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event )
737 static const WORD messages[NB_BUTTONS] =
738 { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
739 static WORD statusCodes[NB_BUTTONS] =
740 { ME_LUP, 0, ME_RUP };
741 int buttonNum = event->button - 1;
743 if (buttonNum >= NB_BUTTONS) return;
744 if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
745 MouseButtonsStates[buttonNum] = FALSE;
746 hardware_event( messages[buttonNum],
747 EVENT_XStateToKeyState( event->state ), 0L,
748 pWnd->rectWindow.left + event->x,
749 pWnd->rectWindow.top + event->y,
750 event->time - MSG_WineStartTicks, pWnd->hwndSelf );
752 EVENT_SendMouseEvent( statusCodes[buttonNum],
753 pWnd->rectWindow.left + event->x,
754 pWnd->rectWindow.top + event->y,
759 /**********************************************************************
762 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event )
764 if (Options.managed) EVENT_QueryZOrder( pWnd );
766 if (event->detail != NotifyPointer)
768 HWND32 hwnd = pWnd->hwndSelf;
770 if (hwnd != GetActiveWindow32())
772 WINPOS_ChangeActiveWindow( hwnd, FALSE );
773 KEYBOARD_UpdateState();
775 if ((hwnd != GetFocus32()) && !IsChild32( hwnd, GetFocus32()))
781 /**********************************************************************
784 * Note: only top-level override-redirect windows get FocusOut events.
786 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event )
788 if (event->detail != NotifyPointer)
790 HWND32 hwnd = pWnd->hwndSelf;
792 if (hwnd == GetActiveWindow32())
793 WINPOS_ChangeActiveWindow( 0, FALSE );
794 if ((hwnd == GetFocus32()) || IsChild32( hwnd, GetFocus32()))
799 /**********************************************************************
802 BOOL32 EVENT_CheckFocus(void)
808 TSXGetInputFocus(display, &xW, &state);
810 TSXFindContext(display, xW, winContext, (char **)&pWnd) )
816 /**********************************************************************
819 * Helper function for ConfigureNotify handling.
820 * Get the new geometry of a window relative to the root window.
822 static void EVENT_GetGeometry( Window win, int *px, int *py,
823 unsigned int *pwidth, unsigned int *pheight )
825 Window root, parent, *children;
827 unsigned int width, height, border, depth, nb_children;
829 if (!TSXGetGeometry( display, win, &root, px, py, pwidth, pheight,
830 &border, &depth )) return;
831 if (win == rootWindow)
839 if (!TSXQueryTree(display, win, &root, &parent, &children, &nb_children))
842 if (parent == rootWindow) break;
844 if (!TSXGetGeometry( display, win, &root, &xpos, &ypos,
845 &width, &height, &border, &depth )) return;
852 /**********************************************************************
853 * EVENT_ConfigureNotify
855 * The ConfigureNotify event is only selected on top-level windows
856 * when the -managed flag is used.
858 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event )
861 RECT32 newWindowRect, newClientRect;
862 HRGN32 hrgnOldPos, hrgnNewPos;
863 Window above = event->above;
865 unsigned int width, height;
867 assert (pWnd->flags & WIN_MANAGED);
869 /* We don't rely on the event geometry info, because it is relative
870 * to parent and not to root, and it may be wrong (XFree sets x,y to 0,0
871 * if the window hasn't moved).
873 EVENT_GetGeometry( event->window, &x, &y, &width, &height );
875 /* Fill WINDOWPOS struct */
876 winpos.flags = SWP_NOACTIVATE | SWP_NOZORDER;
877 winpos.hwnd = pWnd->hwndSelf;
883 /* Check for unchanged attributes */
884 if (winpos.x == pWnd->rectWindow.left && winpos.y == pWnd->rectWindow.top)
885 winpos.flags |= SWP_NOMOVE;
886 if ((winpos.cx == pWnd->rectWindow.right - pWnd->rectWindow.left) &&
887 (winpos.cy == pWnd->rectWindow.bottom - pWnd->rectWindow.top))
888 winpos.flags |= SWP_NOSIZE;
891 RECT32 rect = { 0, 0, pWnd->rectWindow.right - pWnd->rectWindow.left,
892 pWnd->rectWindow.bottom - pWnd->rectWindow.top };
893 DCE_InvalidateDCE( pWnd, &rect );
896 /* Send WM_WINDOWPOSCHANGING */
897 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)&winpos );
899 /* Calculate new position and size */
900 newWindowRect.left = x;
901 newWindowRect.right = x + width;
902 newWindowRect.top = y;
903 newWindowRect.bottom = y + height;
905 WINPOS_SendNCCalcSize( winpos.hwnd, TRUE, &newWindowRect,
906 &pWnd->rectWindow, &pWnd->rectClient,
907 &winpos, &newClientRect );
909 hrgnOldPos = CreateRectRgnIndirect32( &pWnd->rectWindow );
910 hrgnNewPos = CreateRectRgnIndirect32( &newWindowRect );
911 CombineRgn32( hrgnOldPos, hrgnOldPos, hrgnNewPos, RGN_DIFF );
912 DeleteObject32(hrgnOldPos);
913 DeleteObject32(hrgnNewPos);
915 /* Set new size and position */
916 pWnd->rectWindow = newWindowRect;
917 pWnd->rectClient = newClientRect;
918 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)&winpos );
920 if (!IsWindow32( winpos.hwnd )) return;
921 if( above == None ) /* absolute bottom */
923 WIN_UnlinkWindow( winpos.hwnd );
924 WIN_LinkWindow( winpos.hwnd, HWND_BOTTOM);
926 else EVENT_QueryZOrder( pWnd ); /* try to outsmart window manager */
930 /***********************************************************************
931 * EVENT_SelectionRequest
933 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event )
935 XSelectionEvent result;
937 Window request = event->requestor;
939 if(event->target == XA_STRING)
945 rprop = event->property;
947 if(rprop == None) rprop = event->target;
949 if(event->selection!=XA_PRIMARY) rprop = None;
950 else if(!CLIPBOARD_IsPresent(CF_OEMTEXT)) rprop = None;
953 /* open to make sure that clipboard is available */
955 BOOL32 couldOpen = OpenClipboard32( pWnd->hwndSelf );
958 hText = GetClipboardData16(CF_TEXT);
959 text = GlobalLock16(hText);
960 size = GlobalSize16(hText);
962 /* remove carriage returns */
964 lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
965 for(i=0,j=0; i < size && text[i]; i++ )
967 if( text[i] == '\r' &&
968 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
969 lpstr[j++] = text[i];
973 TSXChangeProperty(display, request, rprop,
974 XA_STRING, 8, PropModeReplace,
976 HeapFree( GetProcessHeap(), 0, lpstr );
978 /* close only if we opened before */
980 if(couldOpen) CloseClipboard32();
985 TRACE(event,"Request for %s ignored\n", TSXGetAtomName(display,event->target));
987 result.type = SelectionNotify;
988 result.display = display;
989 result.requestor = request;
990 result.selection = event->selection;
991 result.property = rprop;
992 result.target = event->target;
993 result.time = event->time;
994 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
998 /***********************************************************************
999 * EVENT_SelectionNotify
1001 static void EVENT_SelectionNotify( XSelectionEvent *event )
1003 if (event->selection != XA_PRIMARY) return;
1005 if (event->target != XA_STRING) CLIPBOARD_ReadSelection( 0, None );
1006 else CLIPBOARD_ReadSelection( event->requestor, event->property );
1008 TRACE(clipboard,"\tSelectionNotify done!\n");
1012 /***********************************************************************
1013 * EVENT_SelectionClear
1015 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event )
1017 if (event->selection != XA_PRIMARY) return;
1018 CLIPBOARD_ReleaseSelection( event->window, pWnd->hwndSelf );
1022 /**********************************************************************
1023 * EVENT_DropFromOffix
1025 * don't know if it still works (last Changlog is from 96/11/04)
1027 static void EVENT_DropFromOffiX( WND *pWnd, XClientMessageEvent *event )
1029 unsigned long data_length;
1030 unsigned long aux_long;
1031 unsigned char* p_data = NULL;
1039 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
1040 LPDRAGINFO lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
1041 SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
1042 Window w_aux_root, w_aux_child;
1045 if( !lpDragInfo || !spDragInfo ) return;
1047 TSXQueryPointer( display, pWnd->window, &w_aux_root, &w_aux_child,
1048 &x, &y, &u.pt_aux.x, &u.pt_aux.y, (unsigned int*)&aux_long);
1050 lpDragInfo->hScope = pWnd->hwndSelf;
1051 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1053 /* find out drop point and drop window */
1054 if( x < 0 || y < 0 ||
1055 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1056 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1057 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1060 bAccept = DRAG_QueryUpdate( pWnd->hwndSelf, spDragInfo, TRUE );
1061 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1063 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1064 GlobalFree16( hDragInfo );
1068 TSXGetWindowProperty( display, DefaultRootWindow(display),
1069 dndSelection, 0, 65535, FALSE,
1070 AnyPropertyType, &u.atom_aux, &u.pt_aux.y,
1071 &data_length, &aux_long, &p_data);
1073 if( !aux_long && p_data) /* don't bother if > 64K */
1075 char *p = (char*) p_data;
1079 while( *p ) /* calculate buffer size */
1082 if((u.i = *p) != -1 )
1083 u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
1084 if( u.i == -1 ) *p = -1; /* mark as "bad" */
1087 INT32 len = GetShortPathName32A( p, NULL, 0 );
1088 if (len) aux_long += len + 1;
1093 if( aux_long && aux_long < 65535 )
1096 LPDROPFILESTRUCT16 lpDrop;
1098 aux_long += sizeof(DROPFILESTRUCT16) + 1;
1099 hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
1100 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop );
1104 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1105 lpDrop->ptMousePos.x = (INT16)x;
1106 lpDrop->ptMousePos.y = (INT16)y;
1107 lpDrop->fInNonClientArea = (BOOL16)
1108 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1109 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1110 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1111 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1112 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1116 if( *p != -1 ) /* use only "good" entries */
1118 GetShortPathName32A( p, p_drop, 65535 );
1119 p_drop += strlen( p_drop ) + 1;
1124 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1125 (WPARAM16)hDrop, 0L );
1129 if( p_data ) TSXFree(p_data);
1131 } /* WS_EX_ACCEPTFILES */
1134 /**********************************************************************
1137 * drop items are separated by \n
1138 * each item is prefixed by its mime type
1140 * event->data.l[3], event->data.l[4] contains drop x,y position
1142 static void EVENT_DropURLs( WND *pWnd, XClientMessageEvent *event )
1145 unsigned long data_length;
1146 unsigned long aux_long, drop_len = 0;
1147 unsigned char *p_data = NULL; /* property data */
1148 char *p_drop = NULL;
1150 int x, y, drop32 = FALSE ;
1162 drop32 = pWnd->flags & WIN_ISWIN32;
1164 if (!(pWnd->dwExStyle & WS_EX_ACCEPTFILES))
1167 TSXGetWindowProperty( display, DefaultRootWindow(display),
1168 dndSelection, 0, 65535, FALSE,
1169 AnyPropertyType, &u.atom_aux, &u.i,
1170 &data_length, &aux_long, &p_data);
1172 WARN(event,"property too large, truncated!\n");
1173 TRACE(event,"urls=%s\n", p_data);
1175 if( !aux_long && p_data) { /* don't bother if > 64K */
1176 /* calculate length */
1178 next = strchr(p, '\n');
1181 if (strncmp(p,"file:",5) == 0 ) {
1182 INT32 len = GetShortPathName32A( p+5, NULL, 0 );
1183 if (len) drop_len += len + 1;
1188 next = strchr(p, '\n');
1194 if( drop_len && drop_len < 65535 ) {
1195 TSXQueryPointer( display, rootWindow, &u.w_aux, &u.w_aux,
1196 &x, &y, &u.i, &u.i, &u.i);
1197 pDropWnd = WIN_FindWndPtr( pWnd->hwndSelf );
1200 LPDROPFILESTRUCT32 lpDrop;
1201 drop_len += sizeof(DROPFILESTRUCT32) + 1;
1202 hDrop.h32 = (HDROP32)GlobalAlloc32( GMEM_SHARE, drop_len );
1203 lpDrop = (LPDROPFILESTRUCT32) GlobalLock32( hDrop.h32 );
1206 lpDrop->lSize = sizeof(DROPFILESTRUCT32);
1207 lpDrop->ptMousePos.x = (INT32)x;
1208 lpDrop->ptMousePos.y = (INT32)y;
1209 lpDrop->fInNonClientArea = (BOOL32)
1210 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1211 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1212 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1213 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1214 lpDrop->fWideChar = FALSE;
1215 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT32);
1218 LPDROPFILESTRUCT16 lpDrop;
1219 drop_len += sizeof(DROPFILESTRUCT16) + 1;
1220 hDrop.h16 = (HDROP16)GlobalAlloc16( GMEM_SHARE, drop_len );
1221 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop.h16 );
1224 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1225 lpDrop->ptMousePos.x = (INT16)x;
1226 lpDrop->ptMousePos.y = (INT16)y;
1227 lpDrop->fInNonClientArea = (BOOL16)
1228 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1229 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1230 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1231 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1232 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1236 /* create message content */
1239 next = strchr(p, '\n');
1242 if (strncmp(p,"file:",5) == 0 ) {
1243 INT32 len = GetShortPathName32A( p+5, p_drop, 65535 );
1245 TRACE(event, "drop file %s as %s\n", p+5, p_drop);
1248 WARN(event, "can't convert file %s to dos name \n", p+5);
1251 WARN(event, "unknown mime type %s\n", p);
1256 next = strchr(p, '\n');
1264 /* can not use PostMessage32A because it is currently based on
1265 * PostMessage16 and WPARAM32 would be truncated to WPARAM16
1267 GlobalUnlock32(hDrop.h32);
1268 SendMessage32A( pWnd->hwndSelf, WM_DROPFILES,
1269 (WPARAM32)hDrop.h32, 0L );
1271 GlobalUnlock16(hDrop.h16);
1272 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1273 (WPARAM16)hDrop.h16, 0L );
1277 if( p_data ) TSXFree(p_data);
1281 /**********************************************************************
1282 * EVENT_ClientMessage
1284 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event )
1286 if (event->message_type != None && event->format == 32) {
1287 if ((event->message_type == wmProtocols) &&
1288 (((Atom) event->data.l[0]) == wmDeleteWindow))
1289 SendMessage16( pWnd->hwndSelf, WM_SYSCOMMAND, SC_CLOSE, 0 );
1290 else if ( event->message_type == dndProtocol &&
1291 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
1292 EVENT_DropFromOffiX(pWnd, event);
1293 else if ( event->message_type == dndProtocol &&
1294 event->data.l[0] == DndURL )
1295 EVENT_DropURLs(pWnd, event);
1298 /* enable this if you want to see the message */
1299 unsigned char* p_data = NULL;
1305 TSXGetWindowProperty( display, DefaultRootWindow(display),
1306 dndSelection, 0, 65535, FALSE,
1307 AnyPropertyType, &u.atom, &u.i,
1308 &u.l, &u.l, &p_data);
1309 TRACE(event, "message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1310 event->message_type, event->data.l[0], event->data.l[1],
1311 event->data.l[2], event->data.l[3], event->data.l[4],
1314 TRACE(event, "unrecognized ClientMessage\n" );
1319 /**********************************************************************
1322 * Install colormap when Wine window is focused in
1323 * self-managed mode with private colormap
1326 void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
1328 if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
1329 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
1330 TSXInstallColormap( display, COLOR_GetColormap() );
1334 /**********************************************************************
1337 void EVENT_MapNotify( HWND32 hWnd, XMapEvent *event )
1339 HWND32 hwndFocus = GetFocus32();
1341 if (hwndFocus && IsChild32( hWnd, hwndFocus ))
1342 FOCUS_SetXFocus( (HWND32)hwndFocus );
1347 /**********************************************************************
1350 * We need this to be able to generate double click messages
1351 * when menu code captures mouse in the window without CS_DBLCLK style.
1353 HWND32 EVENT_Capture(HWND32 hwnd, INT16 ht)
1355 HWND32 capturePrev = captureWnd;
1364 WND* wndPtr = WIN_FindWndPtr( hwnd );
1367 TRACE(win, "(0x%04x)\n", hwnd );
1373 if( capturePrev && capturePrev != captureWnd )
1375 WND* wndPtr = WIN_FindWndPtr( capturePrev );
1376 if( wndPtr && (wndPtr->flags & WIN_ISWIN32) )
1377 SendMessage32A( capturePrev, WM_CAPTURECHANGED, 0L, hwnd);
1382 /**********************************************************************
1383 * EVENT_GetCaptureInfo
1385 INT16 EVENT_GetCaptureInfo()
1390 /**********************************************************************
1391 * SetCapture16 (USER.18)
1393 HWND16 WINAPI SetCapture16( HWND16 hwnd )
1395 return (HWND16)EVENT_Capture( hwnd, HTCLIENT );
1399 /**********************************************************************
1400 * SetCapture32 (USER32.464)
1402 HWND32 WINAPI SetCapture32( HWND32 hwnd )
1404 return EVENT_Capture( hwnd, HTCLIENT );
1408 /**********************************************************************
1409 * ReleaseCapture (USER.19) (USER32.439)
1411 void WINAPI ReleaseCapture(void)
1413 TRACE(win, "captureWnd=%04x\n", captureWnd );
1414 if( captureWnd ) EVENT_Capture( 0, 0 );
1418 /**********************************************************************
1419 * GetCapture16 (USER.236)
1421 HWND16 WINAPI GetCapture16(void)
1427 /**********************************************************************
1428 * GetCapture32 (USER32.208)
1430 HWND32 WINAPI GetCapture32(void)
1437 /***********************************************************************
1438 * Mouse driver routines:
1442 typedef struct _MOUSEINFO
1452 WORD msMouseCommPort;
1456 static SEGPTR MouseEventProc = 0;
1458 /***********************************************************************
1459 * MouseInquire (MOUSE.1)
1462 WORD WINAPI MouseInquire(MOUSEINFO *mouseInfo)
1464 mouseInfo->msExist = TRUE;
1465 mouseInfo->msRelative = FALSE;
1466 mouseInfo->msNumButtons = 2;
1467 mouseInfo->msRate = 34; /* the DDK says so ... */
1468 mouseInfo->msXThreshold = 0;
1469 mouseInfo->msYThreshold = 0;
1470 mouseInfo->msXRes = 0;
1471 mouseInfo->msYRes = 0;
1472 mouseInfo->msMouseCommPort = 0;
1474 return sizeof(MOUSEINFO);
1477 /***********************************************************************
1478 * MouseEnable (MOUSE.2)
1480 VOID WINAPI MouseEnable(SEGPTR eventProc)
1482 MouseEventProc = eventProc;
1485 /***********************************************************************
1486 * MouseDisable (MOUSE.3)
1488 VOID WINAPI MouseDisable(VOID)
1493 /***********************************************************************
1494 * EVENT_SendMouseEvent
1496 static void EVENT_SendMouseEvent( WORD mouseStatus, WORD deltaX, WORD deltaY,
1497 WORD buttonCount, DWORD extraInfo )
1501 if ( !MouseEventProc ) return;
1503 TRACE( keyboard, "(%04X,%d,%d,%d,%ld)\n", mouseStatus, deltaX, deltaY, buttonCount, extraInfo );
1505 mouseStatus |= 0x8000;
1506 deltaX = (((long)deltaX << 16) + screenWidth/2) / screenWidth;
1507 deltaY = (((long)deltaY << 16) + screenHeight/2) / screenHeight;
1509 memset( &context, 0, sizeof(context) );
1510 CS_reg(&context) = SELECTOROF( MouseEventProc );
1511 EIP_reg(&context) = OFFSETOF( MouseEventProc );
1512 EAX_reg(&context) = mouseStatus;
1513 EBX_reg(&context) = deltaX;
1514 ECX_reg(&context) = deltaY;
1515 EDX_reg(&context) = buttonCount;
1516 ESI_reg(&context) = LOWORD( extraInfo );
1517 EDI_reg(&context) = HIWORD( extraInfo );
1519 Callbacks->CallRegisterShortProc( &context, 0 );
1525 /***********************************************************************
1526 * GetMouseEventProc (USER.337)
1528 FARPROC16 WINAPI GetMouseEventProc(void)
1530 HMODULE16 hmodule = GetModuleHandle16("USER");
1531 return NE_GetEntryPoint( hmodule, NE_GetOrdinal( hmodule, "Mouse_Event" ));
1535 /***********************************************************************
1536 * Mouse_Event (USER.299)
1538 void WINAPI Mouse_Event( CONTEXT *context )
1542 * BX = horizontal displacement if AX & ME_MOVE
1543 * CX = vertical displacement if AX & ME_MOVE
1544 * DX = button state (?)
1545 * SI = mouse event flags (?)
1548 int rootX, rootY, winX, winY;
1551 if (AX_reg(context) & ME_MOVE)
1553 /* We have to actually move the cursor */
1554 TSXWarpPointer( display, rootWindow, None, 0, 0, 0, 0,
1555 (short)BX_reg(context), (short)CX_reg(context) );
1558 if (!TSXQueryPointer( display, rootWindow, &root, &child,
1559 &rootX, &rootY, &winX, &winY, &state )) return;
1560 if (AX_reg(context) & ME_LDOWN)
1561 hardware_event( WM_LBUTTONDOWN, EVENT_XStateToKeyState( state ),
1562 0L, winX, winY, GetTickCount(), 0 );
1563 if (AX_reg(context) & ME_LUP)
1564 hardware_event( WM_LBUTTONUP, EVENT_XStateToKeyState( state ),
1565 0L, winX, winY, GetTickCount(), 0 );
1566 if (AX_reg(context) & ME_RDOWN)
1567 hardware_event( WM_RBUTTONDOWN, EVENT_XStateToKeyState( state ),
1568 0L, winX, winY, GetTickCount(), 0 );
1569 if (AX_reg(context) & ME_RUP)
1570 hardware_event( WM_RBUTTONUP, EVENT_XStateToKeyState( state ),
1571 0L, winX, winY, GetTickCount(), 0 );
1575 /**********************************************************************
1576 * EnableHardwareInput (USER.331)
1578 BOOL16 WINAPI EnableHardwareInput(BOOL16 bEnable)
1580 BOOL16 bOldState = InputEnabled;
1581 FIXME(event,"(%d) - stub\n", bEnable);
1582 InputEnabled = bEnable;
1587 /***********************************************************************
1588 * SwapMouseButton16 (USER.186)
1590 BOOL16 WINAPI SwapMouseButton16( BOOL16 fSwap )
1592 BOOL16 ret = SwappedButtons;
1593 SwappedButtons = fSwap;
1598 /***********************************************************************
1599 * SwapMouseButton32 (USER32.537)
1601 BOOL32 WINAPI SwapMouseButton32( BOOL32 fSwap )
1603 BOOL32 ret = SwappedButtons;
1604 SwappedButtons = fSwap;