4 * Copyright 1993 Alexandre Julliard
9 #ifndef X_DISPLAY_MISSING
11 #include <X11/Xatom.h>
12 #include <X11/keysym.h>
14 #include "ts_xresource.h"
23 #include <sys/types.h>
45 /* X context to associate a hwnd to an X window */
46 extern XContext winContext
;
48 extern Atom wmProtocols
;
49 extern Atom wmDeleteWindow
;
50 extern Atom dndProtocol
;
51 extern Atom dndSelection
;
53 #define NB_BUTTONS 3 /* Windows can handle 3 buttons */
55 #define DndNotDnd -1 /* OffiX drag&drop */
67 #define DndURL 128 /* KDE drag&drop */
69 /* EVENT_WaitNetEvent() master fd sets */
71 static fd_set __event_io_set
[3];
72 static int __event_max_fd
= 0;
73 static int __event_x_connection
= 0;
75 static const char * const event_names
[] =
77 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
78 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
79 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
80 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
81 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
82 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
83 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
84 "ClientMessage", "MappingNotify"
87 static void EVENT_ProcessEvent( XEvent
*event
);
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 static void EVENT_GetGeometry( Window win
, int *px
, int *py
,
110 unsigned int *pwidth
, unsigned int *pheight
);
113 static BOOL32 (WINAPI
*EVENT_RedrawWindow
)( HWND32 hwnd
, const RECT32
*rectUpdate
,
114 HRGN32 hrgnUpdate
, UINT32 flags
) = NULL
;
117 /***********************************************************************
120 * Initialize network IO.
122 BOOL32
X11DRV_EVENT_Init(void)
125 for( i
= 0; i
< 3; i
++ )
126 FD_ZERO( __event_io_set
+ i
);
128 __event_max_fd
= __event_x_connection
= ConnectionNumber(display
);
129 FD_SET( __event_x_connection
, &__event_io_set
[EVENT_IO_READ
] );
134 /***********************************************************************
137 void X11DRV_EVENT_AddIO( int fd
, unsigned io_type
)
139 FD_SET( fd
, &__event_io_set
[io_type
] );
140 if( __event_max_fd
<= fd
) __event_max_fd
= fd
+ 1;
143 /***********************************************************************
144 * X11DRV_EVENT_DeleteIO
146 void X11DRV_EVENT_DeleteIO( int fd
, unsigned io_type
)
148 FD_CLR( fd
, &__event_io_set
[io_type
] );
151 /***********************************************************************
152 * X11DRV_EVENT_IsUserIdle
154 BOOL16
X11DRV_EVENT_IsUserIdle(void)
156 struct timeval timeout
= {0, 0};
160 FD_SET(__event_x_connection
, &check_set
);
161 if( select(__event_x_connection
+ 1, &check_set
, NULL
, NULL
, &timeout
) > 0 )
166 /***********************************************************************
167 * X11DRV_EVENT_WaitNetEvent
169 * Wait for a network event, optionally sleeping until one arrives.
170 * Returns TRUE if an event is pending that cannot be processed in
171 * 'peek' mode, FALSE otherwise.
174 BOOL32
X11DRV_EVENT_WaitNetEvent( BOOL32 sleep
, BOOL32 peek
)
177 LONG maxWait
= sleep
? TIMER_GetNextExpiration() : 0;
178 int pending
= TSXPending(display
);
180 /* Wait for an event or a timeout. If maxWait is -1, we have no timeout;
181 * in this case, we fall through directly to the XNextEvent loop.
184 if ((maxWait
!= -1) && !pending
)
187 struct timeval timeout
;
190 memcpy( io_set
, __event_io_set
, sizeof(io_set
) );
192 timeout
.tv_usec
= (maxWait
% 1000) * 1000;
193 timeout
.tv_sec
= maxWait
/ 1000;
196 sigsetjmp(env_wait_x
, 1);
199 if (DDE_GetRemoteMessage()) {
200 while(DDE_GetRemoteMessage())
204 stop_wait_op
= STOP_WAIT_X
;
205 /* The code up to the next "stop_wait_op = CONT" must be reentrant */
206 num_pending
= select( __event_max_fd
, &io_set
[EVENT_IO_READ
],
207 &io_set
[EVENT_IO_WRITE
],
208 &io_set
[EVENT_IO_EXCEPT
], &timeout
);
209 if ( num_pending
== 0 )
212 TIMER_ExpireTimers();
215 else stop_wait_op
= CONT
;
216 #else /* CONFIG_IPC */
217 num_pending
= select( __event_max_fd
, &io_set
[EVENT_IO_READ
],
218 &io_set
[EVENT_IO_WRITE
],
219 &io_set
[EVENT_IO_EXCEPT
], &timeout
);
220 if ( num_pending
== 0)
222 /* Timeout or error */
223 TIMER_ExpireTimers();
226 #endif /* CONFIG_IPC */
228 /* Winsock asynchronous services */
230 if( FD_ISSET( __event_x_connection
, &io_set
[EVENT_IO_READ
]) )
234 WINSOCK_HandleIO( &__event_max_fd
, num_pending
, io_set
, __event_io_set
);
236 else /* no X events */
238 WINSOCK_HandleIO( &__event_max_fd
, num_pending
, io_set
, __event_io_set
);
243 { /* Wait for X11 input. */
247 FD_SET(__event_x_connection
, &set
);
248 select(__event_x_connection
+ 1, &set
, 0, 0, 0 );
251 /* Process current X event (and possibly others that occurred in the meantime) */
253 EnterCriticalSection(&X11DRV_CritSection
);
254 while (XPending( display
))
258 if (DDE_GetRemoteMessage())
260 LeaveCriticalSection(&X11DRV_CritSection
);
261 while(DDE_GetRemoteMessage()) ;
264 #endif /* CONFIG_IPC */
266 XNextEvent( display
, &event
);
270 /* Check only for those events which can be processed
273 if( event
.type
== MotionNotify
||
274 event
.type
== ButtonPress
|| event
.type
== ButtonRelease
||
275 event
.type
== KeyPress
|| event
.type
== KeyRelease
||
276 event
.type
== SelectionRequest
|| event
.type
== SelectionClear
||
277 event
.type
== ClientMessage
)
279 LeaveCriticalSection(&X11DRV_CritSection
);
280 EVENT_ProcessEvent( &event
);
281 EnterCriticalSection(&X11DRV_CritSection
);
285 if ( event
.type
== NoExpose
)
288 XPutBackEvent(display
, &event
);
289 LeaveCriticalSection(&X11DRV_CritSection
);
294 LeaveCriticalSection(&X11DRV_CritSection
);
295 EVENT_ProcessEvent( &event
);
296 EnterCriticalSection(&X11DRV_CritSection
);
299 LeaveCriticalSection(&X11DRV_CritSection
);
304 /***********************************************************************
307 * Synchronize with the X server. Should not be used too often.
309 void X11DRV_EVENT_Synchronize()
313 /* Use of the X critical section is needed or we have a small
314 * race between XPending() and XNextEvent().
316 EnterCriticalSection( &X11DRV_CritSection
);
317 XSync( display
, False
);
318 while (XPending( display
))
320 XNextEvent( display
, &event
);
321 /* unlock X critsection for EVENT_ProcessEvent() might switch tasks */
322 LeaveCriticalSection( &X11DRV_CritSection
);
323 EVENT_ProcessEvent( &event
);
324 EnterCriticalSection( &X11DRV_CritSection
);
326 LeaveCriticalSection( &X11DRV_CritSection
);
329 /***********************************************************************
332 * Process an X event.
334 static void EVENT_ProcessEvent( XEvent
*event
)
338 if ( TSXFindContext( display
, event
->xany
.window
, winContext
,
339 (char **)&pWnd
) != 0) {
340 if ( event
->type
== ClientMessage
) {
341 /* query window (drag&drop event contains only drag window) */
343 int root_x
, root_y
, child_x
, child_y
;
345 TSXQueryPointer( display
, rootWindow
, &root
, &child
,
346 &root_x
, &root_y
, &child_x
, &child_y
, &u
);
347 if (TSXFindContext( display
, child
, winContext
, (char **)&pWnd
) != 0)
350 pWnd
= NULL
; /* Not for a registered window */
354 TRACE(event
, "Got event %s for hwnd %04x\n",
355 event_names
[event
->type
], pWnd
? pWnd
->hwndSelf
: 0 );
361 EVENT_Key( pWnd
, (XKeyEvent
*)event
);
365 EVENT_ButtonPress( pWnd
, (XButtonEvent
*)event
);
369 EVENT_ButtonRelease( pWnd
, (XButtonEvent
*)event
);
373 /* Wine between two fast machines across the overloaded campus
374 ethernet gets very boged down in MotionEvents. The following
375 simply finds the last motion event in the queue and drops
376 the rest. On a good link events are servered before they build
377 up so this doesn't take place. On a slow link this may cause
378 problems if the event order is important. I'm not yet seen
379 of any problems. Jon 7/6/96.
381 while (TSXCheckTypedWindowEvent(display
,((XAnyEvent
*)event
)->window
,
382 MotionNotify
, event
));
383 EVENT_MotionNotify( pWnd
, (XMotionEvent
*)event
);
388 EVENT_FocusIn( pWnd
, (XFocusChangeEvent
*)event
);
393 EVENT_FocusOut( pWnd
, (XFocusChangeEvent
*)event
);
397 EVENT_Expose( pWnd
, (XExposeEvent
*)event
);
401 EVENT_GraphicsExpose( pWnd
, (XGraphicsExposeEvent
*)event
);
404 case ConfigureNotify
:
406 EVENT_ConfigureNotify( pWnd
, (XConfigureEvent
*)event
);
409 case SelectionRequest
:
411 EVENT_SelectionRequest( pWnd
, (XSelectionRequestEvent
*)event
);
414 case SelectionNotify
:
416 EVENT_SelectionNotify( (XSelectionEvent
*)event
);
421 EVENT_SelectionClear( pWnd
, (XSelectionClearEvent
*) event
);
426 EVENT_ClientMessage( pWnd
, (XClientMessageEvent
*) event
);
431 EVENT_EnterNotify( pWnd
, (XCrossingEvent
*) event
);
438 /* We get all these because of StructureNotifyMask. */
440 case CirculateNotify
:
449 EVENT_MapNotify( pWnd
->hwndSelf
, (XMapEvent
*)event
);
453 WARN(event
, "Unprocessed event %s for hwnd %04x\n",
454 event_names
[event
->type
], pWnd
? pWnd
->hwndSelf
: 0 );
459 /***********************************************************************
462 * Try to synchronize internal z-order with the window manager's.
463 * Probably a futile endeavor.
465 static BOOL32
__check_query_condition( WND
** pWndA
, WND
** pWndB
)
467 /* return TRUE if we have at least two managed windows */
469 for( *pWndB
= NULL
; *pWndA
; *pWndA
= (*pWndA
)->next
)
470 if( (*pWndA
)->flags
& WIN_MANAGED
&&
471 (*pWndA
)->dwStyle
& WS_VISIBLE
) break;
473 for( *pWndB
= (*pWndA
)->next
; *pWndB
; *pWndB
= (*pWndB
)->next
)
474 if( (*pWndB
)->flags
& WIN_MANAGED
&&
475 (*pWndB
)->dwStyle
& WS_VISIBLE
) break;
476 return ((*pWndB
) != NULL
);
479 static Window
__get_common_ancestor( Window A
, Window B
,
480 Window
** children
, unsigned* total
)
482 /* find the real root window */
484 Window root
, *childrenB
;
489 if( *children
) TSXFree( *children
);
490 TSXQueryTree( display
, A
, &root
, &A
, children
, total
);
491 TSXQueryTree( display
, B
, &root
, &B
, &childrenB
, &totalB
);
492 if( childrenB
) TSXFree( childrenB
);
493 } while( A
!= B
&& A
&& B
);
494 return ( A
&& B
) ? A
: 0 ;
497 static Window
__get_top_decoration( Window w
, Window ancestor
)
499 Window
* children
, root
, prev
= w
, parent
= w
;
505 TSXQueryTree( display
, w
, &root
, &parent
, &children
, &total
);
506 if( children
) TSXFree( children
);
507 } while( parent
&& parent
!= ancestor
);
508 TRACE(event
, "\t%08x -> %08x\n", (unsigned)prev
, (unsigned)w
);
509 return ( parent
) ? w
: 0 ;
512 static unsigned __td_lookup( Window w
, Window
* list
, unsigned max
)
515 for( i
= 0; i
< max
; i
++ ) if( list
[i
] == w
) break;
519 static BOOL32
EVENT_QueryZOrder( WND
* pWndCheck
)
522 HWND32 hwndInsertAfter
= HWND_TOP
;
523 WND
* pWnd
, *pWndZ
= WIN_GetDesktop()->child
;
524 Window w
, parent
, *children
= NULL
;
525 unsigned total
, check
, pos
, best
;
527 if( !__check_query_condition(&pWndZ
, &pWnd
) ) return TRUE
;
529 parent
= __get_common_ancestor( X11DRV_WND_GetXWindow(pWndZ
),
530 X11DRV_WND_GetXWindow(pWnd
),
532 if( parent
&& children
)
534 w
= __get_top_decoration( X11DRV_WND_GetXWindow(pWndCheck
), parent
);
535 if( w
!= children
[total
- 1] )
537 check
= __td_lookup( w
, children
, total
);
539 for( pWnd
= pWndZ
; pWnd
; pWnd
= pWnd
->next
)
541 if( pWnd
!= pWndCheck
)
543 if( !(pWnd
->flags
& WIN_MANAGED
) ||
544 !(w
= __get_top_decoration( X11DRV_WND_GetXWindow(pWnd
), parent
)) )
546 pos
= __td_lookup( w
, children
, total
);
547 if( pos
< best
&& pos
> check
)
550 hwndInsertAfter
= pWnd
->hwndSelf
;
552 if( check
- best
== 1 ) break;
555 WIN_UnlinkWindow( pWndCheck
->hwndSelf
);
556 WIN_LinkWindow( pWndCheck
->hwndSelf
, hwndInsertAfter
);
559 if( children
) TSXFree( children
);
564 /***********************************************************************
565 * EVENT_XStateToKeyState
567 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
568 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
570 static WORD
EVENT_XStateToKeyState( int state
)
574 if (state
& Button1Mask
) kstate
|= MK_LBUTTON
;
575 if (state
& Button2Mask
) kstate
|= MK_MBUTTON
;
576 if (state
& Button3Mask
) kstate
|= MK_RBUTTON
;
577 if (state
& ShiftMask
) kstate
|= MK_SHIFT
;
578 if (state
& ControlMask
) kstate
|= MK_CONTROL
;
582 /***********************************************************************
583 * X11DRV_EVENT_QueryPointer
585 BOOL32
X11DRV_EVENT_QueryPointer(DWORD
*posX
, DWORD
*posY
, DWORD
*state
)
588 int rootX
, rootY
, winX
, winY
;
591 if (!TSXQueryPointer( display
, rootWindow
, &root
, &child
,
592 &rootX
, &rootY
, &winX
, &winY
, &xstate
))
600 *state
= EVENT_XStateToKeyState( xstate
);
605 /***********************************************************************
608 static void EVENT_Expose( WND
*pWnd
, XExposeEvent
*event
)
612 /* Make position relative to client area instead of window */
613 rect
.left
= event
->x
- (pWnd
? (pWnd
->rectClient
.left
- pWnd
->rectWindow
.left
) : 0);
614 rect
.top
= event
->y
- (pWnd
? (pWnd
->rectClient
.top
- pWnd
->rectWindow
.top
) : 0);
615 rect
.right
= rect
.left
+ event
->width
;
616 rect
.bottom
= rect
.top
+ event
->height
;
618 if ( !EVENT_RedrawWindow
)
620 HMODULE32 hModule
= GetModuleHandle32A( "USER32" );
621 EVENT_RedrawWindow
= GetProcAddress32( hModule
, "RedrawWindow" );
624 EVENT_RedrawWindow( pWnd
? pWnd
->hwndSelf
: 0, &rect
, 0,
625 RDW_INVALIDATE
| RDW_FRAME
| RDW_ALLCHILDREN
| RDW_ERASE
|
626 (event
->count
? 0 : RDW_ERASENOW
) );
630 /***********************************************************************
631 * EVENT_GraphicsExpose
633 * This is needed when scrolling area is partially obscured
634 * by non-Wine X window.
636 static void EVENT_GraphicsExpose( WND
*pWnd
, XGraphicsExposeEvent
*event
)
640 /* Make position relative to client area instead of window */
641 rect
.left
= event
->x
- (pWnd
? (pWnd
->rectClient
.left
- pWnd
->rectWindow
.left
) : 0);
642 rect
.top
= event
->y
- (pWnd
? (pWnd
->rectClient
.top
- pWnd
->rectWindow
.top
) : 0);
643 rect
.right
= rect
.left
+ event
->width
;
644 rect
.bottom
= rect
.top
+ event
->height
;
646 if ( !EVENT_RedrawWindow
)
648 HMODULE32 hModule
= GetModuleHandle32A( "USER32" );
649 EVENT_RedrawWindow
= GetProcAddress32( hModule
, "RedrawWindow" );
652 EVENT_RedrawWindow( pWnd
? pWnd
->hwndSelf
: 0, &rect
, 0,
653 RDW_INVALIDATE
| RDW_ALLCHILDREN
| RDW_ERASE
|
654 (event
->count
? 0 : RDW_ERASENOW
) );
658 /***********************************************************************
661 * Handle a X key event
663 static void EVENT_Key( WND
*pWnd
, XKeyEvent
*event
)
665 KEYBOARD_HandleEvent( pWnd
, event
);
669 /***********************************************************************
672 static void EVENT_MotionNotify( WND
*pWnd
, XMotionEvent
*event
)
674 int xOffset
= pWnd
? pWnd
->rectWindow
.left
: 0;
675 int yOffset
= pWnd
? pWnd
->rectWindow
.top
: 0;
677 MOUSE_SendEvent( MOUSEEVENTF_MOVE
,
678 xOffset
+ event
->x
, yOffset
+ event
->y
,
679 EVENT_XStateToKeyState( event
->state
),
680 event
->time
- MSG_WineStartTicks
,
681 pWnd
? pWnd
->hwndSelf
: 0 );
685 /***********************************************************************
686 * X11DRV_EVENT_DummyMotionNotify
688 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
690 void X11DRV_EVENT_DummyMotionNotify(void)
692 DWORD winX
, winY
, state
;
694 if ( EVENT_QueryPointer( &winX
, &winY
, &state
) )
696 MOUSE_SendEvent( MOUSEEVENTF_MOVE
, winX
, winY
, state
,
702 /***********************************************************************
705 static void EVENT_ButtonPress( WND
*pWnd
, XButtonEvent
*event
)
707 static WORD statusCodes
[NB_BUTTONS
] =
708 { MOUSEEVENTF_LEFTDOWN
, MOUSEEVENTF_MIDDLEDOWN
, MOUSEEVENTF_RIGHTDOWN
};
709 int buttonNum
= event
->button
- 1;
711 int xOffset
= pWnd
? pWnd
->rectWindow
.left
: 0;
712 int yOffset
= pWnd
? pWnd
->rectWindow
.top
: 0;
714 if (buttonNum
>= NB_BUTTONS
) return;
716 MOUSE_SendEvent( statusCodes
[buttonNum
],
717 xOffset
+ event
->x
, yOffset
+ event
->y
,
718 EVENT_XStateToKeyState( event
->state
),
719 event
->time
- MSG_WineStartTicks
,
720 pWnd
? pWnd
->hwndSelf
: 0 );
724 /***********************************************************************
725 * EVENT_ButtonRelease
727 static void EVENT_ButtonRelease( WND
*pWnd
, XButtonEvent
*event
)
729 static WORD statusCodes
[NB_BUTTONS
] =
730 { MOUSEEVENTF_LEFTUP
, MOUSEEVENTF_MIDDLEUP
, MOUSEEVENTF_RIGHTUP
};
731 int buttonNum
= event
->button
- 1;
733 int xOffset
= pWnd
? pWnd
->rectWindow
.left
: 0;
734 int yOffset
= pWnd
? pWnd
->rectWindow
.top
: 0;
736 if (buttonNum
>= NB_BUTTONS
) return;
738 MOUSE_SendEvent( statusCodes
[buttonNum
],
739 xOffset
+ event
->x
, yOffset
+ event
->y
,
740 EVENT_XStateToKeyState( event
->state
),
741 event
->time
- MSG_WineStartTicks
,
742 pWnd
? pWnd
->hwndSelf
: 0 );
746 /**********************************************************************
749 static void EVENT_FocusIn( WND
*pWnd
, XFocusChangeEvent
*event
)
751 if (Options
.managed
) EVENT_QueryZOrder( pWnd
);
753 if (event
->detail
!= NotifyPointer
)
755 HWND32 hwnd
= pWnd
->hwndSelf
;
757 if (hwnd
!= GetActiveWindow32())
759 WINPOS_ChangeActiveWindow( hwnd
, FALSE
);
760 KEYBOARD_UpdateState();
762 if ((hwnd
!= GetFocus32()) && !IsChild32( hwnd
, GetFocus32()))
768 /**********************************************************************
771 * Note: only top-level override-redirect windows get FocusOut events.
773 static void EVENT_FocusOut( WND
*pWnd
, XFocusChangeEvent
*event
)
775 if (event
->detail
!= NotifyPointer
)
777 HWND32 hwnd
= pWnd
->hwndSelf
;
779 if (hwnd
== GetActiveWindow32())
780 WINPOS_ChangeActiveWindow( 0, FALSE
);
781 if ((hwnd
== GetFocus32()) || IsChild32( hwnd
, GetFocus32()))
786 /**********************************************************************
787 * X11DRV_EVENT_CheckFocus
789 BOOL32
X11DRV_EVENT_CheckFocus(void)
795 TSXGetInputFocus(display
, &xW
, &state
);
797 TSXFindContext(display
, xW
, winContext
, (char **)&pWnd
) )
802 /**********************************************************************
805 * Helper function for ConfigureNotify handling.
806 * Get the new geometry of a window relative to the root window.
808 static void EVENT_GetGeometry( Window win
, int *px
, int *py
,
809 unsigned int *pwidth
, unsigned int *pheight
)
811 Window root
, parent
, *children
;
813 unsigned int width
, height
, border
, depth
, nb_children
;
815 if (!TSXGetGeometry( display
, win
, &root
, px
, py
, pwidth
, pheight
,
816 &border
, &depth
)) return;
817 if (win
== rootWindow
)
825 if (!TSXQueryTree(display
, win
, &root
, &parent
, &children
, &nb_children
))
828 if (parent
== rootWindow
) break;
830 if (!TSXGetGeometry( display
, win
, &root
, &xpos
, &ypos
,
831 &width
, &height
, &border
, &depth
)) return;
838 /**********************************************************************
839 * EVENT_ConfigureNotify
841 * The ConfigureNotify event is only selected on top-level windows
842 * when the -managed flag is used.
844 static void EVENT_ConfigureNotify( WND
*pWnd
, XConfigureEvent
*event
)
847 RECT32 newWindowRect
, newClientRect
;
848 HRGN32 hrgnOldPos
, hrgnNewPos
;
849 Window above
= event
->above
;
851 unsigned int width
, height
;
853 assert (pWnd
->flags
& WIN_MANAGED
);
855 /* We don't rely on the event geometry info, because it is relative
856 * to parent and not to root, and it may be wrong (XFree sets x,y to 0,0
857 * if the window hasn't moved).
859 EVENT_GetGeometry( event
->window
, &x
, &y
, &width
, &height
);
861 /* Fill WINDOWPOS struct */
862 winpos
.flags
= SWP_NOACTIVATE
| SWP_NOZORDER
;
863 winpos
.hwnd
= pWnd
->hwndSelf
;
869 /* Check for unchanged attributes */
870 if (winpos
.x
== pWnd
->rectWindow
.left
&& winpos
.y
== pWnd
->rectWindow
.top
)
871 winpos
.flags
|= SWP_NOMOVE
;
872 if ((winpos
.cx
== pWnd
->rectWindow
.right
- pWnd
->rectWindow
.left
) &&
873 (winpos
.cy
== pWnd
->rectWindow
.bottom
- pWnd
->rectWindow
.top
))
874 winpos
.flags
|= SWP_NOSIZE
;
877 RECT32 rect
= { 0, 0, pWnd
->rectWindow
.right
- pWnd
->rectWindow
.left
,
878 pWnd
->rectWindow
.bottom
- pWnd
->rectWindow
.top
};
879 DCE_InvalidateDCE( pWnd
, &rect
);
882 /* Send WM_WINDOWPOSCHANGING */
883 SendMessage32A( winpos
.hwnd
, WM_WINDOWPOSCHANGING
, 0, (LPARAM
)&winpos
);
885 /* Calculate new position and size */
886 newWindowRect
.left
= x
;
887 newWindowRect
.right
= x
+ width
;
888 newWindowRect
.top
= y
;
889 newWindowRect
.bottom
= y
+ height
;
891 WINPOS_SendNCCalcSize( winpos
.hwnd
, TRUE
, &newWindowRect
,
892 &pWnd
->rectWindow
, &pWnd
->rectClient
,
893 &winpos
, &newClientRect
);
895 hrgnOldPos
= CreateRectRgnIndirect32( &pWnd
->rectWindow
);
896 hrgnNewPos
= CreateRectRgnIndirect32( &newWindowRect
);
897 CombineRgn32( hrgnOldPos
, hrgnOldPos
, hrgnNewPos
, RGN_DIFF
);
898 DeleteObject32(hrgnOldPos
);
899 DeleteObject32(hrgnNewPos
);
901 /* Set new size and position */
902 pWnd
->rectWindow
= newWindowRect
;
903 pWnd
->rectClient
= newClientRect
;
904 SendMessage32A( winpos
.hwnd
, WM_WINDOWPOSCHANGED
, 0, (LPARAM
)&winpos
);
906 if (!IsWindow32( winpos
.hwnd
)) return;
907 if( above
== None
) /* absolute bottom */
909 WIN_UnlinkWindow( winpos
.hwnd
);
910 WIN_LinkWindow( winpos
.hwnd
, HWND_BOTTOM
);
912 else EVENT_QueryZOrder( pWnd
); /* try to outsmart window manager */
916 /***********************************************************************
917 * EVENT_SelectionRequest
919 static void EVENT_SelectionRequest( WND
*pWnd
, XSelectionRequestEvent
*event
)
921 XSelectionEvent result
;
923 Window request
= event
->requestor
;
925 if(event
->target
== XA_STRING
)
931 rprop
= event
->property
;
933 if(rprop
== None
) rprop
= event
->target
;
935 if(event
->selection
!=XA_PRIMARY
) rprop
= None
;
936 else if(!CLIPBOARD_IsPresent(CF_OEMTEXT
)) rprop
= None
;
939 /* open to make sure that clipboard is available */
941 BOOL32 couldOpen
= OpenClipboard32( pWnd
->hwndSelf
);
944 hText
= GetClipboardData16(CF_TEXT
);
945 text
= GlobalLock16(hText
);
946 size
= GlobalSize16(hText
);
948 /* remove carriage returns */
950 lpstr
= (char*)HEAP_xalloc( GetProcessHeap(), 0, size
-- );
951 for(i
=0,j
=0; i
< size
&& text
[i
]; i
++ )
953 if( text
[i
] == '\r' &&
954 (text
[i
+1] == '\n' || text
[i
+1] == '\0') ) continue;
955 lpstr
[j
++] = text
[i
];
959 TSXChangeProperty(display
, request
, rprop
,
960 XA_STRING
, 8, PropModeReplace
,
962 HeapFree( GetProcessHeap(), 0, lpstr
);
964 /* close only if we opened before */
966 if(couldOpen
) CloseClipboard32();
971 TRACE(event
,"Request for %s ignored\n", TSXGetAtomName(display
,event
->target
));
973 result
.type
= SelectionNotify
;
974 result
.display
= display
;
975 result
.requestor
= request
;
976 result
.selection
= event
->selection
;
977 result
.property
= rprop
;
978 result
.target
= event
->target
;
979 result
.time
= event
->time
;
980 TSXSendEvent(display
,event
->requestor
,False
,NoEventMask
,(XEvent
*)&result
);
984 /***********************************************************************
985 * EVENT_SelectionNotify
987 static void EVENT_SelectionNotify( XSelectionEvent
*event
)
989 if (event
->selection
!= XA_PRIMARY
) return;
991 if (event
->target
!= XA_STRING
) X11DRV_CLIPBOARD_ReadSelection( 0, None
);
992 else X11DRV_CLIPBOARD_ReadSelection( event
->requestor
, event
->property
);
994 TRACE(clipboard
,"\tSelectionNotify done!\n");
998 /***********************************************************************
999 * EVENT_SelectionClear
1001 static void EVENT_SelectionClear( WND
*pWnd
, XSelectionClearEvent
*event
)
1003 if (event
->selection
!= XA_PRIMARY
) return;
1004 X11DRV_CLIPBOARD_ReleaseSelection( event
->window
, pWnd
->hwndSelf
);
1008 /**********************************************************************
1009 * EVENT_DropFromOffix
1011 * don't know if it still works (last Changlog is from 96/11/04)
1013 static void EVENT_DropFromOffiX( WND
*pWnd
, XClientMessageEvent
*event
)
1015 unsigned long data_length
;
1016 unsigned long aux_long
;
1017 unsigned char* p_data
= NULL
;
1025 HGLOBAL16 hDragInfo
= GlobalAlloc16( GMEM_SHARE
| GMEM_ZEROINIT
, sizeof(DRAGINFO
));
1026 LPDRAGINFO lpDragInfo
= (LPDRAGINFO
) GlobalLock16(hDragInfo
);
1027 SEGPTR spDragInfo
= (SEGPTR
) WIN16_GlobalLock16(hDragInfo
);
1028 Window w_aux_root
, w_aux_child
;
1031 if( !lpDragInfo
|| !spDragInfo
) return;
1033 TSXQueryPointer( display
, X11DRV_WND_GetXWindow(pWnd
), &w_aux_root
, &w_aux_child
,
1034 &x
, &y
, &u
.pt_aux
.x
, &u
.pt_aux
.y
, (unsigned int*)&aux_long
);
1036 lpDragInfo
->hScope
= pWnd
->hwndSelf
;
1037 lpDragInfo
->pt
.x
= (INT16
)x
; lpDragInfo
->pt
.y
= (INT16
)y
;
1039 /* find out drop point and drop window */
1040 if( x
< 0 || y
< 0 ||
1041 x
> (pWnd
->rectWindow
.right
- pWnd
->rectWindow
.left
) ||
1042 y
> (pWnd
->rectWindow
.bottom
- pWnd
->rectWindow
.top
) )
1043 { bAccept
= pWnd
->dwExStyle
& WS_EX_ACCEPTFILES
; x
= y
= 0; }
1046 bAccept
= DRAG_QueryUpdate( pWnd
->hwndSelf
, spDragInfo
, TRUE
);
1047 x
= lpDragInfo
->pt
.x
; y
= lpDragInfo
->pt
.y
;
1049 pDropWnd
= WIN_FindWndPtr( lpDragInfo
->hScope
);
1050 GlobalFree16( hDragInfo
);
1054 TSXGetWindowProperty( display
, DefaultRootWindow(display
),
1055 dndSelection
, 0, 65535, FALSE
,
1056 AnyPropertyType
, &u
.atom_aux
, &u
.pt_aux
.y
,
1057 &data_length
, &aux_long
, &p_data
);
1059 if( !aux_long
&& p_data
) /* don't bother if > 64K */
1061 char *p
= (char*) p_data
;
1065 while( *p
) /* calculate buffer size */
1068 if((u
.i
= *p
) != -1 )
1069 u
.i
= DRIVE_FindDriveRoot( (const char **)&p_drop
);
1070 if( u
.i
== -1 ) *p
= -1; /* mark as "bad" */
1073 INT32 len
= GetShortPathName32A( p
, NULL
, 0 );
1074 if (len
) aux_long
+= len
+ 1;
1079 if( aux_long
&& aux_long
< 65535 )
1082 LPDROPFILESTRUCT16 lpDrop
;
1084 aux_long
+= sizeof(DROPFILESTRUCT16
) + 1;
1085 hDrop
= (HDROP16
)GlobalAlloc16( GMEM_SHARE
, aux_long
);
1086 lpDrop
= (LPDROPFILESTRUCT16
) GlobalLock16( hDrop
);
1090 lpDrop
->wSize
= sizeof(DROPFILESTRUCT16
);
1091 lpDrop
->ptMousePos
.x
= (INT16
)x
;
1092 lpDrop
->ptMousePos
.y
= (INT16
)y
;
1093 lpDrop
->fInNonClientArea
= (BOOL16
)
1094 ( x
< (pDropWnd
->rectClient
.left
- pDropWnd
->rectWindow
.left
) ||
1095 y
< (pDropWnd
->rectClient
.top
- pDropWnd
->rectWindow
.top
) ||
1096 x
> (pDropWnd
->rectClient
.right
- pDropWnd
->rectWindow
.left
) ||
1097 y
> (pDropWnd
->rectClient
.bottom
- pDropWnd
->rectWindow
.top
) );
1098 p_drop
= ((char*)lpDrop
) + sizeof(DROPFILESTRUCT16
);
1102 if( *p
!= -1 ) /* use only "good" entries */
1104 GetShortPathName32A( p
, p_drop
, 65535 );
1105 p_drop
+= strlen( p_drop
) + 1;
1110 PostMessage16( pWnd
->hwndSelf
, WM_DROPFILES
,
1111 (WPARAM16
)hDrop
, 0L );
1115 if( p_data
) TSXFree(p_data
);
1117 } /* WS_EX_ACCEPTFILES */
1120 /**********************************************************************
1123 * drop items are separated by \n
1124 * each item is prefixed by its mime type
1126 * event->data.l[3], event->data.l[4] contains drop x,y position
1128 static void EVENT_DropURLs( WND
*pWnd
, XClientMessageEvent
*event
)
1131 unsigned long data_length
;
1132 unsigned long aux_long
, drop_len
= 0;
1133 unsigned char *p_data
= NULL
; /* property data */
1134 char *p_drop
= NULL
;
1136 int x
, y
, drop32
= FALSE
;
1148 drop32
= pWnd
->flags
& WIN_ISWIN32
;
1150 if (!(pWnd
->dwExStyle
& WS_EX_ACCEPTFILES
))
1153 TSXGetWindowProperty( display
, DefaultRootWindow(display
),
1154 dndSelection
, 0, 65535, FALSE
,
1155 AnyPropertyType
, &u
.atom_aux
, &u
.i
,
1156 &data_length
, &aux_long
, &p_data
);
1158 WARN(event
,"property too large, truncated!\n");
1159 TRACE(event
,"urls=%s\n", p_data
);
1161 if( !aux_long
&& p_data
) { /* don't bother if > 64K */
1162 /* calculate length */
1164 next
= strchr(p
, '\n');
1167 if (strncmp(p
,"file:",5) == 0 ) {
1168 INT32 len
= GetShortPathName32A( p
+5, NULL
, 0 );
1169 if (len
) drop_len
+= len
+ 1;
1174 next
= strchr(p
, '\n');
1180 if( drop_len
&& drop_len
< 65535 ) {
1181 TSXQueryPointer( display
, rootWindow
, &u
.w_aux
, &u
.w_aux
,
1182 &x
, &y
, &u
.i
, &u
.i
, &u
.i
);
1183 pDropWnd
= WIN_FindWndPtr( pWnd
->hwndSelf
);
1186 LPDROPFILESTRUCT32 lpDrop
;
1187 drop_len
+= sizeof(DROPFILESTRUCT32
) + 1;
1188 hDrop
.h32
= (HDROP32
)GlobalAlloc32( GMEM_SHARE
, drop_len
);
1189 lpDrop
= (LPDROPFILESTRUCT32
) GlobalLock32( hDrop
.h32
);
1192 lpDrop
->lSize
= sizeof(DROPFILESTRUCT32
);
1193 lpDrop
->ptMousePos
.x
= (INT32
)x
;
1194 lpDrop
->ptMousePos
.y
= (INT32
)y
;
1195 lpDrop
->fInNonClientArea
= (BOOL32
)
1196 ( x
< (pDropWnd
->rectClient
.left
- pDropWnd
->rectWindow
.left
) ||
1197 y
< (pDropWnd
->rectClient
.top
- pDropWnd
->rectWindow
.top
) ||
1198 x
> (pDropWnd
->rectClient
.right
- pDropWnd
->rectWindow
.left
) ||
1199 y
> (pDropWnd
->rectClient
.bottom
- pDropWnd
->rectWindow
.top
) );
1200 lpDrop
->fWideChar
= FALSE
;
1201 p_drop
= ((char*)lpDrop
) + sizeof(DROPFILESTRUCT32
);
1204 LPDROPFILESTRUCT16 lpDrop
;
1205 drop_len
+= sizeof(DROPFILESTRUCT16
) + 1;
1206 hDrop
.h16
= (HDROP16
)GlobalAlloc16( GMEM_SHARE
, drop_len
);
1207 lpDrop
= (LPDROPFILESTRUCT16
) GlobalLock16( hDrop
.h16
);
1210 lpDrop
->wSize
= sizeof(DROPFILESTRUCT16
);
1211 lpDrop
->ptMousePos
.x
= (INT16
)x
;
1212 lpDrop
->ptMousePos
.y
= (INT16
)y
;
1213 lpDrop
->fInNonClientArea
= (BOOL16
)
1214 ( x
< (pDropWnd
->rectClient
.left
- pDropWnd
->rectWindow
.left
) ||
1215 y
< (pDropWnd
->rectClient
.top
- pDropWnd
->rectWindow
.top
) ||
1216 x
> (pDropWnd
->rectClient
.right
- pDropWnd
->rectWindow
.left
) ||
1217 y
> (pDropWnd
->rectClient
.bottom
- pDropWnd
->rectWindow
.top
) );
1218 p_drop
= ((char*)lpDrop
) + sizeof(DROPFILESTRUCT16
);
1222 /* create message content */
1225 next
= strchr(p
, '\n');
1228 if (strncmp(p
,"file:",5) == 0 ) {
1229 INT32 len
= GetShortPathName32A( p
+5, p_drop
, 65535 );
1231 TRACE(event
, "drop file %s as %s\n", p
+5, p_drop
);
1234 WARN(event
, "can't convert file %s to dos name \n", p
+5);
1237 WARN(event
, "unknown mime type %s\n", p
);
1242 next
= strchr(p
, '\n');
1250 /* can not use PostMessage32A because it is currently based on
1251 * PostMessage16 and WPARAM32 would be truncated to WPARAM16
1253 GlobalUnlock32(hDrop
.h32
);
1254 SendMessage32A( pWnd
->hwndSelf
, WM_DROPFILES
,
1255 (WPARAM32
)hDrop
.h32
, 0L );
1257 GlobalUnlock16(hDrop
.h16
);
1258 PostMessage16( pWnd
->hwndSelf
, WM_DROPFILES
,
1259 (WPARAM16
)hDrop
.h16
, 0L );
1263 if( p_data
) TSXFree(p_data
);
1267 /**********************************************************************
1268 * EVENT_ClientMessage
1270 static void EVENT_ClientMessage( WND
*pWnd
, XClientMessageEvent
*event
)
1272 if (event
->message_type
!= None
&& event
->format
== 32) {
1273 if ((event
->message_type
== wmProtocols
) &&
1274 (((Atom
) event
->data
.l
[0]) == wmDeleteWindow
))
1275 SendMessage16( pWnd
->hwndSelf
, WM_SYSCOMMAND
, SC_CLOSE
, 0 );
1276 else if ( event
->message_type
== dndProtocol
&&
1277 (event
->data
.l
[0] == DndFile
|| event
->data
.l
[0] == DndFiles
) )
1278 EVENT_DropFromOffiX(pWnd
, event
);
1279 else if ( event
->message_type
== dndProtocol
&&
1280 event
->data
.l
[0] == DndURL
)
1281 EVENT_DropURLs(pWnd
, event
);
1284 /* enable this if you want to see the message */
1285 unsigned char* p_data
= NULL
;
1291 TSXGetWindowProperty( display
, DefaultRootWindow(display
),
1292 dndSelection
, 0, 65535, FALSE
,
1293 AnyPropertyType
, &u
.atom
, &u
.i
,
1294 &u
.l
, &u
.l
, &p_data
);
1295 TRACE(event
, "message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1296 event
->message_type
, event
->data
.l
[0], event
->data
.l
[1],
1297 event
->data
.l
[2], event
->data
.l
[3], event
->data
.l
[4],
1300 TRACE(event
, "unrecognized ClientMessage\n" );
1305 /**********************************************************************
1308 * Install colormap when Wine window is focused in
1309 * self-managed mode with private colormap
1312 void EVENT_EnterNotify( WND
*pWnd
, XCrossingEvent
*event
)
1314 if( !Options
.managed
&& rootWindow
== DefaultRootWindow(display
) &&
1315 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE
) && GetFocus32() )
1316 TSXInstallColormap( display
, COLOR_GetColormap() );
1320 /**********************************************************************
1323 void EVENT_MapNotify( HWND32 hWnd
, XMapEvent
*event
)
1325 HWND32 hwndFocus
= GetFocus32();
1327 if (hwndFocus
&& IsChild32( hWnd
, hwndFocus
))
1328 X11DRV_WND_SetFocus( WIN_FindWndPtr( hwndFocus
) );
1333 /**********************************************************************
1334 * X11DRV_EVENT_Pending
1336 BOOL32
X11DRV_EVENT_Pending()
1338 return TSXPending(display
);
1341 #endif /* !defined(X_DISPLAY_MISSING) */