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"
46 #define NB_BUTTONS 3 /* Windows can handle 3 buttons */
48 #define DndNotDnd -1 /* OffiX drag&drop */
60 #define DndURL 128 /* KDE drag&drop */
63 /* X context to associate a hwnd to an X window */
64 static XContext winContext
= 0;
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 int 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
);
112 /***********************************************************************
115 * Initialize network IO.
117 BOOL32
EVENT_Init(void)
120 for( i
= 0; i
< 3; i
++ )
121 FD_ZERO( __event_io_set
+ i
);
123 __event_max_fd
= __event_x_connection
= ConnectionNumber(display
);
124 FD_SET( __event_x_connection
, &__event_io_set
[EVENT_IO_READ
] );
129 /***********************************************************************
132 void EVENT_AddIO( int fd
, unsigned io_type
)
134 FD_SET( fd
, &__event_io_set
[io_type
] );
135 if( __event_max_fd
<= fd
) __event_max_fd
= fd
+ 1;
138 void EVENT_DeleteIO( int fd
, unsigned io_type
)
140 FD_CLR( fd
, &__event_io_set
[io_type
] );
143 /***********************************************************************
146 * Process an X event.
148 void EVENT_ProcessEvent( XEvent
*event
)
152 if ( TSXFindContext( display
, event
->xany
.window
, winContext
,
153 (char **)&pWnd
) != 0) {
154 if ( event
->type
== ClientMessage
) {
155 /* query window (drag&drop event contains only drag window) */
157 int root_x
, root_y
, child_x
, child_y
;
159 TSXQueryPointer( display
, rootWindow
, &root
, &child
,
160 &root_x
, &root_y
, &child_x
, &child_y
, &u
);
161 if (TSXFindContext( display
, child
, winContext
, (char **)&pWnd
) != 0)
164 pWnd
= NULL
; /* Not for a registered window */
168 TRACE(event
, "Got event %s for hwnd %04x\n",
169 event_names
[event
->type
], pWnd
? pWnd
->hwndSelf
: 0 );
175 EVENT_Key( pWnd
, (XKeyEvent
*)event
);
179 EVENT_ButtonPress( pWnd
, (XButtonEvent
*)event
);
183 EVENT_ButtonRelease( pWnd
, (XButtonEvent
*)event
);
187 /* Wine between two fast machines across the overloaded campus
188 ethernet gets very boged down in MotionEvents. The following
189 simply finds the last motion event in the queue and drops
190 the rest. On a good link events are servered before they build
191 up so this doesn't take place. On a slow link this may cause
192 problems if the event order is important. I'm not yet seen
193 of any problems. Jon 7/6/96.
195 while (TSXCheckTypedWindowEvent(display
,((XAnyEvent
*)event
)->window
,
196 MotionNotify
, event
));
197 EVENT_MotionNotify( pWnd
, (XMotionEvent
*)event
);
202 EVENT_FocusIn( pWnd
, (XFocusChangeEvent
*)event
);
207 EVENT_FocusOut( pWnd
, (XFocusChangeEvent
*)event
);
212 if (EVENT_Expose( pWnd
, (XExposeEvent
*)event
)) {
213 /* need to process ConfigureNotify first */
216 /* attempt to find and process the ConfigureNotify event now */
217 if (TSXCheckTypedWindowEvent(display
,((XAnyEvent
*)event
)->window
,
218 ConfigureNotify
, &new_event
)) {
219 EVENT_ProcessEvent( &new_event
);
220 EVENT_Expose( pWnd
, (XExposeEvent
*)event
);
224 /* no luck at this time, defer Expose event for later */
225 if (!pWnd
->expose_event
) pWnd
->expose_event
= malloc( sizeof(XExposeEvent
) );
226 else { FIXME(x11
,"can't handle more than one deferred Expose events\n"); }
227 *(pWnd
->expose_event
) = *(XExposeEvent
*)event
;
233 EVENT_GraphicsExpose( pWnd
, (XGraphicsExposeEvent
*)event
);
236 case ConfigureNotify
:
238 EVENT_ConfigureNotify( pWnd
, (XConfigureEvent
*)event
);
239 if (pWnd
->expose_event
) {
240 /* process deferred Expose event */
241 EVENT_Expose( pWnd
, pWnd
->expose_event
);
242 free( pWnd
->expose_event
);
243 pWnd
->expose_event
= NULL
;
247 case SelectionRequest
:
249 EVENT_SelectionRequest( pWnd
, (XSelectionRequestEvent
*)event
);
252 case SelectionNotify
:
254 EVENT_SelectionNotify( (XSelectionEvent
*)event
);
259 EVENT_SelectionClear( pWnd
, (XSelectionClearEvent
*) event
);
264 EVENT_ClientMessage( pWnd
, (XClientMessageEvent
*) event
);
268 * EVENT_EnterNotify( pWnd, (XCrossingEvent *) event );
274 /* We get all these because of StructureNotifyMask. */
276 case CirculateNotify
:
285 EVENT_MapNotify( pWnd
->hwndSelf
, (XMapEvent
*)event
);
289 WARN(event
, "Unprocessed event %s for hwnd %04x\n",
290 event_names
[event
->type
], pWnd
? pWnd
->hwndSelf
: 0 );
296 /***********************************************************************
297 * EVENT_RegisterWindow
299 * Associate an X window to a HWND.
301 void EVENT_RegisterWindow( WND
*pWnd
)
303 if (wmProtocols
== None
)
304 wmProtocols
= TSXInternAtom( display
, "WM_PROTOCOLS", True
);
305 if (wmDeleteWindow
== None
)
306 wmDeleteWindow
= TSXInternAtom( display
, "WM_DELETE_WINDOW", True
);
307 if( dndProtocol
== None
)
308 dndProtocol
= TSXInternAtom( display
, "DndProtocol" , False
);
309 if( dndSelection
== None
)
310 dndSelection
= TSXInternAtom( display
, "DndSelection" , False
);
312 TSXSetWMProtocols( display
, pWnd
->window
, &wmDeleteWindow
, 1 );
314 if (!winContext
) winContext
= TSXUniqueContext();
315 TSXSaveContext( display
, pWnd
->window
, winContext
, (char *)pWnd
);
318 /***********************************************************************
319 * EVENT_DestroyWindow
321 void EVENT_DestroyWindow( WND
*pWnd
)
325 if (pWnd
->expose_event
) {
326 free( pWnd
->expose_event
);
327 pWnd
->expose_event
= NULL
;
329 TSXDeleteContext( display
, pWnd
->window
, winContext
);
330 TSXDestroyWindow( display
, pWnd
->window
);
331 while( TSXCheckWindowEvent(display
, pWnd
->window
, NoEventMask
, &xe
) );
335 /***********************************************************************
336 * IsUserIdle (USER.333)
338 * Check if we have pending X events.
340 BOOL16 WINAPI
IsUserIdle(void)
342 struct timeval timeout
= {0, 0};
346 FD_SET(__event_x_connection
, &check_set
);
347 if( select(__event_x_connection
+ 1, &check_set
, NULL
, NULL
, &timeout
) > 0 )
353 /***********************************************************************
356 * Wait for a network event, optionally sleeping until one arrives.
357 * Return TRUE if an event is pending, FALSE on timeout or error
358 * (for instance lost connection with the server).
360 BOOL32
EVENT_WaitNetEvent( BOOL32 sleep
, BOOL32 peek
)
363 LONG maxWait
= sleep
? TIMER_GetNextExpiration() : 0;
364 int pending
= TSXPending(display
);
366 /* Wait for an event or a timeout. If maxWait is -1, we have no timeout;
367 * in this case, we fall through directly to the XNextEvent loop.
370 if ((maxWait
!= -1) && !pending
)
373 struct timeval timeout
;
376 memcpy( io_set
, __event_io_set
, sizeof(io_set
) );
378 timeout
.tv_usec
= (maxWait
% 1000) * 1000;
379 timeout
.tv_sec
= maxWait
/ 1000;
382 sigsetjmp(env_wait_x
, 1);
385 if (DDE_GetRemoteMessage()) {
386 while(DDE_GetRemoteMessage())
390 stop_wait_op
= STOP_WAIT_X
;
391 /* The code up to the next "stop_wait_op = CONT" must be reentrant */
392 num_pending
= select( __event_max_fd
, &io_set
[EVENT_IO_READ
],
393 &io_set
[EVENT_IO_WRITE
],
394 &io_set
[EVENT_IO_EXCEPT
], &timeout
);
395 if ( num_pending
== 0 )
398 TIMER_ExpireTimers();
401 else stop_wait_op
= CONT
;
402 #else /* CONFIG_IPC */
403 num_pending
= select( __event_max_fd
, &io_set
[EVENT_IO_READ
],
404 &io_set
[EVENT_IO_WRITE
],
405 &io_set
[EVENT_IO_EXCEPT
], &timeout
);
406 if ( num_pending
== 0)
408 /* Timeout or error */
409 TIMER_ExpireTimers();
412 #endif /* CONFIG_IPC */
414 /* Winsock asynchronous services */
416 if( FD_ISSET( __event_x_connection
, &io_set
[EVENT_IO_READ
]) )
420 WINSOCK_HandleIO( &__event_max_fd
, num_pending
, io_set
, __event_io_set
);
422 else /* no X events */
423 return WINSOCK_HandleIO( &__event_max_fd
, num_pending
, io_set
, __event_io_set
);
426 { /* Wait for X11 input. */
430 FD_SET(__event_x_connection
, &set
);
431 select(__event_x_connection
+ 1, &set
, 0, 0, 0 );
434 /* Process current X event (and possibly others that occurred in the meantime) */
436 EnterCriticalSection(&X11DRV_CritSection
);
437 while (XPending( display
))
441 if (DDE_GetRemoteMessage())
443 LeaveCriticalSection(&X11DRV_CritSection
);
444 while(DDE_GetRemoteMessage()) ;
447 #endif /* CONFIG_IPC */
449 XNextEvent( display
, &event
);
451 LeaveCriticalSection(&X11DRV_CritSection
);
458 /* Check only for those events which can be processed
461 if( event
.type
== MotionNotify
||
462 event
.type
== ButtonPress
|| event
.type
== ButtonRelease
||
463 event
.type
== KeyPress
|| event
.type
== KeyRelease
||
464 event
.type
== SelectionRequest
|| event
.type
== SelectionClear
||
465 event
.type
== ClientMessage
)
467 EVENT_ProcessEvent( &event
);
471 if (TSXFindContext( display
, ((XAnyEvent
*)&event
)->window
, winContext
,
472 (char **)&pWnd
) || (event
.type
== NoExpose
))
477 if( (pQ
= (MESSAGEQUEUE
*)GlobalLock16(pWnd
->hmemTaskQ
)) )
479 pQ
->flags
|= QUEUE_FLAG_XEVENT
;
480 PostEvent(pQ
->hTask
);
481 TSXPutBackEvent(display
, &event
);
486 else EVENT_ProcessEvent( &event
);
487 EnterCriticalSection(&X11DRV_CritSection
);
489 LeaveCriticalSection(&X11DRV_CritSection
);
494 /***********************************************************************
497 * Synchronize with the X server. Should not be used too often.
499 void EVENT_Synchronize()
503 /* Use of the X critical section is needed or we have a small
504 * race between XPending() and XNextEvent().
506 EnterCriticalSection( &X11DRV_CritSection
);
507 XSync( display
, False
);
508 while (XPending( display
))
510 XNextEvent( display
, &event
);
511 /* unlock X critsection for EVENT_ProcessEvent() might switch tasks */
512 LeaveCriticalSection( &X11DRV_CritSection
);
513 EVENT_ProcessEvent( &event
);
514 EnterCriticalSection( &X11DRV_CritSection
);
516 LeaveCriticalSection( &X11DRV_CritSection
);
519 /***********************************************************************
522 * Try to synchronize internal z-order with the window manager's.
523 * Probably a futile endeavor.
525 static BOOL32
__check_query_condition( WND
** pWndA
, WND
** pWndB
)
527 /* return TRUE if we have at least two managed windows */
529 for( *pWndB
= NULL
; *pWndA
; *pWndA
= (*pWndA
)->next
)
530 if( (*pWndA
)->flags
& WIN_MANAGED
&&
531 (*pWndA
)->dwStyle
& WS_VISIBLE
) break;
533 for( *pWndB
= (*pWndA
)->next
; *pWndB
; *pWndB
= (*pWndB
)->next
)
534 if( (*pWndB
)->flags
& WIN_MANAGED
&&
535 (*pWndB
)->dwStyle
& WS_VISIBLE
) break;
536 return ((*pWndB
) != NULL
);
539 static Window
__get_common_ancestor( Window A
, Window B
,
540 Window
** children
, unsigned* total
)
542 /* find the real root window */
544 Window root
, *childrenB
;
549 if( *children
) TSXFree( *children
);
550 TSXQueryTree( display
, A
, &root
, &A
, children
, total
);
551 TSXQueryTree( display
, B
, &root
, &B
, &childrenB
, &totalB
);
552 if( childrenB
) TSXFree( childrenB
);
553 } while( A
!= B
&& A
&& B
);
554 return ( A
&& B
) ? A
: 0 ;
557 static Window
__get_top_decoration( Window w
, Window ancestor
)
559 Window
* children
, root
, prev
= w
, parent
= w
;
565 TSXQueryTree( display
, w
, &root
, &parent
, &children
, &total
);
566 if( children
) TSXFree( children
);
567 } while( parent
&& parent
!= ancestor
);
568 TRACE(event
, "\t%08x -> %08x\n", (unsigned)prev
, (unsigned)w
);
569 return ( parent
) ? w
: 0 ;
572 static unsigned __td_lookup( Window w
, Window
* list
, unsigned max
)
575 for( i
= 0; i
< max
; i
++ ) if( list
[i
] == w
) break;
579 static BOOL32
EVENT_QueryZOrder( WND
* pWndCheck
)
582 HWND32 hwndInsertAfter
= HWND_TOP
;
583 WND
* pWnd
, *pWndZ
= WIN_GetDesktop()->child
;
584 Window w
, parent
, *children
= NULL
;
585 unsigned total
, check
, pos
, best
;
587 if( !__check_query_condition(&pWndZ
, &pWnd
) ) return TRUE
;
589 parent
= __get_common_ancestor( pWndZ
->window
, pWnd
->window
,
591 if( parent
&& children
)
593 w
= __get_top_decoration( pWndCheck
->window
, parent
);
594 if( w
!= children
[total
- 1] )
596 check
= __td_lookup( w
, children
, total
);
598 for( pWnd
= pWndZ
; pWnd
; pWnd
= pWnd
->next
)
600 if( pWnd
!= pWndCheck
)
602 if( !(pWnd
->flags
& WIN_MANAGED
) ||
603 !(w
= __get_top_decoration( pWnd
->window
, parent
)) )
605 pos
= __td_lookup( w
, children
, total
);
606 if( pos
< best
&& pos
> check
)
609 hwndInsertAfter
= pWnd
->hwndSelf
;
611 if( check
- best
== 1 ) break;
614 WIN_UnlinkWindow( pWndCheck
->hwndSelf
);
615 WIN_LinkWindow( pWndCheck
->hwndSelf
, hwndInsertAfter
);
618 if( children
) TSXFree( children
);
623 /***********************************************************************
624 * EVENT_XStateToKeyState
626 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
627 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
629 static WORD
EVENT_XStateToKeyState( int state
)
633 if (state
& Button1Mask
) kstate
|= MK_LBUTTON
;
634 if (state
& Button2Mask
) kstate
|= MK_MBUTTON
;
635 if (state
& Button3Mask
) kstate
|= MK_RBUTTON
;
636 if (state
& ShiftMask
) kstate
|= MK_SHIFT
;
637 if (state
& ControlMask
) kstate
|= MK_CONTROL
;
641 /***********************************************************************
644 BOOL32
EVENT_QueryPointer( DWORD
*posX
, DWORD
*posY
, DWORD
*state
)
647 int rootX
, rootY
, winX
, winY
;
650 if (!TSXQueryPointer( display
, rootWindow
, &root
, &child
,
651 &rootX
, &rootY
, &winX
, &winY
, &xstate
))
656 *state
= EVENT_XStateToKeyState( xstate
);
661 /***********************************************************************
664 static int EVENT_Expose( WND
*pWnd
, XExposeEvent
*event
)
668 unsigned int width
, height
;
670 /* When scrolling, many (fvwm2-based) window managers send the Expose
671 * event before sending the ConfigureNotify event, and we don't like
672 * that, so before processing the Expose event, we check whether the
673 * geometry has changed, and if so, we defer the Expose event until
674 * we get the ConfigureNotify event. -Ove KÃ¥ven */
675 EVENT_GetGeometry( event
->window
, &x
, &y
, &width
, &height
);
677 if ( x
!= pWnd
->rectWindow
.left
|| y
!= pWnd
->rectWindow
.top
||
678 (width
!= pWnd
->rectWindow
.right
- pWnd
->rectWindow
.left
) ||
679 (height
!= pWnd
->rectWindow
.bottom
- pWnd
->rectWindow
.top
))
680 return 1; /* tell EVENT_ProcessEvent() to defer it */
682 /* Make position relative to client area instead of window */
683 rect
.left
= event
->x
- (pWnd
->rectClient
.left
- pWnd
->rectWindow
.left
);
684 rect
.top
= event
->y
- (pWnd
->rectClient
.top
- pWnd
->rectWindow
.top
);
685 rect
.right
= rect
.left
+ event
->width
;
686 rect
.bottom
= rect
.top
+ event
->height
;
688 PAINT_RedrawWindow( pWnd
->hwndSelf
, &rect
, 0,
689 RDW_INVALIDATE
| RDW_FRAME
| RDW_ALLCHILDREN
| RDW_ERASE
|
690 (event
->count
? 0 : RDW_ERASENOW
), 0 );
695 /***********************************************************************
696 * EVENT_GraphicsExpose
698 * This is needed when scrolling area is partially obscured
699 * by non-Wine X window.
701 static void EVENT_GraphicsExpose( WND
*pWnd
, XGraphicsExposeEvent
*event
)
705 /* Make position relative to client area instead of window */
706 rect
.left
= event
->x
- (pWnd
->rectClient
.left
- pWnd
->rectWindow
.left
);
707 rect
.top
= event
->y
- (pWnd
->rectClient
.top
- pWnd
->rectWindow
.top
);
708 rect
.right
= rect
.left
+ event
->width
;
709 rect
.bottom
= rect
.top
+ event
->height
;
711 PAINT_RedrawWindow( pWnd
->hwndSelf
, &rect
, 0,
712 RDW_INVALIDATE
| RDW_ALLCHILDREN
| RDW_ERASE
|
713 (event
->count
? 0 : RDW_ERASENOW
), 0 );
717 /***********************************************************************
720 * Handle a X key event
722 static void EVENT_Key( WND
*pWnd
, XKeyEvent
*event
)
724 KEYBOARD_HandleEvent( pWnd
, event
);
728 /***********************************************************************
731 static void EVENT_MotionNotify( WND
*pWnd
, XMotionEvent
*event
)
733 int xOffset
= pWnd
? pWnd
->rectWindow
.left
: 0;
734 int yOffset
= pWnd
? pWnd
->rectWindow
.top
: 0;
736 MOUSE_SendEvent( MOUSEEVENTF_MOVE
,
737 xOffset
+ event
->x
, yOffset
+ event
->y
,
738 EVENT_XStateToKeyState( event
->state
),
739 event
->time
- MSG_WineStartTicks
,
740 pWnd
? pWnd
->hwndSelf
: 0 );
744 /***********************************************************************
745 * EVENT_DummyMotionNotify
747 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
749 void EVENT_DummyMotionNotify(void)
751 DWORD winX
, winY
, state
;
753 if ( EVENT_QueryPointer( &winX
, &winY
, &state
) )
755 MOUSE_SendEvent( MOUSEEVENTF_MOVE
, winX
, winY
, state
,
761 /***********************************************************************
764 static void EVENT_ButtonPress( WND
*pWnd
, XButtonEvent
*event
)
766 static WORD statusCodes
[NB_BUTTONS
] =
767 { MOUSEEVENTF_LEFTDOWN
, MOUSEEVENTF_MIDDLEDOWN
, MOUSEEVENTF_RIGHTDOWN
};
768 int buttonNum
= event
->button
- 1;
770 int xOffset
= pWnd
? pWnd
->rectWindow
.left
: 0;
771 int yOffset
= pWnd
? pWnd
->rectWindow
.top
: 0;
773 if (buttonNum
>= NB_BUTTONS
) return;
775 MOUSE_SendEvent( statusCodes
[buttonNum
],
776 xOffset
+ event
->x
, yOffset
+ event
->y
,
777 EVENT_XStateToKeyState( event
->state
),
778 event
->time
- MSG_WineStartTicks
,
779 pWnd
? pWnd
->hwndSelf
: 0 );
783 /***********************************************************************
784 * EVENT_ButtonRelease
786 static void EVENT_ButtonRelease( WND
*pWnd
, XButtonEvent
*event
)
788 static WORD statusCodes
[NB_BUTTONS
] =
789 { MOUSEEVENTF_LEFTUP
, MOUSEEVENTF_MIDDLEUP
, MOUSEEVENTF_RIGHTUP
};
790 int buttonNum
= event
->button
- 1;
792 int xOffset
= pWnd
? pWnd
->rectWindow
.left
: 0;
793 int yOffset
= pWnd
? pWnd
->rectWindow
.top
: 0;
795 if (buttonNum
>= NB_BUTTONS
) return;
797 MOUSE_SendEvent( statusCodes
[buttonNum
],
798 xOffset
+ event
->x
, yOffset
+ event
->y
,
799 EVENT_XStateToKeyState( event
->state
),
800 event
->time
- MSG_WineStartTicks
,
801 pWnd
? pWnd
->hwndSelf
: 0 );
805 /**********************************************************************
808 static void EVENT_FocusIn( WND
*pWnd
, XFocusChangeEvent
*event
)
810 if (Options
.managed
) EVENT_QueryZOrder( pWnd
);
812 if (event
->detail
!= NotifyPointer
)
814 HWND32 hwnd
= pWnd
->hwndSelf
;
816 if (hwnd
!= GetActiveWindow32())
818 WINPOS_ChangeActiveWindow( hwnd
, FALSE
);
819 KEYBOARD_UpdateState();
821 if ((hwnd
!= GetFocus32()) && !IsChild32( hwnd
, GetFocus32()))
827 /**********************************************************************
830 * Note: only top-level override-redirect windows get FocusOut events.
832 static void EVENT_FocusOut( WND
*pWnd
, XFocusChangeEvent
*event
)
834 if (event
->detail
!= NotifyPointer
)
836 HWND32 hwnd
= pWnd
->hwndSelf
;
838 if (hwnd
== GetActiveWindow32())
839 WINPOS_ChangeActiveWindow( 0, FALSE
);
840 if ((hwnd
== GetFocus32()) || IsChild32( hwnd
, GetFocus32()))
845 /**********************************************************************
848 BOOL32
EVENT_CheckFocus(void)
854 TSXGetInputFocus(display
, &xW
, &state
);
856 TSXFindContext(display
, xW
, winContext
, (char **)&pWnd
) )
862 /**********************************************************************
865 * Helper function for ConfigureNotify handling.
866 * Get the new geometry of a window relative to the root window.
868 static void EVENT_GetGeometry( Window win
, int *px
, int *py
,
869 unsigned int *pwidth
, unsigned int *pheight
)
871 Window root
, parent
, *children
;
873 unsigned int width
, height
, border
, depth
, nb_children
;
875 if (!TSXGetGeometry( display
, win
, &root
, px
, py
, pwidth
, pheight
,
876 &border
, &depth
)) return;
877 if (win
== rootWindow
)
885 if (!TSXQueryTree(display
, win
, &root
, &parent
, &children
, &nb_children
))
888 if (parent
== rootWindow
) break;
890 if (!TSXGetGeometry( display
, win
, &root
, &xpos
, &ypos
,
891 &width
, &height
, &border
, &depth
)) return;
898 /**********************************************************************
899 * EVENT_ConfigureNotify
901 * The ConfigureNotify event is only selected on top-level windows
902 * when the -managed flag is used.
904 static void EVENT_ConfigureNotify( WND
*pWnd
, XConfigureEvent
*event
)
907 RECT32 newWindowRect
, newClientRect
;
908 HRGN32 hrgnOldPos
, hrgnNewPos
;
909 Window above
= event
->above
;
911 unsigned int width
, height
;
913 assert (pWnd
->flags
& WIN_MANAGED
);
915 /* We don't rely on the event geometry info, because it is relative
916 * to parent and not to root, and it may be wrong (XFree sets x,y to 0,0
917 * if the window hasn't moved).
919 EVENT_GetGeometry( event
->window
, &x
, &y
, &width
, &height
);
921 /* Fill WINDOWPOS struct */
922 winpos
.flags
= SWP_NOACTIVATE
| SWP_NOZORDER
;
923 winpos
.hwnd
= pWnd
->hwndSelf
;
929 /* Check for unchanged attributes */
930 if (winpos
.x
== pWnd
->rectWindow
.left
&& winpos
.y
== pWnd
->rectWindow
.top
)
931 winpos
.flags
|= SWP_NOMOVE
;
932 if ((winpos
.cx
== pWnd
->rectWindow
.right
- pWnd
->rectWindow
.left
) &&
933 (winpos
.cy
== pWnd
->rectWindow
.bottom
- pWnd
->rectWindow
.top
))
934 winpos
.flags
|= SWP_NOSIZE
;
937 RECT32 rect
= { 0, 0, pWnd
->rectWindow
.right
- pWnd
->rectWindow
.left
,
938 pWnd
->rectWindow
.bottom
- pWnd
->rectWindow
.top
};
939 DCE_InvalidateDCE( pWnd
, &rect
);
942 /* Send WM_WINDOWPOSCHANGING */
943 SendMessage32A( winpos
.hwnd
, WM_WINDOWPOSCHANGING
, 0, (LPARAM
)&winpos
);
945 /* Calculate new position and size */
946 newWindowRect
.left
= x
;
947 newWindowRect
.right
= x
+ width
;
948 newWindowRect
.top
= y
;
949 newWindowRect
.bottom
= y
+ height
;
951 WINPOS_SendNCCalcSize( winpos
.hwnd
, TRUE
, &newWindowRect
,
952 &pWnd
->rectWindow
, &pWnd
->rectClient
,
953 &winpos
, &newClientRect
);
955 hrgnOldPos
= CreateRectRgnIndirect32( &pWnd
->rectWindow
);
956 hrgnNewPos
= CreateRectRgnIndirect32( &newWindowRect
);
957 CombineRgn32( hrgnOldPos
, hrgnOldPos
, hrgnNewPos
, RGN_DIFF
);
958 DeleteObject32(hrgnOldPos
);
959 DeleteObject32(hrgnNewPos
);
961 /* Set new size and position */
962 pWnd
->rectWindow
= newWindowRect
;
963 pWnd
->rectClient
= newClientRect
;
964 SendMessage32A( winpos
.hwnd
, WM_WINDOWPOSCHANGED
, 0, (LPARAM
)&winpos
);
966 if (!IsWindow32( winpos
.hwnd
)) return;
967 if( above
== None
) /* absolute bottom */
969 WIN_UnlinkWindow( winpos
.hwnd
);
970 WIN_LinkWindow( winpos
.hwnd
, HWND_BOTTOM
);
972 else EVENT_QueryZOrder( pWnd
); /* try to outsmart window manager */
976 /***********************************************************************
977 * EVENT_SelectionRequest
979 static void EVENT_SelectionRequest( WND
*pWnd
, XSelectionRequestEvent
*event
)
981 XSelectionEvent result
;
983 Window request
= event
->requestor
;
985 if(event
->target
== XA_STRING
)
991 rprop
= event
->property
;
993 if(rprop
== None
) rprop
= event
->target
;
995 if(event
->selection
!=XA_PRIMARY
) rprop
= None
;
996 else if(!CLIPBOARD_IsPresent(CF_OEMTEXT
)) rprop
= None
;
999 /* open to make sure that clipboard is available */
1001 BOOL32 couldOpen
= OpenClipboard32( pWnd
->hwndSelf
);
1004 hText
= GetClipboardData16(CF_TEXT
);
1005 text
= GlobalLock16(hText
);
1006 size
= GlobalSize16(hText
);
1008 /* remove carriage returns */
1010 lpstr
= (char*)HEAP_xalloc( GetProcessHeap(), 0, size
-- );
1011 for(i
=0,j
=0; i
< size
&& text
[i
]; i
++ )
1013 if( text
[i
] == '\r' &&
1014 (text
[i
+1] == '\n' || text
[i
+1] == '\0') ) continue;
1015 lpstr
[j
++] = text
[i
];
1019 TSXChangeProperty(display
, request
, rprop
,
1020 XA_STRING
, 8, PropModeReplace
,
1022 HeapFree( GetProcessHeap(), 0, lpstr
);
1024 /* close only if we opened before */
1026 if(couldOpen
) CloseClipboard32();
1031 TRACE(event
,"Request for %s ignored\n", TSXGetAtomName(display
,event
->target
));
1033 result
.type
= SelectionNotify
;
1034 result
.display
= display
;
1035 result
.requestor
= request
;
1036 result
.selection
= event
->selection
;
1037 result
.property
= rprop
;
1038 result
.target
= event
->target
;
1039 result
.time
= event
->time
;
1040 TSXSendEvent(display
,event
->requestor
,False
,NoEventMask
,(XEvent
*)&result
);
1044 /***********************************************************************
1045 * EVENT_SelectionNotify
1047 static void EVENT_SelectionNotify( XSelectionEvent
*event
)
1049 if (event
->selection
!= XA_PRIMARY
) return;
1051 if (event
->target
!= XA_STRING
) CLIPBOARD_ReadSelection( 0, None
);
1052 else CLIPBOARD_ReadSelection( event
->requestor
, event
->property
);
1054 TRACE(clipboard
,"\tSelectionNotify done!\n");
1058 /***********************************************************************
1059 * EVENT_SelectionClear
1061 static void EVENT_SelectionClear( WND
*pWnd
, XSelectionClearEvent
*event
)
1063 if (event
->selection
!= XA_PRIMARY
) return;
1064 CLIPBOARD_ReleaseSelection( event
->window
, pWnd
->hwndSelf
);
1068 /**********************************************************************
1069 * EVENT_DropFromOffix
1071 * don't know if it still works (last Changlog is from 96/11/04)
1073 static void EVENT_DropFromOffiX( WND
*pWnd
, XClientMessageEvent
*event
)
1075 unsigned long data_length
;
1076 unsigned long aux_long
;
1077 unsigned char* p_data
= NULL
;
1085 HGLOBAL16 hDragInfo
= GlobalAlloc16( GMEM_SHARE
| GMEM_ZEROINIT
, sizeof(DRAGINFO
));
1086 LPDRAGINFO lpDragInfo
= (LPDRAGINFO
) GlobalLock16(hDragInfo
);
1087 SEGPTR spDragInfo
= (SEGPTR
) WIN16_GlobalLock16(hDragInfo
);
1088 Window w_aux_root
, w_aux_child
;
1091 if( !lpDragInfo
|| !spDragInfo
) return;
1093 TSXQueryPointer( display
, pWnd
->window
, &w_aux_root
, &w_aux_child
,
1094 &x
, &y
, &u
.pt_aux
.x
, &u
.pt_aux
.y
, (unsigned int*)&aux_long
);
1096 lpDragInfo
->hScope
= pWnd
->hwndSelf
;
1097 lpDragInfo
->pt
.x
= (INT16
)x
; lpDragInfo
->pt
.y
= (INT16
)y
;
1099 /* find out drop point and drop window */
1100 if( x
< 0 || y
< 0 ||
1101 x
> (pWnd
->rectWindow
.right
- pWnd
->rectWindow
.left
) ||
1102 y
> (pWnd
->rectWindow
.bottom
- pWnd
->rectWindow
.top
) )
1103 { bAccept
= pWnd
->dwExStyle
& WS_EX_ACCEPTFILES
; x
= y
= 0; }
1106 bAccept
= DRAG_QueryUpdate( pWnd
->hwndSelf
, spDragInfo
, TRUE
);
1107 x
= lpDragInfo
->pt
.x
; y
= lpDragInfo
->pt
.y
;
1109 pDropWnd
= WIN_FindWndPtr( lpDragInfo
->hScope
);
1110 GlobalFree16( hDragInfo
);
1114 TSXGetWindowProperty( display
, DefaultRootWindow(display
),
1115 dndSelection
, 0, 65535, FALSE
,
1116 AnyPropertyType
, &u
.atom_aux
, &u
.pt_aux
.y
,
1117 &data_length
, &aux_long
, &p_data
);
1119 if( !aux_long
&& p_data
) /* don't bother if > 64K */
1121 char *p
= (char*) p_data
;
1125 while( *p
) /* calculate buffer size */
1128 if((u
.i
= *p
) != -1 )
1129 u
.i
= DRIVE_FindDriveRoot( (const char **)&p_drop
);
1130 if( u
.i
== -1 ) *p
= -1; /* mark as "bad" */
1133 INT32 len
= GetShortPathName32A( p
, NULL
, 0 );
1134 if (len
) aux_long
+= len
+ 1;
1139 if( aux_long
&& aux_long
< 65535 )
1142 LPDROPFILESTRUCT16 lpDrop
;
1144 aux_long
+= sizeof(DROPFILESTRUCT16
) + 1;
1145 hDrop
= (HDROP16
)GlobalAlloc16( GMEM_SHARE
, aux_long
);
1146 lpDrop
= (LPDROPFILESTRUCT16
) GlobalLock16( hDrop
);
1150 lpDrop
->wSize
= sizeof(DROPFILESTRUCT16
);
1151 lpDrop
->ptMousePos
.x
= (INT16
)x
;
1152 lpDrop
->ptMousePos
.y
= (INT16
)y
;
1153 lpDrop
->fInNonClientArea
= (BOOL16
)
1154 ( x
< (pDropWnd
->rectClient
.left
- pDropWnd
->rectWindow
.left
) ||
1155 y
< (pDropWnd
->rectClient
.top
- pDropWnd
->rectWindow
.top
) ||
1156 x
> (pDropWnd
->rectClient
.right
- pDropWnd
->rectWindow
.left
) ||
1157 y
> (pDropWnd
->rectClient
.bottom
- pDropWnd
->rectWindow
.top
) );
1158 p_drop
= ((char*)lpDrop
) + sizeof(DROPFILESTRUCT16
);
1162 if( *p
!= -1 ) /* use only "good" entries */
1164 GetShortPathName32A( p
, p_drop
, 65535 );
1165 p_drop
+= strlen( p_drop
) + 1;
1170 PostMessage16( pWnd
->hwndSelf
, WM_DROPFILES
,
1171 (WPARAM16
)hDrop
, 0L );
1175 if( p_data
) TSXFree(p_data
);
1177 } /* WS_EX_ACCEPTFILES */
1180 /**********************************************************************
1183 * drop items are separated by \n
1184 * each item is prefixed by its mime type
1186 * event->data.l[3], event->data.l[4] contains drop x,y position
1188 static void EVENT_DropURLs( WND
*pWnd
, XClientMessageEvent
*event
)
1191 unsigned long data_length
;
1192 unsigned long aux_long
, drop_len
= 0;
1193 unsigned char *p_data
= NULL
; /* property data */
1194 char *p_drop
= NULL
;
1196 int x
, y
, drop32
= FALSE
;
1208 drop32
= pWnd
->flags
& WIN_ISWIN32
;
1210 if (!(pWnd
->dwExStyle
& WS_EX_ACCEPTFILES
))
1213 TSXGetWindowProperty( display
, DefaultRootWindow(display
),
1214 dndSelection
, 0, 65535, FALSE
,
1215 AnyPropertyType
, &u
.atom_aux
, &u
.i
,
1216 &data_length
, &aux_long
, &p_data
);
1218 WARN(event
,"property too large, truncated!\n");
1219 TRACE(event
,"urls=%s\n", p_data
);
1221 if( !aux_long
&& p_data
) { /* don't bother if > 64K */
1222 /* calculate length */
1224 next
= strchr(p
, '\n');
1227 if (strncmp(p
,"file:",5) == 0 ) {
1228 INT32 len
= GetShortPathName32A( p
+5, NULL
, 0 );
1229 if (len
) drop_len
+= len
+ 1;
1234 next
= strchr(p
, '\n');
1240 if( drop_len
&& drop_len
< 65535 ) {
1241 TSXQueryPointer( display
, rootWindow
, &u
.w_aux
, &u
.w_aux
,
1242 &x
, &y
, &u
.i
, &u
.i
, &u
.i
);
1243 pDropWnd
= WIN_FindWndPtr( pWnd
->hwndSelf
);
1246 LPDROPFILESTRUCT32 lpDrop
;
1247 drop_len
+= sizeof(DROPFILESTRUCT32
) + 1;
1248 hDrop
.h32
= (HDROP32
)GlobalAlloc32( GMEM_SHARE
, drop_len
);
1249 lpDrop
= (LPDROPFILESTRUCT32
) GlobalLock32( hDrop
.h32
);
1252 lpDrop
->lSize
= sizeof(DROPFILESTRUCT32
);
1253 lpDrop
->ptMousePos
.x
= (INT32
)x
;
1254 lpDrop
->ptMousePos
.y
= (INT32
)y
;
1255 lpDrop
->fInNonClientArea
= (BOOL32
)
1256 ( x
< (pDropWnd
->rectClient
.left
- pDropWnd
->rectWindow
.left
) ||
1257 y
< (pDropWnd
->rectClient
.top
- pDropWnd
->rectWindow
.top
) ||
1258 x
> (pDropWnd
->rectClient
.right
- pDropWnd
->rectWindow
.left
) ||
1259 y
> (pDropWnd
->rectClient
.bottom
- pDropWnd
->rectWindow
.top
) );
1260 lpDrop
->fWideChar
= FALSE
;
1261 p_drop
= ((char*)lpDrop
) + sizeof(DROPFILESTRUCT32
);
1264 LPDROPFILESTRUCT16 lpDrop
;
1265 drop_len
+= sizeof(DROPFILESTRUCT16
) + 1;
1266 hDrop
.h16
= (HDROP16
)GlobalAlloc16( GMEM_SHARE
, drop_len
);
1267 lpDrop
= (LPDROPFILESTRUCT16
) GlobalLock16( hDrop
.h16
);
1270 lpDrop
->wSize
= sizeof(DROPFILESTRUCT16
);
1271 lpDrop
->ptMousePos
.x
= (INT16
)x
;
1272 lpDrop
->ptMousePos
.y
= (INT16
)y
;
1273 lpDrop
->fInNonClientArea
= (BOOL16
)
1274 ( x
< (pDropWnd
->rectClient
.left
- pDropWnd
->rectWindow
.left
) ||
1275 y
< (pDropWnd
->rectClient
.top
- pDropWnd
->rectWindow
.top
) ||
1276 x
> (pDropWnd
->rectClient
.right
- pDropWnd
->rectWindow
.left
) ||
1277 y
> (pDropWnd
->rectClient
.bottom
- pDropWnd
->rectWindow
.top
) );
1278 p_drop
= ((char*)lpDrop
) + sizeof(DROPFILESTRUCT16
);
1282 /* create message content */
1285 next
= strchr(p
, '\n');
1288 if (strncmp(p
,"file:",5) == 0 ) {
1289 INT32 len
= GetShortPathName32A( p
+5, p_drop
, 65535 );
1291 TRACE(event
, "drop file %s as %s\n", p
+5, p_drop
);
1294 WARN(event
, "can't convert file %s to dos name \n", p
+5);
1297 WARN(event
, "unknown mime type %s\n", p
);
1302 next
= strchr(p
, '\n');
1310 /* can not use PostMessage32A because it is currently based on
1311 * PostMessage16 and WPARAM32 would be truncated to WPARAM16
1313 GlobalUnlock32(hDrop
.h32
);
1314 SendMessage32A( pWnd
->hwndSelf
, WM_DROPFILES
,
1315 (WPARAM32
)hDrop
.h32
, 0L );
1317 GlobalUnlock16(hDrop
.h16
);
1318 PostMessage16( pWnd
->hwndSelf
, WM_DROPFILES
,
1319 (WPARAM16
)hDrop
.h16
, 0L );
1323 if( p_data
) TSXFree(p_data
);
1327 /**********************************************************************
1328 * EVENT_ClientMessage
1330 static void EVENT_ClientMessage( WND
*pWnd
, XClientMessageEvent
*event
)
1332 if (event
->message_type
!= None
&& event
->format
== 32) {
1333 if ((event
->message_type
== wmProtocols
) &&
1334 (((Atom
) event
->data
.l
[0]) == wmDeleteWindow
))
1335 SendMessage16( pWnd
->hwndSelf
, WM_SYSCOMMAND
, SC_CLOSE
, 0 );
1336 else if ( event
->message_type
== dndProtocol
&&
1337 (event
->data
.l
[0] == DndFile
|| event
->data
.l
[0] == DndFiles
) )
1338 EVENT_DropFromOffiX(pWnd
, event
);
1339 else if ( event
->message_type
== dndProtocol
&&
1340 event
->data
.l
[0] == DndURL
)
1341 EVENT_DropURLs(pWnd
, event
);
1344 /* enable this if you want to see the message */
1345 unsigned char* p_data
= NULL
;
1351 TSXGetWindowProperty( display
, DefaultRootWindow(display
),
1352 dndSelection
, 0, 65535, FALSE
,
1353 AnyPropertyType
, &u
.atom
, &u
.i
,
1354 &u
.l
, &u
.l
, &p_data
);
1355 TRACE(event
, "message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1356 event
->message_type
, event
->data
.l
[0], event
->data
.l
[1],
1357 event
->data
.l
[2], event
->data
.l
[3], event
->data
.l
[4],
1360 TRACE(event
, "unrecognized ClientMessage\n" );
1365 /**********************************************************************
1368 * Install colormap when Wine window is focused in
1369 * self-managed mode with private colormap
1372 void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
1374 if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
1375 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
1376 TSXInstallColormap( display, COLOR_GetColormap() );
1380 /**********************************************************************
1383 void EVENT_MapNotify( HWND32 hWnd
, XMapEvent
*event
)
1385 HWND32 hwndFocus
= GetFocus32();
1387 if (hwndFocus
&& IsChild32( hWnd
, hwndFocus
))
1388 FOCUS_SetXFocus( (HWND32
)hwndFocus
);