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"
44 #define NB_BUTTONS 3 /* Windows can handle 3 buttons */
46 #define DndNotDnd -1 /* OffiX drag&drop */
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"
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 /***********************************************************************
112 * Initialize network IO.
114 BOOL32
EVENT_Init(void)
117 for( i
= 0; i
< 3; i
++ )
118 FD_ZERO( __event_io_set
+ i
);
120 __event_max_fd
= __event_x_connection
= ConnectionNumber(display
);
121 FD_SET( __event_x_connection
, &__event_io_set
[EVENT_IO_READ
] );
126 /***********************************************************************
129 void EVENT_AddIO( int fd
, unsigned io_type
)
131 FD_SET( fd
, &__event_io_set
[io_type
] );
132 if( __event_max_fd
<= fd
) __event_max_fd
= fd
+ 1;
135 void EVENT_DeleteIO( int fd
, unsigned io_type
)
137 FD_CLR( fd
, &__event_io_set
[io_type
] );
140 /***********************************************************************
143 * Process an X event.
145 void EVENT_ProcessEvent( XEvent
*event
)
149 if (TSXFindContext( display
, event
->xany
.window
, winContext
,
150 (char **)&pWnd
) != 0)
151 return; /* Not for a registered window */
153 TRACE(event
, "Got event %s for hwnd %04x\n",
154 event_names
[event
->type
], pWnd
->hwndSelf
);
160 if (InputEnabled
) EVENT_Key( pWnd
, (XKeyEvent
*)event
);
165 EVENT_ButtonPress( pWnd
, (XButtonEvent
*)event
);
170 EVENT_ButtonRelease( pWnd
, (XButtonEvent
*)event
);
174 /* Wine between two fast machines across the overloaded campus
175 ethernet gets very boged down in MotionEvents. The following
176 simply finds the last motion event in the queue and drops
177 the rest. On a good link events are servered before they build
178 up so this doesn't take place. On a slow link this may cause
179 problems if the event order is important. I'm not yet seen
180 of any problems. Jon 7/6/96.
184 while (TSXCheckTypedWindowEvent(display
,((XAnyEvent
*)event
)->window
,
185 MotionNotify
, event
));
186 EVENT_MotionNotify( pWnd
, (XMotionEvent
*)event
);
191 EVENT_FocusIn( pWnd
, (XFocusChangeEvent
*)event
);
195 EVENT_FocusOut( pWnd
, (XFocusChangeEvent
*)event
);
199 EVENT_Expose( pWnd
, (XExposeEvent
*)event
);
203 EVENT_GraphicsExpose( pWnd
, (XGraphicsExposeEvent
*)event
);
206 case ConfigureNotify
:
207 EVENT_ConfigureNotify( pWnd
, (XConfigureEvent
*)event
);
210 case SelectionRequest
:
211 EVENT_SelectionRequest( pWnd
, (XSelectionRequestEvent
*)event
);
214 case SelectionNotify
:
215 EVENT_SelectionNotify( (XSelectionEvent
*)event
);
219 EVENT_SelectionClear( pWnd
, (XSelectionClearEvent
*) event
);
223 EVENT_ClientMessage( pWnd
, (XClientMessageEvent
*) event
);
227 * EVENT_EnterNotify( pWnd, (XCrossingEvent *) event );
233 /* We get all these because of StructureNotifyMask. */
235 case CirculateNotify
:
243 EVENT_MapNotify( pWnd
->hwndSelf
, (XMapEvent
*)event
);
247 WARN(event
, "Unprocessed event %s for hwnd %04x\n",
248 event_names
[event
->type
], pWnd
->hwndSelf
);
254 /***********************************************************************
255 * EVENT_RegisterWindow
257 * Associate an X window to a HWND.
259 void EVENT_RegisterWindow( WND
*pWnd
)
261 if (wmProtocols
== None
)
262 wmProtocols
= TSXInternAtom( display
, "WM_PROTOCOLS", True
);
263 if (wmDeleteWindow
== None
)
264 wmDeleteWindow
= TSXInternAtom( display
, "WM_DELETE_WINDOW", True
);
265 if( dndProtocol
== None
)
266 dndProtocol
= TSXInternAtom( display
, "DndProtocol" , False
);
267 if( dndSelection
== None
)
268 dndSelection
= TSXInternAtom( display
, "DndSelection" , False
);
270 TSXSetWMProtocols( display
, pWnd
->window
, &wmDeleteWindow
, 1 );
272 if (!winContext
) winContext
= TSXUniqueContext();
273 TSXSaveContext( display
, pWnd
->window
, winContext
, (char *)pWnd
);
276 /***********************************************************************
277 * EVENT_DestroyWindow
279 void EVENT_DestroyWindow( WND
*pWnd
)
283 TSXDeleteContext( display
, pWnd
->window
, winContext
);
284 TSXDestroyWindow( display
, pWnd
->window
);
285 while( TSXCheckWindowEvent(display
, pWnd
->window
, NoEventMask
, &xe
) );
289 /***********************************************************************
290 * IsUserIdle (USER.333)
292 * Check if we have pending X events.
294 BOOL16 WINAPI
IsUserIdle(void)
296 struct timeval timeout
= {0, 0};
300 FD_SET(__event_x_connection
, &check_set
);
301 if( select(__event_x_connection
+ 1, &check_set
, NULL
, NULL
, &timeout
) > 0 )
307 /***********************************************************************
310 * Wait for a network event, optionally sleeping until one arrives.
311 * Return TRUE if an event is pending, FALSE on timeout or error
312 * (for instance lost connection with the server).
314 BOOL32
EVENT_WaitNetEvent( BOOL32 sleep
, BOOL32 peek
)
317 LONG maxWait
= sleep
? TIMER_GetNextExpiration() : 0;
318 int pending
= TSXPending(display
);
320 /* Wait for an event or a timeout. If maxWait is -1, we have no timeout;
321 * in this case, we fall through directly to the XNextEvent loop.
324 if ((maxWait
!= -1) && !pending
)
327 struct timeval timeout
;
330 memcpy( io_set
, __event_io_set
, sizeof(io_set
) );
332 timeout
.tv_usec
= (maxWait
% 1000) * 1000;
333 timeout
.tv_sec
= maxWait
/ 1000;
336 sigsetjmp(env_wait_x
, 1);
339 if (DDE_GetRemoteMessage()) {
340 while(DDE_GetRemoteMessage())
344 stop_wait_op
= STOP_WAIT_X
;
345 /* The code up to the next "stop_wait_op = CONT" must be reentrant */
346 num_pending
= select( __event_max_fd
, &io_set
[EVENT_IO_READ
],
347 &io_set
[EVENT_IO_WRITE
],
348 &io_set
[EVENT_IO_EXCEPT
], &timeout
);
349 if ( num_pending
== 0 )
352 TIMER_ExpireTimers();
355 else stop_wait_op
= CONT
;
356 #else /* CONFIG_IPC */
357 num_pending
= select( __event_max_fd
, &io_set
[EVENT_IO_READ
],
358 &io_set
[EVENT_IO_WRITE
],
359 &io_set
[EVENT_IO_EXCEPT
], &timeout
);
360 if ( num_pending
== 0)
362 /* Timeout or error */
363 TIMER_ExpireTimers();
366 #endif /* CONFIG_IPC */
368 /* Winsock asynchronous services */
370 if( FD_ISSET( __event_x_connection
, &io_set
[EVENT_IO_READ
]) )
374 WINSOCK_HandleIO( &__event_max_fd
, num_pending
, io_set
, __event_io_set
);
376 else /* no X events */
377 return WINSOCK_HandleIO( &__event_max_fd
, num_pending
, io_set
, __event_io_set
);
380 { /* Wait for X11 input. */
384 FD_SET(__event_x_connection
, &set
);
385 select(__event_x_connection
+ 1, &set
, 0, 0, 0 );
388 /* Process current X event (and possibly others that occurred in the meantime) */
390 EnterCriticalSection(&X11DRV_CritSection
);
391 while (XPending( display
))
395 if (DDE_GetRemoteMessage())
397 LeaveCriticalSection(&X11DRV_CritSection
);
398 while(DDE_GetRemoteMessage()) ;
401 #endif /* CONFIG_IPC */
403 XNextEvent( display
, &event
);
405 LeaveCriticalSection(&X11DRV_CritSection
);
411 if (TSXFindContext( display
, ((XAnyEvent
*)&event
)->window
, winContext
,
412 (char **)&pWnd
) || (event
.type
== NoExpose
))
415 /* Check only for those events which can be processed
418 if( event
.type
== MotionNotify
||
419 event
.type
== ButtonPress
|| event
.type
== ButtonRelease
||
420 event
.type
== KeyPress
|| event
.type
== KeyRelease
||
421 event
.type
== SelectionRequest
|| event
.type
== SelectionClear
)
423 EVENT_ProcessEvent( &event
);
429 if( (pQ
= (MESSAGEQUEUE
*)GlobalLock16(pWnd
->hmemTaskQ
)) )
431 pQ
->flags
|= QUEUE_FLAG_XEVENT
;
432 PostEvent(pQ
->hTask
);
433 TSXPutBackEvent(display
, &event
);
438 else EVENT_ProcessEvent( &event
);
439 EnterCriticalSection(&X11DRV_CritSection
);
441 LeaveCriticalSection(&X11DRV_CritSection
);
446 /***********************************************************************
449 * Synchronize with the X server. Should not be used too often.
451 void EVENT_Synchronize()
455 /* Use of the X critical section is needed or we have a small
456 * race between XPending() and XNextEvent().
458 EnterCriticalSection( &X11DRV_CritSection
);
459 XSync( display
, False
);
460 while (XPending( display
))
462 XNextEvent( display
, &event
);
463 /* unlock X critsection for EVENT_ProcessEvent() might switch tasks */
464 LeaveCriticalSection( &X11DRV_CritSection
);
465 EVENT_ProcessEvent( &event
);
466 EnterCriticalSection( &X11DRV_CritSection
);
468 LeaveCriticalSection( &X11DRV_CritSection
);
471 /***********************************************************************
474 * Try to synchronize internal z-order with the window manager's.
475 * Probably a futile endeavor.
477 static BOOL32
__check_query_condition( WND
** pWndA
, WND
** pWndB
)
479 /* return TRUE if we have at least two managed windows */
481 for( *pWndB
= NULL
; *pWndA
; *pWndA
= (*pWndA
)->next
)
482 if( (*pWndA
)->flags
& WIN_MANAGED
&&
483 (*pWndA
)->dwStyle
& WS_VISIBLE
) break;
485 for( *pWndB
= (*pWndA
)->next
; *pWndB
; *pWndB
= (*pWndB
)->next
)
486 if( (*pWndB
)->flags
& WIN_MANAGED
&&
487 (*pWndB
)->dwStyle
& WS_VISIBLE
) break;
488 return ((*pWndB
) != NULL
);
491 static Window
__get_common_ancestor( Window A
, Window B
,
492 Window
** children
, unsigned* total
)
494 /* find the real root window */
496 Window root
, *childrenB
;
501 if( *children
) TSXFree( *children
);
502 TSXQueryTree( display
, A
, &root
, &A
, children
, total
);
503 TSXQueryTree( display
, B
, &root
, &B
, &childrenB
, &totalB
);
504 if( childrenB
) TSXFree( childrenB
);
505 } while( A
!= B
&& A
&& B
);
506 return ( A
&& B
) ? A
: 0 ;
509 static Window
__get_top_decoration( Window w
, Window ancestor
)
511 Window
* children
, root
, prev
= w
, parent
= w
;
517 TSXQueryTree( display
, w
, &root
, &parent
, &children
, &total
);
518 if( children
) TSXFree( children
);
519 } while( parent
&& parent
!= ancestor
);
520 TRACE(event
, "\t%08x -> %08x\n", (unsigned)prev
, (unsigned)w
);
521 return ( parent
) ? w
: 0 ;
524 static unsigned __td_lookup( Window w
, Window
* list
, unsigned max
)
527 for( i
= 0; i
< max
; i
++ ) if( list
[i
] == w
) break;
531 static BOOL32
EVENT_QueryZOrder( WND
* pWndCheck
)
534 HWND32 hwndInsertAfter
= HWND_TOP
;
535 WND
* pWnd
, *pWndZ
= WIN_GetDesktop()->child
;
536 Window w
, parent
, *children
= NULL
;
537 unsigned total
, check
, pos
, best
;
539 if( !__check_query_condition(&pWndZ
, &pWnd
) ) return TRUE
;
541 parent
= __get_common_ancestor( pWndZ
->window
, pWnd
->window
,
543 if( parent
&& children
)
545 w
= __get_top_decoration( pWndCheck
->window
, parent
);
546 if( w
!= children
[total
- 1] )
548 check
= __td_lookup( w
, children
, total
);
550 for( pWnd
= pWndZ
; pWnd
; pWnd
= pWnd
->next
)
552 if( pWnd
!= pWndCheck
)
554 if( !(pWnd
->flags
& WIN_MANAGED
) ||
555 !(w
= __get_top_decoration( pWnd
->window
, parent
)) )
557 pos
= __td_lookup( w
, children
, total
);
558 if( pos
< best
&& pos
> check
)
561 hwndInsertAfter
= pWnd
->hwndSelf
;
563 if( check
- best
== 1 ) break;
566 WIN_UnlinkWindow( pWndCheck
->hwndSelf
);
567 WIN_LinkWindow( pWndCheck
->hwndSelf
, hwndInsertAfter
);
570 if( children
) TSXFree( children
);
575 /***********************************************************************
576 * EVENT_XStateToKeyState
578 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
579 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
581 static WORD
EVENT_XStateToKeyState( int state
)
585 if (state
& Button1Mask
) kstate
|= MK_LBUTTON
;
586 if (state
& Button2Mask
) kstate
|= MK_MBUTTON
;
587 if (state
& Button3Mask
) kstate
|= MK_RBUTTON
;
588 if (state
& ShiftMask
) kstate
|= MK_SHIFT
;
589 if (state
& ControlMask
) kstate
|= MK_CONTROL
;
594 /***********************************************************************
597 static void EVENT_Expose( WND
*pWnd
, XExposeEvent
*event
)
601 /* Make position relative to client area instead of window */
602 rect
.left
= event
->x
- (pWnd
->rectClient
.left
- pWnd
->rectWindow
.left
);
603 rect
.top
= event
->y
- (pWnd
->rectClient
.top
- pWnd
->rectWindow
.top
);
604 rect
.right
= rect
.left
+ event
->width
;
605 rect
.bottom
= rect
.top
+ event
->height
;
607 PAINT_RedrawWindow( pWnd
->hwndSelf
, &rect
, 0,
608 RDW_INVALIDATE
| RDW_FRAME
| RDW_ALLCHILDREN
| RDW_ERASE
|
609 (event
->count
? 0 : RDW_ERASENOW
), 0 );
613 /***********************************************************************
614 * EVENT_GraphicsExpose
616 * This is needed when scrolling area is partially obscured
617 * by non-Wine X window.
619 static void EVENT_GraphicsExpose( WND
*pWnd
, XGraphicsExposeEvent
*event
)
623 /* Make position relative to client area instead of window */
624 rect
.left
= event
->x
- (pWnd
->rectClient
.left
- pWnd
->rectWindow
.left
);
625 rect
.top
= event
->y
- (pWnd
->rectClient
.top
- pWnd
->rectWindow
.top
);
626 rect
.right
= rect
.left
+ event
->width
;
627 rect
.bottom
= rect
.top
+ event
->height
;
629 PAINT_RedrawWindow( pWnd
->hwndSelf
, &rect
, 0,
630 RDW_INVALIDATE
| RDW_ALLCHILDREN
| RDW_ERASE
|
631 (event
->count
? 0 : RDW_ERASENOW
), 0 );
635 /***********************************************************************
638 * Handle a X key event
640 static void EVENT_Key( WND
*pWnd
, XKeyEvent
*event
)
642 KEYBOARD_HandleEvent( pWnd
, event
);
646 /***********************************************************************
649 static void EVENT_MotionNotify( WND
*pWnd
, XMotionEvent
*event
)
651 hardware_event( WM_MOUSEMOVE
, EVENT_XStateToKeyState( event
->state
), 0L,
652 pWnd
->rectWindow
.left
+ event
->x
,
653 pWnd
->rectWindow
.top
+ event
->y
,
654 event
->time
- MSG_WineStartTicks
, pWnd
->hwndSelf
);
658 /***********************************************************************
659 * EVENT_DummyMotionNotify
661 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
663 void EVENT_DummyMotionNotify(void)
666 int rootX
, rootY
, winX
, winY
;
669 if (TSXQueryPointer( display
, rootWindow
, &root
, &child
,
670 &rootX
, &rootY
, &winX
, &winY
, &state
))
672 hardware_event( WM_MOUSEMOVE
, EVENT_XStateToKeyState( state
), 0L,
673 winX
, winY
, GetTickCount(), 0 );
678 /***********************************************************************
681 static void EVENT_ButtonPress( WND
*pWnd
, XButtonEvent
*event
)
683 static WORD messages
[NB_BUTTONS
] =
684 { WM_LBUTTONDOWN
, WM_MBUTTONDOWN
, WM_RBUTTONDOWN
};
685 int buttonNum
= event
->button
- 1;
687 if (buttonNum
>= NB_BUTTONS
) return;
688 if (SwappedButtons
) buttonNum
= NB_BUTTONS
- 1 - buttonNum
;
689 MouseButtonsStates
[buttonNum
] = TRUE
;
690 AsyncMouseButtonsStates
[buttonNum
] = TRUE
;
691 hardware_event( messages
[buttonNum
],
692 EVENT_XStateToKeyState( event
->state
), 0L,
693 pWnd
->rectWindow
.left
+ event
->x
,
694 pWnd
->rectWindow
.top
+ event
->y
,
695 event
->time
- MSG_WineStartTicks
, pWnd
->hwndSelf
);
699 /***********************************************************************
700 * EVENT_ButtonRelease
702 static void EVENT_ButtonRelease( WND
*pWnd
, XButtonEvent
*event
)
704 static const WORD messages
[NB_BUTTONS
] =
705 { WM_LBUTTONUP
, WM_MBUTTONUP
, WM_RBUTTONUP
};
706 int buttonNum
= event
->button
- 1;
708 if (buttonNum
>= NB_BUTTONS
) return;
709 if (SwappedButtons
) buttonNum
= NB_BUTTONS
- 1 - buttonNum
;
710 MouseButtonsStates
[buttonNum
] = FALSE
;
711 hardware_event( messages
[buttonNum
],
712 EVENT_XStateToKeyState( event
->state
), 0L,
713 pWnd
->rectWindow
.left
+ event
->x
,
714 pWnd
->rectWindow
.top
+ event
->y
,
715 event
->time
- MSG_WineStartTicks
, pWnd
->hwndSelf
);
719 /**********************************************************************
722 static void EVENT_FocusIn( WND
*pWnd
, XFocusChangeEvent
*event
)
724 if (Options
.managed
) EVENT_QueryZOrder( pWnd
);
726 if (event
->detail
!= NotifyPointer
)
728 HWND32 hwnd
= pWnd
->hwndSelf
;
730 if (hwnd
!= GetActiveWindow32())
731 WINPOS_ChangeActiveWindow( hwnd
, FALSE
);
732 if ((hwnd
!= GetFocus32()) && !IsChild32( hwnd
, GetFocus32()))
738 /**********************************************************************
741 * Note: only top-level override-redirect windows get FocusOut events.
743 static void EVENT_FocusOut( WND
*pWnd
, XFocusChangeEvent
*event
)
745 if (event
->detail
!= NotifyPointer
)
747 HWND32 hwnd
= pWnd
->hwndSelf
;
749 if (hwnd
== GetActiveWindow32())
750 WINPOS_ChangeActiveWindow( 0, FALSE
);
751 if ((hwnd
== GetFocus32()) || IsChild32( hwnd
, GetFocus32()))
756 /**********************************************************************
759 BOOL32
EVENT_CheckFocus(void)
765 TSXGetInputFocus(display
, &xW
, &state
);
767 TSXFindContext(display
, xW
, winContext
, (char **)&pWnd
) )
773 /**********************************************************************
776 * Helper function for ConfigureNotify handling.
777 * Get the new geometry of a window relative to the root window.
779 static void EVENT_GetGeometry( Window win
, int *px
, int *py
,
780 unsigned int *pwidth
, unsigned int *pheight
)
782 Window root
, parent
, *children
;
784 unsigned int width
, height
, border
, depth
, nb_children
;
786 if (!TSXGetGeometry( display
, win
, &root
, px
, py
, pwidth
, pheight
,
787 &border
, &depth
)) return;
788 if (win
== rootWindow
)
796 if (!TSXQueryTree(display
, win
, &root
, &parent
, &children
, &nb_children
))
799 if (parent
== rootWindow
) break;
801 if (!TSXGetGeometry( display
, win
, &root
, &xpos
, &ypos
,
802 &width
, &height
, &border
, &depth
)) return;
809 /**********************************************************************
810 * EVENT_ConfigureNotify
812 * The ConfigureNotify event is only selected on top-level windows
813 * when the -managed flag is used.
815 static void EVENT_ConfigureNotify( WND
*pWnd
, XConfigureEvent
*event
)
818 RECT32 newWindowRect
, newClientRect
;
819 HRGN32 hrgnOldPos
, hrgnNewPos
;
820 Window above
= event
->above
;
822 unsigned int width
, height
;
824 assert (pWnd
->flags
& WIN_MANAGED
);
826 /* We don't rely on the event geometry info, because it is relative
827 * to parent and not to root, and it may be wrong (XFree sets x,y to 0,0
828 * if the window hasn't moved).
830 EVENT_GetGeometry( event
->window
, &x
, &y
, &width
, &height
);
832 /* Fill WINDOWPOS struct */
833 winpos
.flags
= SWP_NOACTIVATE
| SWP_NOZORDER
;
834 winpos
.hwnd
= pWnd
->hwndSelf
;
840 /* Check for unchanged attributes */
841 if (winpos
.x
== pWnd
->rectWindow
.left
&& winpos
.y
== pWnd
->rectWindow
.top
)
842 winpos
.flags
|= SWP_NOMOVE
;
843 if ((winpos
.cx
== pWnd
->rectWindow
.right
- pWnd
->rectWindow
.left
) &&
844 (winpos
.cy
== pWnd
->rectWindow
.bottom
- pWnd
->rectWindow
.top
))
845 winpos
.flags
|= SWP_NOSIZE
;
848 RECT32 rect
= { 0, 0, pWnd
->rectWindow
.right
- pWnd
->rectWindow
.left
,
849 pWnd
->rectWindow
.bottom
- pWnd
->rectWindow
.top
};
850 DCE_InvalidateDCE( pWnd
, &rect
);
853 /* Send WM_WINDOWPOSCHANGING */
854 SendMessage32A( winpos
.hwnd
, WM_WINDOWPOSCHANGING
, 0, (LPARAM
)&winpos
);
856 /* Calculate new position and size */
857 newWindowRect
.left
= x
;
858 newWindowRect
.right
= x
+ width
;
859 newWindowRect
.top
= y
;
860 newWindowRect
.bottom
= y
+ height
;
862 WINPOS_SendNCCalcSize( winpos
.hwnd
, TRUE
, &newWindowRect
,
863 &pWnd
->rectWindow
, &pWnd
->rectClient
,
864 &winpos
, &newClientRect
);
866 hrgnOldPos
= CreateRectRgnIndirect32( &pWnd
->rectWindow
);
867 hrgnNewPos
= CreateRectRgnIndirect32( &newWindowRect
);
868 CombineRgn32( hrgnOldPos
, hrgnOldPos
, hrgnNewPos
, RGN_DIFF
);
869 DeleteObject32(hrgnOldPos
);
870 DeleteObject32(hrgnNewPos
);
872 /* Set new size and position */
873 pWnd
->rectWindow
= newWindowRect
;
874 pWnd
->rectClient
= newClientRect
;
875 SendMessage32A( winpos
.hwnd
, WM_WINDOWPOSCHANGED
, 0, (LPARAM
)&winpos
);
877 if (!IsWindow32( winpos
.hwnd
)) return;
878 if( above
== None
) /* absolute bottom */
880 WIN_UnlinkWindow( winpos
.hwnd
);
881 WIN_LinkWindow( winpos
.hwnd
, HWND_BOTTOM
);
883 else EVENT_QueryZOrder( pWnd
); /* try to outsmart window manager */
887 /***********************************************************************
888 * EVENT_SelectionRequest
890 static void EVENT_SelectionRequest( WND
*pWnd
, XSelectionRequestEvent
*event
)
892 XSelectionEvent result
;
894 Window request
= event
->requestor
;
896 if(event
->target
== XA_STRING
)
902 rprop
= event
->property
;
904 if(rprop
== None
) rprop
= event
->target
;
906 if(event
->selection
!=XA_PRIMARY
) rprop
= None
;
907 else if(!CLIPBOARD_IsPresent(CF_OEMTEXT
)) rprop
= None
;
910 /* open to make sure that clipboard is available */
912 BOOL32 couldOpen
= OpenClipboard32( pWnd
->hwndSelf
);
915 hText
= GetClipboardData16(CF_TEXT
);
916 text
= GlobalLock16(hText
);
917 size
= GlobalSize16(hText
);
919 /* remove carriage returns */
921 lpstr
= (char*)HEAP_xalloc( GetProcessHeap(), 0, size
-- );
922 for(i
=0,j
=0; i
< size
&& text
[i
]; i
++ )
924 if( text
[i
] == '\r' &&
925 (text
[i
+1] == '\n' || text
[i
+1] == '\0') ) continue;
926 lpstr
[j
++] = text
[i
];
930 TSXChangeProperty(display
, request
, rprop
,
931 XA_STRING
, 8, PropModeReplace
,
933 HeapFree( GetProcessHeap(), 0, lpstr
);
935 /* close only if we opened before */
937 if(couldOpen
) CloseClipboard32();
942 TRACE(event
,"Request for %s ignored\n", TSXGetAtomName(display
,event
->target
));
944 result
.type
= SelectionNotify
;
945 result
.display
= display
;
946 result
.requestor
= request
;
947 result
.selection
= event
->selection
;
948 result
.property
= rprop
;
949 result
.target
= event
->target
;
950 result
.time
= event
->time
;
951 TSXSendEvent(display
,event
->requestor
,False
,NoEventMask
,(XEvent
*)&result
);
955 /***********************************************************************
956 * EVENT_SelectionNotify
958 static void EVENT_SelectionNotify( XSelectionEvent
*event
)
960 if (event
->selection
!= XA_PRIMARY
) return;
962 if (event
->target
!= XA_STRING
) CLIPBOARD_ReadSelection( 0, None
);
963 else CLIPBOARD_ReadSelection( event
->requestor
, event
->property
);
965 TRACE(clipboard
,"\tSelectionNotify done!\n");
969 /***********************************************************************
970 * EVENT_SelectionClear
972 static void EVENT_SelectionClear( WND
*pWnd
, XSelectionClearEvent
*event
)
974 if (event
->selection
!= XA_PRIMARY
) return;
975 CLIPBOARD_ReleaseSelection( event
->window
, pWnd
->hwndSelf
);
979 /**********************************************************************
980 * EVENT_ClientMessage
982 static void EVENT_ClientMessage( WND
*pWnd
, XClientMessageEvent
*event
)
984 if (event
->message_type
!= None
&& event
->format
== 32)
986 if ((event
->message_type
== wmProtocols
) &&
987 (((Atom
) event
->data
.l
[0]) == wmDeleteWindow
))
988 SendMessage16( pWnd
->hwndSelf
, WM_SYSCOMMAND
, SC_CLOSE
, 0 );
989 else if ( event
->message_type
== dndProtocol
&&
990 (event
->data
.l
[0] == DndFile
|| event
->data
.l
[0] == DndFiles
) )
992 unsigned long data_length
;
993 unsigned long aux_long
;
994 unsigned char* p_data
= NULL
;
1002 HGLOBAL16 hDragInfo
= GlobalAlloc16( GMEM_SHARE
| GMEM_ZEROINIT
, sizeof(DRAGINFO
));
1003 LPDRAGINFO lpDragInfo
= (LPDRAGINFO
) GlobalLock16(hDragInfo
);
1004 SEGPTR spDragInfo
= (SEGPTR
) WIN16_GlobalLock16(hDragInfo
);
1005 Window w_aux_root
, w_aux_child
;
1008 if( !lpDragInfo
|| !spDragInfo
) return;
1010 TSXQueryPointer( display
, pWnd
->window
, &w_aux_root
, &w_aux_child
,
1011 &x
, &y
, &u
.pt_aux
.x
, &u
.pt_aux
.y
, (unsigned int*)&aux_long
);
1013 lpDragInfo
->hScope
= pWnd
->hwndSelf
;
1014 lpDragInfo
->pt
.x
= (INT16
)x
; lpDragInfo
->pt
.y
= (INT16
)y
;
1016 /* find out drop point and drop window */
1017 if( x
< 0 || y
< 0 ||
1018 x
> (pWnd
->rectWindow
.right
- pWnd
->rectWindow
.left
) ||
1019 y
> (pWnd
->rectWindow
.bottom
- pWnd
->rectWindow
.top
) )
1020 { bAccept
= pWnd
->dwExStyle
& WS_EX_ACCEPTFILES
; x
= y
= 0; }
1023 bAccept
= DRAG_QueryUpdate( pWnd
->hwndSelf
, spDragInfo
, TRUE
);
1024 x
= lpDragInfo
->pt
.x
; y
= lpDragInfo
->pt
.y
;
1026 pDropWnd
= WIN_FindWndPtr( lpDragInfo
->hScope
);
1027 GlobalFree16( hDragInfo
);
1031 TSXGetWindowProperty( display
, DefaultRootWindow(display
),
1032 dndSelection
, 0, 65535, FALSE
,
1033 AnyPropertyType
, &u
.atom_aux
, &u
.pt_aux
.y
,
1034 &data_length
, &aux_long
, &p_data
);
1036 if( !aux_long
&& p_data
) /* don't bother if > 64K */
1038 char *p
= (char*) p_data
;
1042 while( *p
) /* calculate buffer size */
1045 if((u
.i
= *p
) != -1 )
1046 u
.i
= DRIVE_FindDriveRoot( (const char **)&p_drop
);
1047 if( u
.i
== -1 ) *p
= -1; /* mark as "bad" */
1050 INT32 len
= GetShortPathName32A( p
, NULL
, 0 );
1051 if (len
) aux_long
+= len
+ 1;
1056 if( aux_long
&& aux_long
< 65535 )
1059 LPDROPFILESTRUCT lpDrop
;
1061 aux_long
+= sizeof(DROPFILESTRUCT
) + 1;
1062 hDrop
= (HDROP16
)GlobalAlloc16( GMEM_SHARE
, aux_long
);
1063 lpDrop
= (LPDROPFILESTRUCT
) GlobalLock16( hDrop
);
1067 lpDrop
->wSize
= sizeof(DROPFILESTRUCT
);
1068 lpDrop
->ptMousePos
.x
= (INT16
)x
;
1069 lpDrop
->ptMousePos
.y
= (INT16
)y
;
1070 lpDrop
->fInNonClientArea
= (BOOL16
)
1071 ( x
< (pDropWnd
->rectClient
.left
- pDropWnd
->rectWindow
.left
) ||
1072 y
< (pDropWnd
->rectClient
.top
- pDropWnd
->rectWindow
.top
) ||
1073 x
> (pDropWnd
->rectClient
.right
- pDropWnd
->rectWindow
.left
) ||
1074 y
> (pDropWnd
->rectClient
.bottom
- pDropWnd
->rectWindow
.top
) );
1075 p_drop
= ((char*)lpDrop
) + sizeof(DROPFILESTRUCT
);
1079 if( *p
!= -1 ) /* use only "good" entries */
1081 GetShortPathName32A( p
, p_drop
, 65535 );
1082 p_drop
+= strlen( p_drop
) + 1;
1087 PostMessage16( pWnd
->hwndSelf
, WM_DROPFILES
,
1088 (WPARAM16
)hDrop
, 0L );
1092 if( p_data
) TSXFree(p_data
);
1094 } /* WS_EX_ACCEPTFILES */
1097 TRACE(event
, "unrecognized ClientMessage\n" );
1101 /**********************************************************************
1104 * Install colormap when Wine window is focused in
1105 * self-managed mode with private colormap
1108 void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
1110 if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
1111 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
1112 TSXInstallColormap( display, COLOR_GetColormap() );
1116 /**********************************************************************
1119 void EVENT_MapNotify( HWND32 hWnd
, XMapEvent
*event
)
1121 HWND32 hwndFocus
= GetFocus32();
1123 if (hwndFocus
&& IsChild32( hWnd
, hwndFocus
))
1124 FOCUS_SetXFocus( (HWND32
)hwndFocus
);
1129 /**********************************************************************
1132 * We need this to be able to generate double click messages
1133 * when menu code captures mouse in the window without CS_DBLCLK style.
1135 HWND32
EVENT_Capture(HWND32 hwnd
, INT16 ht
)
1138 HWND32 capturePrev
= captureWnd
;
1147 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
1150 TRACE(win
, "(0x%04x)\n", hwnd
);
1156 if( capturePrev
&& capturePrev
!= captureWnd
)
1158 WND
* wndPtr
= WIN_FindWndPtr( capturePrev
);
1159 if( wndPtr
&& (wndPtr
->flags
& WIN_ISWIN32
) )
1160 SendMessage32A( capturePrev
, WM_CAPTURECHANGED
, 0L, hwnd
);
1165 /**********************************************************************
1166 * EVENT_GetCaptureInfo
1168 INT16
EVENT_GetCaptureInfo()
1173 /**********************************************************************
1174 * SetCapture16 (USER.18)
1176 HWND16 WINAPI
SetCapture16( HWND16 hwnd
)
1178 return (HWND16
)EVENT_Capture( hwnd
, HTCLIENT
);
1182 /**********************************************************************
1183 * SetCapture32 (USER32.464)
1185 HWND32 WINAPI
SetCapture32( HWND32 hwnd
)
1187 return EVENT_Capture( hwnd
, HTCLIENT
);
1191 /**********************************************************************
1192 * ReleaseCapture (USER.19) (USER32.439)
1194 void WINAPI
ReleaseCapture(void)
1196 TRACE(win
, "captureWnd=%04x\n", captureWnd
);
1197 if( captureWnd
) EVENT_Capture( 0, 0 );
1201 /**********************************************************************
1202 * GetCapture16 (USER.236)
1204 HWND16 WINAPI
GetCapture16(void)
1210 /**********************************************************************
1211 * GetCapture32 (USER32.208)
1213 HWND32 WINAPI
GetCapture32(void)
1219 /***********************************************************************
1220 * GetMouseEventProc (USER.337)
1222 FARPROC16 WINAPI
GetMouseEventProc(void)
1224 HMODULE16 hmodule
= GetModuleHandle16("USER");
1225 return NE_GetEntryPoint( hmodule
, NE_GetOrdinal( hmodule
, "Mouse_Event" ));
1229 /***********************************************************************
1230 * Mouse_Event (USER.299)
1232 void WINAPI
Mouse_Event( CONTEXT
*context
)
1236 * BX = horizontal displacement if AX & ME_MOVE
1237 * CX = vertical displacement if AX & ME_MOVE
1238 * DX = button state (?)
1239 * SI = mouse event flags (?)
1242 int rootX
, rootY
, winX
, winY
;
1245 if (AX_reg(context
) & ME_MOVE
)
1247 /* We have to actually move the cursor */
1248 TSXWarpPointer( display
, rootWindow
, None
, 0, 0, 0, 0,
1249 (short)BX_reg(context
), (short)CX_reg(context
) );
1252 if (!TSXQueryPointer( display
, rootWindow
, &root
, &child
,
1253 &rootX
, &rootY
, &winX
, &winY
, &state
)) return;
1254 if (AX_reg(context
) & ME_LDOWN
)
1255 hardware_event( WM_LBUTTONDOWN
, EVENT_XStateToKeyState( state
),
1256 0L, winX
, winY
, GetTickCount(), 0 );
1257 if (AX_reg(context
) & ME_LUP
)
1258 hardware_event( WM_LBUTTONUP
, EVENT_XStateToKeyState( state
),
1259 0L, winX
, winY
, GetTickCount(), 0 );
1260 if (AX_reg(context
) & ME_RDOWN
)
1261 hardware_event( WM_RBUTTONDOWN
, EVENT_XStateToKeyState( state
),
1262 0L, winX
, winY
, GetTickCount(), 0 );
1263 if (AX_reg(context
) & ME_RUP
)
1264 hardware_event( WM_RBUTTONUP
, EVENT_XStateToKeyState( state
),
1265 0L, winX
, winY
, GetTickCount(), 0 );
1269 /**********************************************************************
1270 * EnableHardwareInput (USER.331)
1272 BOOL16 WINAPI
EnableHardwareInput(BOOL16 bEnable
)
1274 BOOL16 bOldState
= InputEnabled
;
1275 FIXME(event
,"(%d) - stub\n", bEnable
);
1276 InputEnabled
= bEnable
;
1281 /***********************************************************************
1282 * SwapMouseButton16 (USER.186)
1284 BOOL16 WINAPI
SwapMouseButton16( BOOL16 fSwap
)
1286 BOOL16 ret
= SwappedButtons
;
1287 SwappedButtons
= fSwap
;
1292 /***********************************************************************
1293 * SwapMouseButton32 (USER32.537)
1295 BOOL32 WINAPI
SwapMouseButton32( BOOL32 fSwap
)
1297 BOOL32 ret
= SwappedButtons
;
1298 SwappedButtons
= fSwap
;