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 /* X context to associate a hwnd to an X window */
60 static XContext winContext
= 0;
62 static INT16 captureHT
= HTCLIENT
;
63 static HWND32 captureWnd
= 0;
64 static BOOL32 InputEnabled
= TRUE
;
65 static BOOL32 SwappedButtons
= FALSE
;
67 static Atom wmProtocols
= None
;
68 static Atom wmDeleteWindow
= None
;
69 static Atom dndProtocol
= None
;
70 static Atom dndSelection
= None
;
72 /* EVENT_WaitNetEvent() master fd sets */
74 static fd_set __event_io_set
[3];
75 static int __event_max_fd
= 0;
76 static int __event_x_connection
= 0;
78 static const char * const event_names
[] =
80 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
81 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
82 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
83 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
84 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
85 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
86 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
87 "ClientMessage", "MappingNotify"
91 static void EVENT_Key( WND
*pWnd
, XKeyEvent
*event
);
92 static void EVENT_ButtonPress( WND
*pWnd
, XButtonEvent
*event
);
93 static void EVENT_ButtonRelease( WND
*pWnd
, XButtonEvent
*event
);
94 static void EVENT_MotionNotify( WND
*pWnd
, XMotionEvent
*event
);
95 static void EVENT_FocusIn( WND
*pWnd
, XFocusChangeEvent
*event
);
96 static void EVENT_FocusOut( WND
*pWnd
, XFocusChangeEvent
*event
);
97 static void EVENT_Expose( WND
*pWnd
, XExposeEvent
*event
);
98 static void EVENT_GraphicsExpose( WND
*pWnd
, XGraphicsExposeEvent
*event
);
99 static void EVENT_ConfigureNotify( WND
*pWnd
, XConfigureEvent
*event
);
100 static void EVENT_SelectionRequest( WND
*pWnd
, XSelectionRequestEvent
*event
);
101 static void EVENT_SelectionNotify( XSelectionEvent
*event
);
102 static void EVENT_SelectionClear( WND
*pWnd
, XSelectionClearEvent
*event
);
103 static void EVENT_ClientMessage( WND
*pWnd
, XClientMessageEvent
*event
);
104 static void EVENT_MapNotify( HWND32 hwnd
, XMapEvent
*event
);
106 /* Usable only with OLVWM - compile option perhaps?
107 static void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event );
110 static void EVENT_SendMouseEvent( WORD mouseStatus
, WORD deltaX
, WORD deltaY
,
111 WORD buttonCount
, DWORD extraInfo
);
113 /***********************************************************************
116 * Initialize network IO.
118 BOOL32
EVENT_Init(void)
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
] );
130 /***********************************************************************
133 void EVENT_AddIO( int fd
, unsigned 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
, unsigned io_type
)
141 FD_CLR( fd
, &__event_io_set
[io_type
] );
144 /***********************************************************************
147 * Process an X event.
149 void EVENT_ProcessEvent( XEvent
*event
)
153 if (TSXFindContext( display
, event
->xany
.window
, winContext
,
154 (char **)&pWnd
) != 0)
155 return; /* Not for a registered window */
157 TRACE(event
, "Got event %s for hwnd %04x\n",
158 event_names
[event
->type
], pWnd
->hwndSelf
);
164 if (InputEnabled
) EVENT_Key( pWnd
, (XKeyEvent
*)event
);
169 EVENT_ButtonPress( pWnd
, (XButtonEvent
*)event
);
174 EVENT_ButtonRelease( pWnd
, (XButtonEvent
*)event
);
178 /* Wine between two fast machines across the overloaded campus
179 ethernet gets very boged down in MotionEvents. The following
180 simply finds the last motion event in the queue and drops
181 the rest. On a good link events are servered before they build
182 up so this doesn't take place. On a slow link this may cause
183 problems if the event order is important. I'm not yet seen
184 of any problems. Jon 7/6/96.
188 while (TSXCheckTypedWindowEvent(display
,((XAnyEvent
*)event
)->window
,
189 MotionNotify
, event
));
190 EVENT_MotionNotify( pWnd
, (XMotionEvent
*)event
);
195 EVENT_FocusIn( pWnd
, (XFocusChangeEvent
*)event
);
199 EVENT_FocusOut( pWnd
, (XFocusChangeEvent
*)event
);
203 EVENT_Expose( pWnd
, (XExposeEvent
*)event
);
207 EVENT_GraphicsExpose( pWnd
, (XGraphicsExposeEvent
*)event
);
210 case ConfigureNotify
:
211 EVENT_ConfigureNotify( pWnd
, (XConfigureEvent
*)event
);
214 case SelectionRequest
:
215 EVENT_SelectionRequest( pWnd
, (XSelectionRequestEvent
*)event
);
218 case SelectionNotify
:
219 EVENT_SelectionNotify( (XSelectionEvent
*)event
);
223 EVENT_SelectionClear( pWnd
, (XSelectionClearEvent
*) event
);
227 EVENT_ClientMessage( pWnd
, (XClientMessageEvent
*) event
);
231 * EVENT_EnterNotify( pWnd, (XCrossingEvent *) event );
237 /* We get all these because of StructureNotifyMask. */
239 case CirculateNotify
:
247 EVENT_MapNotify( pWnd
->hwndSelf
, (XMapEvent
*)event
);
251 WARN(event
, "Unprocessed event %s for hwnd %04x\n",
252 event_names
[event
->type
], pWnd
->hwndSelf
);
258 /***********************************************************************
259 * EVENT_RegisterWindow
261 * Associate an X window to a HWND.
263 void EVENT_RegisterWindow( WND
*pWnd
)
265 if (wmProtocols
== None
)
266 wmProtocols
= TSXInternAtom( display
, "WM_PROTOCOLS", True
);
267 if (wmDeleteWindow
== None
)
268 wmDeleteWindow
= TSXInternAtom( display
, "WM_DELETE_WINDOW", True
);
269 if( dndProtocol
== None
)
270 dndProtocol
= TSXInternAtom( display
, "DndProtocol" , False
);
271 if( dndSelection
== None
)
272 dndSelection
= TSXInternAtom( display
, "DndSelection" , False
);
274 TSXSetWMProtocols( display
, pWnd
->window
, &wmDeleteWindow
, 1 );
276 if (!winContext
) winContext
= TSXUniqueContext();
277 TSXSaveContext( display
, pWnd
->window
, winContext
, (char *)pWnd
);
280 /***********************************************************************
281 * EVENT_DestroyWindow
283 void EVENT_DestroyWindow( WND
*pWnd
)
287 TSXDeleteContext( display
, pWnd
->window
, winContext
);
288 TSXDestroyWindow( display
, pWnd
->window
);
289 while( TSXCheckWindowEvent(display
, pWnd
->window
, NoEventMask
, &xe
) );
293 /***********************************************************************
294 * IsUserIdle (USER.333)
296 * Check if we have pending X events.
298 BOOL16 WINAPI
IsUserIdle(void)
300 struct timeval timeout
= {0, 0};
304 FD_SET(__event_x_connection
, &check_set
);
305 if( select(__event_x_connection
+ 1, &check_set
, NULL
, NULL
, &timeout
) > 0 )
311 /***********************************************************************
314 * Wait for a network event, optionally sleeping until one arrives.
315 * Return TRUE if an event is pending, FALSE on timeout or error
316 * (for instance lost connection with the server).
318 BOOL32
EVENT_WaitNetEvent( BOOL32 sleep
, BOOL32 peek
)
321 LONG maxWait
= sleep
? TIMER_GetNextExpiration() : 0;
322 int pending
= TSXPending(display
);
324 /* Wait for an event or a timeout. If maxWait is -1, we have no timeout;
325 * in this case, we fall through directly to the XNextEvent loop.
328 if ((maxWait
!= -1) && !pending
)
331 struct timeval timeout
;
334 memcpy( io_set
, __event_io_set
, sizeof(io_set
) );
336 timeout
.tv_usec
= (maxWait
% 1000) * 1000;
337 timeout
.tv_sec
= maxWait
/ 1000;
340 sigsetjmp(env_wait_x
, 1);
343 if (DDE_GetRemoteMessage()) {
344 while(DDE_GetRemoteMessage())
348 stop_wait_op
= STOP_WAIT_X
;
349 /* The code up to the next "stop_wait_op = CONT" must be reentrant */
350 num_pending
= select( __event_max_fd
, &io_set
[EVENT_IO_READ
],
351 &io_set
[EVENT_IO_WRITE
],
352 &io_set
[EVENT_IO_EXCEPT
], &timeout
);
353 if ( num_pending
== 0 )
356 TIMER_ExpireTimers();
359 else stop_wait_op
= CONT
;
360 #else /* CONFIG_IPC */
361 num_pending
= select( __event_max_fd
, &io_set
[EVENT_IO_READ
],
362 &io_set
[EVENT_IO_WRITE
],
363 &io_set
[EVENT_IO_EXCEPT
], &timeout
);
364 if ( num_pending
== 0)
366 /* Timeout or error */
367 TIMER_ExpireTimers();
370 #endif /* CONFIG_IPC */
372 /* Winsock asynchronous services */
374 if( FD_ISSET( __event_x_connection
, &io_set
[EVENT_IO_READ
]) )
378 WINSOCK_HandleIO( &__event_max_fd
, num_pending
, io_set
, __event_io_set
);
380 else /* no X events */
381 return WINSOCK_HandleIO( &__event_max_fd
, num_pending
, io_set
, __event_io_set
);
384 { /* Wait for X11 input. */
388 FD_SET(__event_x_connection
, &set
);
389 select(__event_x_connection
+ 1, &set
, 0, 0, 0 );
392 /* Process current X event (and possibly others that occurred in the meantime) */
394 EnterCriticalSection(&X11DRV_CritSection
);
395 while (XPending( display
))
399 if (DDE_GetRemoteMessage())
401 LeaveCriticalSection(&X11DRV_CritSection
);
402 while(DDE_GetRemoteMessage()) ;
405 #endif /* CONFIG_IPC */
407 XNextEvent( display
, &event
);
409 LeaveCriticalSection(&X11DRV_CritSection
);
415 if (TSXFindContext( display
, ((XAnyEvent
*)&event
)->window
, winContext
,
416 (char **)&pWnd
) || (event
.type
== NoExpose
))
419 /* Check only for those events which can be processed
422 if( event
.type
== MotionNotify
||
423 event
.type
== ButtonPress
|| event
.type
== ButtonRelease
||
424 event
.type
== KeyPress
|| event
.type
== KeyRelease
||
425 event
.type
== SelectionRequest
|| event
.type
== SelectionClear
)
427 EVENT_ProcessEvent( &event
);
433 if( (pQ
= (MESSAGEQUEUE
*)GlobalLock16(pWnd
->hmemTaskQ
)) )
435 pQ
->flags
|= QUEUE_FLAG_XEVENT
;
436 PostEvent(pQ
->hTask
);
437 TSXPutBackEvent(display
, &event
);
442 else EVENT_ProcessEvent( &event
);
443 EnterCriticalSection(&X11DRV_CritSection
);
445 LeaveCriticalSection(&X11DRV_CritSection
);
450 /***********************************************************************
453 * Synchronize with the X server. Should not be used too often.
455 void EVENT_Synchronize()
459 /* Use of the X critical section is needed or we have a small
460 * race between XPending() and XNextEvent().
462 EnterCriticalSection( &X11DRV_CritSection
);
463 XSync( display
, False
);
464 while (XPending( display
))
466 XNextEvent( display
, &event
);
467 /* unlock X critsection for EVENT_ProcessEvent() might switch tasks */
468 LeaveCriticalSection( &X11DRV_CritSection
);
469 EVENT_ProcessEvent( &event
);
470 EnterCriticalSection( &X11DRV_CritSection
);
472 LeaveCriticalSection( &X11DRV_CritSection
);
475 /***********************************************************************
478 * Try to synchronize internal z-order with the window manager's.
479 * Probably a futile endeavor.
481 static BOOL32
__check_query_condition( WND
** pWndA
, WND
** pWndB
)
483 /* return TRUE if we have at least two managed windows */
485 for( *pWndB
= NULL
; *pWndA
; *pWndA
= (*pWndA
)->next
)
486 if( (*pWndA
)->flags
& WIN_MANAGED
&&
487 (*pWndA
)->dwStyle
& WS_VISIBLE
) break;
489 for( *pWndB
= (*pWndA
)->next
; *pWndB
; *pWndB
= (*pWndB
)->next
)
490 if( (*pWndB
)->flags
& WIN_MANAGED
&&
491 (*pWndB
)->dwStyle
& WS_VISIBLE
) break;
492 return ((*pWndB
) != NULL
);
495 static Window
__get_common_ancestor( Window A
, Window B
,
496 Window
** children
, unsigned* total
)
498 /* find the real root window */
500 Window root
, *childrenB
;
505 if( *children
) TSXFree( *children
);
506 TSXQueryTree( display
, A
, &root
, &A
, children
, total
);
507 TSXQueryTree( display
, B
, &root
, &B
, &childrenB
, &totalB
);
508 if( childrenB
) TSXFree( childrenB
);
509 } while( A
!= B
&& A
&& B
);
510 return ( A
&& B
) ? A
: 0 ;
513 static Window
__get_top_decoration( Window w
, Window ancestor
)
515 Window
* children
, root
, prev
= w
, parent
= w
;
521 TSXQueryTree( display
, w
, &root
, &parent
, &children
, &total
);
522 if( children
) TSXFree( children
);
523 } while( parent
&& parent
!= ancestor
);
524 TRACE(event
, "\t%08x -> %08x\n", (unsigned)prev
, (unsigned)w
);
525 return ( parent
) ? w
: 0 ;
528 static unsigned __td_lookup( Window w
, Window
* list
, unsigned max
)
531 for( i
= 0; i
< max
; i
++ ) if( list
[i
] == w
) break;
535 static BOOL32
EVENT_QueryZOrder( WND
* pWndCheck
)
538 HWND32 hwndInsertAfter
= HWND_TOP
;
539 WND
* pWnd
, *pWndZ
= WIN_GetDesktop()->child
;
540 Window w
, parent
, *children
= NULL
;
541 unsigned total
, check
, pos
, best
;
543 if( !__check_query_condition(&pWndZ
, &pWnd
) ) return TRUE
;
545 parent
= __get_common_ancestor( pWndZ
->window
, pWnd
->window
,
547 if( parent
&& children
)
549 w
= __get_top_decoration( pWndCheck
->window
, parent
);
550 if( w
!= children
[total
- 1] )
552 check
= __td_lookup( w
, children
, total
);
554 for( pWnd
= pWndZ
; pWnd
; pWnd
= pWnd
->next
)
556 if( pWnd
!= pWndCheck
)
558 if( !(pWnd
->flags
& WIN_MANAGED
) ||
559 !(w
= __get_top_decoration( pWnd
->window
, parent
)) )
561 pos
= __td_lookup( w
, children
, total
);
562 if( pos
< best
&& pos
> check
)
565 hwndInsertAfter
= pWnd
->hwndSelf
;
567 if( check
- best
== 1 ) break;
570 WIN_UnlinkWindow( pWndCheck
->hwndSelf
);
571 WIN_LinkWindow( pWndCheck
->hwndSelf
, hwndInsertAfter
);
574 if( children
) TSXFree( children
);
579 /***********************************************************************
580 * EVENT_XStateToKeyState
582 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
583 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
585 static WORD
EVENT_XStateToKeyState( int state
)
589 if (state
& Button1Mask
) kstate
|= MK_LBUTTON
;
590 if (state
& Button2Mask
) kstate
|= MK_MBUTTON
;
591 if (state
& Button3Mask
) kstate
|= MK_RBUTTON
;
592 if (state
& ShiftMask
) kstate
|= MK_SHIFT
;
593 if (state
& ControlMask
) kstate
|= MK_CONTROL
;
598 /***********************************************************************
601 static void EVENT_Expose( WND
*pWnd
, XExposeEvent
*event
)
605 /* Make position relative to client area instead of window */
606 rect
.left
= event
->x
- (pWnd
->rectClient
.left
- pWnd
->rectWindow
.left
);
607 rect
.top
= event
->y
- (pWnd
->rectClient
.top
- pWnd
->rectWindow
.top
);
608 rect
.right
= rect
.left
+ event
->width
;
609 rect
.bottom
= rect
.top
+ event
->height
;
611 PAINT_RedrawWindow( pWnd
->hwndSelf
, &rect
, 0,
612 RDW_INVALIDATE
| RDW_FRAME
| RDW_ALLCHILDREN
| RDW_ERASE
|
613 (event
->count
? 0 : RDW_ERASENOW
), 0 );
617 /***********************************************************************
618 * EVENT_GraphicsExpose
620 * This is needed when scrolling area is partially obscured
621 * by non-Wine X window.
623 static void EVENT_GraphicsExpose( WND
*pWnd
, XGraphicsExposeEvent
*event
)
627 /* Make position relative to client area instead of window */
628 rect
.left
= event
->x
- (pWnd
->rectClient
.left
- pWnd
->rectWindow
.left
);
629 rect
.top
= event
->y
- (pWnd
->rectClient
.top
- pWnd
->rectWindow
.top
);
630 rect
.right
= rect
.left
+ event
->width
;
631 rect
.bottom
= rect
.top
+ event
->height
;
633 PAINT_RedrawWindow( pWnd
->hwndSelf
, &rect
, 0,
634 RDW_INVALIDATE
| RDW_ALLCHILDREN
| RDW_ERASE
|
635 (event
->count
? 0 : RDW_ERASENOW
), 0 );
639 /***********************************************************************
642 * Handle a X key event
644 static void EVENT_Key( WND
*pWnd
, XKeyEvent
*event
)
646 KEYBOARD_HandleEvent( pWnd
, event
);
650 /***********************************************************************
653 static void EVENT_MotionNotify( WND
*pWnd
, XMotionEvent
*event
)
655 hardware_event( WM_MOUSEMOVE
, EVENT_XStateToKeyState( event
->state
), 0L,
656 pWnd
->rectWindow
.left
+ event
->x
,
657 pWnd
->rectWindow
.top
+ event
->y
,
658 event
->time
- MSG_WineStartTicks
, pWnd
->hwndSelf
);
660 EVENT_SendMouseEvent( ME_MOVE
,
661 pWnd
->rectWindow
.left
+ event
->x
,
662 pWnd
->rectWindow
.top
+ event
->y
,
667 /***********************************************************************
668 * EVENT_DummyMotionNotify
670 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
672 void EVENT_DummyMotionNotify(void)
675 int rootX
, rootY
, winX
, winY
;
678 if (TSXQueryPointer( display
, rootWindow
, &root
, &child
,
679 &rootX
, &rootY
, &winX
, &winY
, &state
))
681 hardware_event( WM_MOUSEMOVE
, EVENT_XStateToKeyState( state
), 0L,
682 winX
, winY
, GetTickCount(), 0 );
687 /***********************************************************************
690 static void EVENT_ButtonPress( WND
*pWnd
, XButtonEvent
*event
)
692 static WORD messages
[NB_BUTTONS
] =
693 { WM_LBUTTONDOWN
, WM_MBUTTONDOWN
, WM_RBUTTONDOWN
};
694 static WORD statusCodes
[NB_BUTTONS
] =
695 { ME_LDOWN
, 0, ME_RDOWN
};
696 int buttonNum
= event
->button
- 1;
698 if (buttonNum
>= NB_BUTTONS
) return;
699 if (SwappedButtons
) buttonNum
= NB_BUTTONS
- 1 - buttonNum
;
700 MouseButtonsStates
[buttonNum
] = TRUE
;
701 AsyncMouseButtonsStates
[buttonNum
] = TRUE
;
702 hardware_event( messages
[buttonNum
],
703 EVENT_XStateToKeyState( event
->state
), 0L,
704 pWnd
->rectWindow
.left
+ event
->x
,
705 pWnd
->rectWindow
.top
+ event
->y
,
706 event
->time
- MSG_WineStartTicks
, pWnd
->hwndSelf
);
708 EVENT_SendMouseEvent( statusCodes
[buttonNum
],
709 pWnd
->rectWindow
.left
+ event
->x
,
710 pWnd
->rectWindow
.top
+ event
->y
,
715 /***********************************************************************
716 * EVENT_ButtonRelease
718 static void EVENT_ButtonRelease( WND
*pWnd
, XButtonEvent
*event
)
720 static const WORD messages
[NB_BUTTONS
] =
721 { WM_LBUTTONUP
, WM_MBUTTONUP
, WM_RBUTTONUP
};
722 static WORD statusCodes
[NB_BUTTONS
] =
723 { ME_LUP
, 0, ME_RUP
};
724 int buttonNum
= event
->button
- 1;
726 if (buttonNum
>= NB_BUTTONS
) return;
727 if (SwappedButtons
) buttonNum
= NB_BUTTONS
- 1 - buttonNum
;
728 MouseButtonsStates
[buttonNum
] = FALSE
;
729 hardware_event( messages
[buttonNum
],
730 EVENT_XStateToKeyState( event
->state
), 0L,
731 pWnd
->rectWindow
.left
+ event
->x
,
732 pWnd
->rectWindow
.top
+ event
->y
,
733 event
->time
- MSG_WineStartTicks
, pWnd
->hwndSelf
);
735 EVENT_SendMouseEvent( statusCodes
[buttonNum
],
736 pWnd
->rectWindow
.left
+ event
->x
,
737 pWnd
->rectWindow
.top
+ event
->y
,
742 /**********************************************************************
745 static void EVENT_FocusIn( WND
*pWnd
, XFocusChangeEvent
*event
)
747 if (Options
.managed
) EVENT_QueryZOrder( pWnd
);
749 if (event
->detail
!= NotifyPointer
)
751 HWND32 hwnd
= pWnd
->hwndSelf
;
753 if (hwnd
!= GetActiveWindow32())
755 WINPOS_ChangeActiveWindow( hwnd
, FALSE
);
756 KEYBOARD_UpdateState();
758 if ((hwnd
!= GetFocus32()) && !IsChild32( hwnd
, GetFocus32()))
764 /**********************************************************************
767 * Note: only top-level override-redirect windows get FocusOut events.
769 static void EVENT_FocusOut( WND
*pWnd
, XFocusChangeEvent
*event
)
771 if (event
->detail
!= NotifyPointer
)
773 HWND32 hwnd
= pWnd
->hwndSelf
;
775 if (hwnd
== GetActiveWindow32())
776 WINPOS_ChangeActiveWindow( 0, FALSE
);
777 if ((hwnd
== GetFocus32()) || IsChild32( hwnd
, GetFocus32()))
782 /**********************************************************************
785 BOOL32
EVENT_CheckFocus(void)
791 TSXGetInputFocus(display
, &xW
, &state
);
793 TSXFindContext(display
, xW
, winContext
, (char **)&pWnd
) )
799 /**********************************************************************
802 * Helper function for ConfigureNotify handling.
803 * Get the new geometry of a window relative to the root window.
805 static void EVENT_GetGeometry( Window win
, int *px
, int *py
,
806 unsigned int *pwidth
, unsigned int *pheight
)
808 Window root
, parent
, *children
;
810 unsigned int width
, height
, border
, depth
, nb_children
;
812 if (!TSXGetGeometry( display
, win
, &root
, px
, py
, pwidth
, pheight
,
813 &border
, &depth
)) return;
814 if (win
== rootWindow
)
822 if (!TSXQueryTree(display
, win
, &root
, &parent
, &children
, &nb_children
))
825 if (parent
== rootWindow
) break;
827 if (!TSXGetGeometry( display
, win
, &root
, &xpos
, &ypos
,
828 &width
, &height
, &border
, &depth
)) return;
835 /**********************************************************************
836 * EVENT_ConfigureNotify
838 * The ConfigureNotify event is only selected on top-level windows
839 * when the -managed flag is used.
841 static void EVENT_ConfigureNotify( WND
*pWnd
, XConfigureEvent
*event
)
844 RECT32 newWindowRect
, newClientRect
;
845 HRGN32 hrgnOldPos
, hrgnNewPos
;
846 Window above
= event
->above
;
848 unsigned int width
, height
;
850 assert (pWnd
->flags
& WIN_MANAGED
);
852 /* We don't rely on the event geometry info, because it is relative
853 * to parent and not to root, and it may be wrong (XFree sets x,y to 0,0
854 * if the window hasn't moved).
856 EVENT_GetGeometry( event
->window
, &x
, &y
, &width
, &height
);
858 /* Fill WINDOWPOS struct */
859 winpos
.flags
= SWP_NOACTIVATE
| SWP_NOZORDER
;
860 winpos
.hwnd
= pWnd
->hwndSelf
;
866 /* Check for unchanged attributes */
867 if (winpos
.x
== pWnd
->rectWindow
.left
&& winpos
.y
== pWnd
->rectWindow
.top
)
868 winpos
.flags
|= SWP_NOMOVE
;
869 if ((winpos
.cx
== pWnd
->rectWindow
.right
- pWnd
->rectWindow
.left
) &&
870 (winpos
.cy
== pWnd
->rectWindow
.bottom
- pWnd
->rectWindow
.top
))
871 winpos
.flags
|= SWP_NOSIZE
;
874 RECT32 rect
= { 0, 0, pWnd
->rectWindow
.right
- pWnd
->rectWindow
.left
,
875 pWnd
->rectWindow
.bottom
- pWnd
->rectWindow
.top
};
876 DCE_InvalidateDCE( pWnd
, &rect
);
879 /* Send WM_WINDOWPOSCHANGING */
880 SendMessage32A( winpos
.hwnd
, WM_WINDOWPOSCHANGING
, 0, (LPARAM
)&winpos
);
882 /* Calculate new position and size */
883 newWindowRect
.left
= x
;
884 newWindowRect
.right
= x
+ width
;
885 newWindowRect
.top
= y
;
886 newWindowRect
.bottom
= y
+ height
;
888 WINPOS_SendNCCalcSize( winpos
.hwnd
, TRUE
, &newWindowRect
,
889 &pWnd
->rectWindow
, &pWnd
->rectClient
,
890 &winpos
, &newClientRect
);
892 hrgnOldPos
= CreateRectRgnIndirect32( &pWnd
->rectWindow
);
893 hrgnNewPos
= CreateRectRgnIndirect32( &newWindowRect
);
894 CombineRgn32( hrgnOldPos
, hrgnOldPos
, hrgnNewPos
, RGN_DIFF
);
895 DeleteObject32(hrgnOldPos
);
896 DeleteObject32(hrgnNewPos
);
898 /* Set new size and position */
899 pWnd
->rectWindow
= newWindowRect
;
900 pWnd
->rectClient
= newClientRect
;
901 SendMessage32A( winpos
.hwnd
, WM_WINDOWPOSCHANGED
, 0, (LPARAM
)&winpos
);
903 if (!IsWindow32( winpos
.hwnd
)) return;
904 if( above
== None
) /* absolute bottom */
906 WIN_UnlinkWindow( winpos
.hwnd
);
907 WIN_LinkWindow( winpos
.hwnd
, HWND_BOTTOM
);
909 else EVENT_QueryZOrder( pWnd
); /* try to outsmart window manager */
913 /***********************************************************************
914 * EVENT_SelectionRequest
916 static void EVENT_SelectionRequest( WND
*pWnd
, XSelectionRequestEvent
*event
)
918 XSelectionEvent result
;
920 Window request
= event
->requestor
;
922 if(event
->target
== XA_STRING
)
928 rprop
= event
->property
;
930 if(rprop
== None
) rprop
= event
->target
;
932 if(event
->selection
!=XA_PRIMARY
) rprop
= None
;
933 else if(!CLIPBOARD_IsPresent(CF_OEMTEXT
)) rprop
= None
;
936 /* open to make sure that clipboard is available */
938 BOOL32 couldOpen
= OpenClipboard32( pWnd
->hwndSelf
);
941 hText
= GetClipboardData16(CF_TEXT
);
942 text
= GlobalLock16(hText
);
943 size
= GlobalSize16(hText
);
945 /* remove carriage returns */
947 lpstr
= (char*)HEAP_xalloc( GetProcessHeap(), 0, size
-- );
948 for(i
=0,j
=0; i
< size
&& text
[i
]; i
++ )
950 if( text
[i
] == '\r' &&
951 (text
[i
+1] == '\n' || text
[i
+1] == '\0') ) continue;
952 lpstr
[j
++] = text
[i
];
956 TSXChangeProperty(display
, request
, rprop
,
957 XA_STRING
, 8, PropModeReplace
,
959 HeapFree( GetProcessHeap(), 0, lpstr
);
961 /* close only if we opened before */
963 if(couldOpen
) CloseClipboard32();
968 TRACE(event
,"Request for %s ignored\n", TSXGetAtomName(display
,event
->target
));
970 result
.type
= SelectionNotify
;
971 result
.display
= display
;
972 result
.requestor
= request
;
973 result
.selection
= event
->selection
;
974 result
.property
= rprop
;
975 result
.target
= event
->target
;
976 result
.time
= event
->time
;
977 TSXSendEvent(display
,event
->requestor
,False
,NoEventMask
,(XEvent
*)&result
);
981 /***********************************************************************
982 * EVENT_SelectionNotify
984 static void EVENT_SelectionNotify( XSelectionEvent
*event
)
986 if (event
->selection
!= XA_PRIMARY
) return;
988 if (event
->target
!= XA_STRING
) CLIPBOARD_ReadSelection( 0, None
);
989 else CLIPBOARD_ReadSelection( event
->requestor
, event
->property
);
991 TRACE(clipboard
,"\tSelectionNotify done!\n");
995 /***********************************************************************
996 * EVENT_SelectionClear
998 static void EVENT_SelectionClear( WND
*pWnd
, XSelectionClearEvent
*event
)
1000 if (event
->selection
!= XA_PRIMARY
) return;
1001 CLIPBOARD_ReleaseSelection( event
->window
, pWnd
->hwndSelf
);
1005 /**********************************************************************
1006 * EVENT_ClientMessage
1008 static void EVENT_ClientMessage( WND
*pWnd
, XClientMessageEvent
*event
)
1010 if (event
->message_type
!= None
&& event
->format
== 32)
1012 if ((event
->message_type
== wmProtocols
) &&
1013 (((Atom
) event
->data
.l
[0]) == wmDeleteWindow
))
1014 SendMessage16( pWnd
->hwndSelf
, WM_SYSCOMMAND
, SC_CLOSE
, 0 );
1015 else if ( event
->message_type
== dndProtocol
&&
1016 (event
->data
.l
[0] == DndFile
|| event
->data
.l
[0] == DndFiles
) )
1018 unsigned long data_length
;
1019 unsigned long aux_long
;
1020 unsigned char* p_data
= NULL
;
1028 HGLOBAL16 hDragInfo
= GlobalAlloc16( GMEM_SHARE
| GMEM_ZEROINIT
, sizeof(DRAGINFO
));
1029 LPDRAGINFO lpDragInfo
= (LPDRAGINFO
) GlobalLock16(hDragInfo
);
1030 SEGPTR spDragInfo
= (SEGPTR
) WIN16_GlobalLock16(hDragInfo
);
1031 Window w_aux_root
, w_aux_child
;
1034 if( !lpDragInfo
|| !spDragInfo
) return;
1036 TSXQueryPointer( display
, pWnd
->window
, &w_aux_root
, &w_aux_child
,
1037 &x
, &y
, &u
.pt_aux
.x
, &u
.pt_aux
.y
, (unsigned int*)&aux_long
);
1039 lpDragInfo
->hScope
= pWnd
->hwndSelf
;
1040 lpDragInfo
->pt
.x
= (INT16
)x
; lpDragInfo
->pt
.y
= (INT16
)y
;
1042 /* find out drop point and drop window */
1043 if( x
< 0 || y
< 0 ||
1044 x
> (pWnd
->rectWindow
.right
- pWnd
->rectWindow
.left
) ||
1045 y
> (pWnd
->rectWindow
.bottom
- pWnd
->rectWindow
.top
) )
1046 { bAccept
= pWnd
->dwExStyle
& WS_EX_ACCEPTFILES
; x
= y
= 0; }
1049 bAccept
= DRAG_QueryUpdate( pWnd
->hwndSelf
, spDragInfo
, TRUE
);
1050 x
= lpDragInfo
->pt
.x
; y
= lpDragInfo
->pt
.y
;
1052 pDropWnd
= WIN_FindWndPtr( lpDragInfo
->hScope
);
1053 GlobalFree16( hDragInfo
);
1057 TSXGetWindowProperty( display
, DefaultRootWindow(display
),
1058 dndSelection
, 0, 65535, FALSE
,
1059 AnyPropertyType
, &u
.atom_aux
, &u
.pt_aux
.y
,
1060 &data_length
, &aux_long
, &p_data
);
1062 if( !aux_long
&& p_data
) /* don't bother if > 64K */
1064 char *p
= (char*) p_data
;
1068 while( *p
) /* calculate buffer size */
1071 if((u
.i
= *p
) != -1 )
1072 u
.i
= DRIVE_FindDriveRoot( (const char **)&p_drop
);
1073 if( u
.i
== -1 ) *p
= -1; /* mark as "bad" */
1076 INT32 len
= GetShortPathName32A( p
, NULL
, 0 );
1077 if (len
) aux_long
+= len
+ 1;
1082 if( aux_long
&& aux_long
< 65535 )
1085 LPDROPFILESTRUCT lpDrop
;
1087 aux_long
+= sizeof(DROPFILESTRUCT
) + 1;
1088 hDrop
= (HDROP16
)GlobalAlloc16( GMEM_SHARE
, aux_long
);
1089 lpDrop
= (LPDROPFILESTRUCT
) GlobalLock16( hDrop
);
1093 lpDrop
->wSize
= sizeof(DROPFILESTRUCT
);
1094 lpDrop
->ptMousePos
.x
= (INT16
)x
;
1095 lpDrop
->ptMousePos
.y
= (INT16
)y
;
1096 lpDrop
->fInNonClientArea
= (BOOL16
)
1097 ( x
< (pDropWnd
->rectClient
.left
- pDropWnd
->rectWindow
.left
) ||
1098 y
< (pDropWnd
->rectClient
.top
- pDropWnd
->rectWindow
.top
) ||
1099 x
> (pDropWnd
->rectClient
.right
- pDropWnd
->rectWindow
.left
) ||
1100 y
> (pDropWnd
->rectClient
.bottom
- pDropWnd
->rectWindow
.top
) );
1101 p_drop
= ((char*)lpDrop
) + sizeof(DROPFILESTRUCT
);
1105 if( *p
!= -1 ) /* use only "good" entries */
1107 GetShortPathName32A( p
, p_drop
, 65535 );
1108 p_drop
+= strlen( p_drop
) + 1;
1113 PostMessage16( pWnd
->hwndSelf
, WM_DROPFILES
,
1114 (WPARAM16
)hDrop
, 0L );
1118 if( p_data
) TSXFree(p_data
);
1120 } /* WS_EX_ACCEPTFILES */
1123 TRACE(event
, "unrecognized ClientMessage\n" );
1127 /**********************************************************************
1130 * Install colormap when Wine window is focused in
1131 * self-managed mode with private colormap
1134 void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
1136 if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
1137 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
1138 TSXInstallColormap( display, COLOR_GetColormap() );
1142 /**********************************************************************
1145 void EVENT_MapNotify( HWND32 hWnd
, XMapEvent
*event
)
1147 HWND32 hwndFocus
= GetFocus32();
1149 if (hwndFocus
&& IsChild32( hWnd
, hwndFocus
))
1150 FOCUS_SetXFocus( (HWND32
)hwndFocus
);
1155 /**********************************************************************
1158 * We need this to be able to generate double click messages
1159 * when menu code captures mouse in the window without CS_DBLCLK style.
1161 HWND32
EVENT_Capture(HWND32 hwnd
, INT16 ht
)
1163 HWND32 capturePrev
= captureWnd
;
1172 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
1175 TRACE(win
, "(0x%04x)\n", hwnd
);
1181 if( capturePrev
&& capturePrev
!= captureWnd
)
1183 WND
* wndPtr
= WIN_FindWndPtr( capturePrev
);
1184 if( wndPtr
&& (wndPtr
->flags
& WIN_ISWIN32
) )
1185 SendMessage32A( capturePrev
, WM_CAPTURECHANGED
, 0L, hwnd
);
1190 /**********************************************************************
1191 * EVENT_GetCaptureInfo
1193 INT16
EVENT_GetCaptureInfo()
1198 /**********************************************************************
1199 * SetCapture16 (USER.18)
1201 HWND16 WINAPI
SetCapture16( HWND16 hwnd
)
1203 return (HWND16
)EVENT_Capture( hwnd
, HTCLIENT
);
1207 /**********************************************************************
1208 * SetCapture32 (USER32.464)
1210 HWND32 WINAPI
SetCapture32( HWND32 hwnd
)
1212 return EVENT_Capture( hwnd
, HTCLIENT
);
1216 /**********************************************************************
1217 * ReleaseCapture (USER.19) (USER32.439)
1219 void WINAPI
ReleaseCapture(void)
1221 TRACE(win
, "captureWnd=%04x\n", captureWnd
);
1222 if( captureWnd
) EVENT_Capture( 0, 0 );
1226 /**********************************************************************
1227 * GetCapture16 (USER.236)
1229 HWND16 WINAPI
GetCapture16(void)
1235 /**********************************************************************
1236 * GetCapture32 (USER32.208)
1238 HWND32 WINAPI
GetCapture32(void)
1245 /***********************************************************************
1246 * Mouse driver routines:
1250 typedef struct _MOUSEINFO
1260 WORD msMouseCommPort
;
1264 static SEGPTR MouseEventProc
= 0;
1266 /***********************************************************************
1267 * MouseInquire (MOUSE.1)
1270 WORD WINAPI
MouseInquire(MOUSEINFO
*mouseInfo
)
1272 mouseInfo
->msExist
= TRUE
;
1273 mouseInfo
->msRelative
= FALSE
;
1274 mouseInfo
->msNumButtons
= 2;
1275 mouseInfo
->msRate
= 34; /* the DDK says so ... */
1276 mouseInfo
->msXThreshold
= 0;
1277 mouseInfo
->msYThreshold
= 0;
1278 mouseInfo
->msXRes
= 0;
1279 mouseInfo
->msYRes
= 0;
1280 mouseInfo
->msMouseCommPort
= 0;
1282 return sizeof(MOUSEINFO
);
1285 /***********************************************************************
1286 * MouseEnable (MOUSE.2)
1288 VOID WINAPI
MouseEnable(SEGPTR eventProc
)
1290 MouseEventProc
= eventProc
;
1293 /***********************************************************************
1294 * MouseDisable (MOUSE.3)
1296 VOID WINAPI
MouseDisable(VOID
)
1301 /***********************************************************************
1302 * EVENT_SendMouseEvent
1304 static void EVENT_SendMouseEvent( WORD mouseStatus
, WORD deltaX
, WORD deltaY
,
1305 WORD buttonCount
, DWORD extraInfo
)
1309 if ( !MouseEventProc
) return;
1311 TRACE( keyboard
, "(%04X,%d,%d,%d,%ld)\n", mouseStatus
, deltaX
, deltaY
, buttonCount
, extraInfo
);
1313 mouseStatus
|= 0x8000;
1314 deltaX
= (((long)deltaX
<< 16) + screenWidth
/2) / screenWidth
;
1315 deltaY
= (((long)deltaY
<< 16) + screenHeight
/2) / screenHeight
;
1317 memset( &context
, 0, sizeof(context
) );
1318 CS_reg(&context
) = SELECTOROF( MouseEventProc
);
1319 EIP_reg(&context
) = OFFSETOF( MouseEventProc
);
1320 EAX_reg(&context
) = mouseStatus
;
1321 EBX_reg(&context
) = deltaX
;
1322 ECX_reg(&context
) = deltaY
;
1323 EDX_reg(&context
) = buttonCount
;
1324 ESI_reg(&context
) = LOWORD( extraInfo
);
1325 EDI_reg(&context
) = HIWORD( extraInfo
);
1327 Callbacks
->CallRegisterShortProc( &context
, 0 );
1333 /***********************************************************************
1334 * GetMouseEventProc (USER.337)
1336 FARPROC16 WINAPI
GetMouseEventProc(void)
1338 HMODULE16 hmodule
= GetModuleHandle16("USER");
1339 return NE_GetEntryPoint( hmodule
, NE_GetOrdinal( hmodule
, "Mouse_Event" ));
1343 /***********************************************************************
1344 * Mouse_Event (USER.299)
1346 void WINAPI
Mouse_Event( CONTEXT
*context
)
1350 * BX = horizontal displacement if AX & ME_MOVE
1351 * CX = vertical displacement if AX & ME_MOVE
1352 * DX = button state (?)
1353 * SI = mouse event flags (?)
1356 int rootX
, rootY
, winX
, winY
;
1359 if (AX_reg(context
) & ME_MOVE
)
1361 /* We have to actually move the cursor */
1362 TSXWarpPointer( display
, rootWindow
, None
, 0, 0, 0, 0,
1363 (short)BX_reg(context
), (short)CX_reg(context
) );
1366 if (!TSXQueryPointer( display
, rootWindow
, &root
, &child
,
1367 &rootX
, &rootY
, &winX
, &winY
, &state
)) return;
1368 if (AX_reg(context
) & ME_LDOWN
)
1369 hardware_event( WM_LBUTTONDOWN
, EVENT_XStateToKeyState( state
),
1370 0L, winX
, winY
, GetTickCount(), 0 );
1371 if (AX_reg(context
) & ME_LUP
)
1372 hardware_event( WM_LBUTTONUP
, EVENT_XStateToKeyState( state
),
1373 0L, winX
, winY
, GetTickCount(), 0 );
1374 if (AX_reg(context
) & ME_RDOWN
)
1375 hardware_event( WM_RBUTTONDOWN
, EVENT_XStateToKeyState( state
),
1376 0L, winX
, winY
, GetTickCount(), 0 );
1377 if (AX_reg(context
) & ME_RUP
)
1378 hardware_event( WM_RBUTTONUP
, EVENT_XStateToKeyState( state
),
1379 0L, winX
, winY
, GetTickCount(), 0 );
1383 /**********************************************************************
1384 * EnableHardwareInput (USER.331)
1386 BOOL16 WINAPI
EnableHardwareInput(BOOL16 bEnable
)
1388 BOOL16 bOldState
= InputEnabled
;
1389 FIXME(event
,"(%d) - stub\n", bEnable
);
1390 InputEnabled
= bEnable
;
1395 /***********************************************************************
1396 * SwapMouseButton16 (USER.186)
1398 BOOL16 WINAPI
SwapMouseButton16( BOOL16 fSwap
)
1400 BOOL16 ret
= SwappedButtons
;
1401 SwappedButtons
= fSwap
;
1406 /***********************************************************************
1407 * SwapMouseButton32 (USER32.537)
1409 BOOL32 WINAPI
SwapMouseButton32( BOOL32 fSwap
)
1411 BOOL32 ret
= SwappedButtons
;
1412 SwappedButtons
= fSwap
;