4 * Copyright 1993 Alexandre Julliard
10 #include <X11/Xatom.h>
11 #include <X11/keysym.h>
14 #include "ts_xresource.h"
19 #ifdef HAVE_LIBXXF86DGA2
20 #include "ts_xf86dga2.h"
25 #include "wine/winuser16.h"
26 #include "shlobj.h" /* DROPFILES */
28 #include "clipboard.h"
30 #include "debugtools.h"
45 DEFAULT_DEBUG_CHANNEL(event
);
46 DECLARE_DEBUG_CHANNEL(win
);
48 /* X context to associate a hwnd to an X window */
49 extern XContext winContext
;
51 extern Atom wmProtocols
;
52 extern Atom wmDeleteWindow
;
53 extern Atom dndProtocol
;
54 extern Atom dndSelection
;
56 extern void X11DRV_KEYBOARD_UpdateState(void);
57 extern void X11DRV_KEYBOARD_HandleEvent(WND
*pWnd
, XKeyEvent
*event
);
59 #define NB_BUTTONS 5 /* Windows can handle 3 buttons and the wheel too */
62 #define DndNotDnd -1 /* OffiX drag&drop */
74 #define DndURL 128 /* KDE drag&drop */
76 /* The last X window which had the focus */
77 static Window glastXFocusWin
= 0;
79 static const char * const event_names
[] =
81 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
82 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
83 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
84 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
85 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
86 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
87 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
88 "ClientMessage", "MappingNotify"
92 static void CALLBACK
EVENT_Flush( ULONG_PTR arg
);
93 static void CALLBACK
EVENT_ProcessAllEvents( ULONG_PTR arg
);
94 static void EVENT_ProcessEvent( XEvent
*event
);
95 BOOL
X11DRV_CheckFocus(void);
98 static void EVENT_Key( HWND hWnd
, XKeyEvent
*event
);
99 static void EVENT_ButtonPress( HWND hWnd
, XButtonEvent
*event
);
100 static void EVENT_ButtonRelease( HWND hWnd
, XButtonEvent
*event
);
101 static void EVENT_MotionNotify( HWND hWnd
, XMotionEvent
*event
);
102 static void EVENT_FocusIn( HWND hWnd
, XFocusChangeEvent
*event
);
103 static void EVENT_FocusOut( HWND hWnd
, XFocusChangeEvent
*event
);
104 static void EVENT_Expose( HWND hWnd
, XExposeEvent
*event
);
105 static void EVENT_GraphicsExpose( HWND hWnd
, XGraphicsExposeEvent
*event
);
106 static void EVENT_ConfigureNotify( HWND hWnd
, XConfigureEvent
*event
);
107 static void EVENT_SelectionRequest( HWND hWnd
, XSelectionRequestEvent
*event
, BOOL bIsMultiple
);
108 static void EVENT_SelectionClear( HWND hWnd
, XSelectionClearEvent
*event
);
109 static void EVENT_PropertyNotify( XPropertyEvent
*event
);
110 static void EVENT_ClientMessage( HWND hWnd
, XClientMessageEvent
*event
);
111 static void EVENT_MapNotify( HWND pWnd
, XMapEvent
*event
);
112 static void EVENT_UnmapNotify( HWND pWnd
, XUnmapEvent
*event
);
113 static void EVENT_MappingNotify( XMappingEvent
*event
);
116 static void EVENT_ShmCompletion( XShmCompletionEvent
*event
);
117 static int ShmAvailable
, ShmCompletionType
;
118 extern int XShmGetEventBase( Display
* );/* Missing prototype for function in libXext. */
121 #ifdef HAVE_LIBXXF86DGA2
122 static int DGAMotionEventType
;
123 static int DGAButtonPressEventType
;
124 static int DGAButtonReleaseEventType
;
125 static int DGAKeyPressEventType
;
126 static int DGAKeyReleaseEventType
;
128 static BOOL DGAUsed
= FALSE
;
129 static HWND DGAhwnd
= 0;
131 static void EVENT_DGAMotionEvent( XDGAMotionEvent
*event
);
132 static void EVENT_DGAButtonPressEvent( XDGAButtonEvent
*event
);
133 static void EVENT_DGAButtonReleaseEvent( XDGAButtonEvent
*event
);
136 /* Usable only with OLVWM - compile option perhaps?
137 static void EVENT_EnterNotify( HWND hWnd, XCrossingEvent *event );
140 static void EVENT_GetGeometry( Window win
, int *px
, int *py
,
141 unsigned int *pwidth
, unsigned int *pheight
);
144 static BOOL bUserRepaintDisabled
= TRUE
;
146 /* Static used for the current input method */
147 static INPUT_TYPE current_input_type
= X11DRV_INPUT_ABSOLUTE
;
148 static BOOL in_transition
= FALSE
; /* This is not used as for today */
150 /***********************************************************************
153 BOOL
X11DRV_EVENT_Init(void)
156 ShmAvailable
= XShmQueryExtension( display
);
158 ShmCompletionType
= XShmGetEventBase( display
) + ShmCompletion
;
162 /* Install the X event processing callback */
163 SERVICE_AddObject( FILE_DupUnixHandle( ConnectionNumber(display
),
164 GENERIC_READ
| SYNCHRONIZE
),
165 EVENT_ProcessAllEvents
, 0 );
167 /* Install the XFlush timer callback */
168 if ( Options
.synchronous
)
169 TSXSynchronize( display
, True
);
171 SERVICE_AddTimer( 200, EVENT_Flush
, 0 );
176 /***********************************************************************
179 static void CALLBACK
EVENT_Flush( ULONG_PTR arg
)
184 /***********************************************************************
185 * EVENT_ProcessAllEvents
187 static void CALLBACK
EVENT_ProcessAllEvents( ULONG_PTR arg
)
191 TRACE( "called (thread %lx).\n", GetCurrentThreadId() );
193 EnterCriticalSection( &X11DRV_CritSection
);
194 while ( XPending( display
) )
196 XNextEvent( display
, &event
);
198 LeaveCriticalSection( &X11DRV_CritSection
);
199 EVENT_ProcessEvent( &event
);
200 EnterCriticalSection( &X11DRV_CritSection
);
202 LeaveCriticalSection( &X11DRV_CritSection
);
205 /***********************************************************************
208 * Synchronize with the X server. Should not be used too often.
210 void X11DRV_Synchronize( void )
212 TSXSync( display
, False
);
213 EVENT_ProcessAllEvents( 0 );
216 /***********************************************************************
217 * X11DRV_UserRepaintDisable
219 void X11DRV_UserRepaintDisable( BOOL bDisabled
)
221 bUserRepaintDisabled
= bDisabled
;
224 /***********************************************************************
227 * Process an X event.
229 static void EVENT_ProcessEvent( XEvent
*event
)
233 TRACE( "called.\n" );
237 case SelectionNotify
: /* all of these should be caught by XCheckTypedWindowEvent() */
238 FIXME("Got SelectionNotify - must not happen!\n");
241 /* We get all these because of StructureNotifyMask.
242 This check is placed here to avoid getting error messages below,
243 as X might send some of these even for windows that have already
245 case CirculateNotify
:
254 if (ShmAvailable
&& (event
->type
== ShmCompletionType
)) {
255 EVENT_ShmCompletion( (XShmCompletionEvent
*)event
);
260 #ifdef HAVE_LIBXXF86DGA2
262 if (event
->type
== DGAMotionEventType
) {
263 TRACE("DGAMotionEvent received.\n");
264 EVENT_DGAMotionEvent((XDGAMotionEvent
*) event
);
267 if (event
->type
== DGAButtonPressEventType
) {
268 TRACE("DGAButtonPressEvent received.\n");
269 EVENT_DGAButtonPressEvent((XDGAButtonEvent
*) event
);
272 if (event
->type
== DGAButtonReleaseEventType
) {
273 TRACE("DGAButtonReleaseEvent received.\n");
274 EVENT_DGAButtonReleaseEvent((XDGAButtonEvent
*) event
);
277 if ((event
->type
== DGAKeyPressEventType
) ||
278 (event
->type
== DGAKeyReleaseEventType
)) {
279 /* Fill a XKeyEvent to send to EVENT_Key */
281 XDGAKeyEvent
*evt
= (XDGAKeyEvent
*) event
;
283 TRACE("DGAKeyPress/ReleaseEvent received.\n");
285 if (evt
->type
== DGAKeyReleaseEventType
)
286 ke
.type
= KeyRelease
;
289 ke
.serial
= evt
->serial
;
290 ke
.send_event
= FALSE
;
291 ke
.display
= evt
->display
;
300 ke
.state
= evt
->state
;
301 ke
.keycode
= evt
->keycode
;
302 ke
.same_screen
= TRUE
;
304 X11DRV_KEYBOARD_HandleEvent(NULL
, &ke
);
310 if ( TSXFindContext( display
, event
->xany
.window
, winContext
,
311 (char **)&hWnd
) != 0) {
312 if ( event
->type
== ClientMessage
) {
313 /* query window (drag&drop event contains only drag window) */
315 int root_x
, root_y
, child_x
, child_y
;
317 TSXQueryPointer( display
, X11DRV_GetXRootWindow(), &root
, &child
,
318 &root_x
, &root_y
, &child_x
, &child_y
, &u
);
319 if (TSXFindContext( display
, child
, winContext
, (char **)&hWnd
) != 0)
322 hWnd
= 0; /* Not for a registered window */
326 if ( !hWnd
&& event
->xany
.window
!= X11DRV_GetXRootWindow()
327 && event
->type
!= PropertyNotify
328 && event
->type
!= MappingNotify
)
329 ERR("Got event %s for unknown Window %08lx\n",
330 event_names
[event
->type
], event
->xany
.window
);
332 TRACE("Got event %s for hwnd %04x\n",
333 event_names
[event
->type
], hWnd
);
339 EVENT_Key( hWnd
, (XKeyEvent
*)event
);
343 EVENT_ButtonPress( hWnd
, (XButtonEvent
*)event
);
347 EVENT_ButtonRelease( hWnd
, (XButtonEvent
*)event
);
351 /* Wine between two fast machines across the overloaded campus
352 ethernet gets very boged down in MotionEvents. The following
353 simply finds the last motion event in the queue and drops
354 the rest. On a good link events are servered before they build
355 up so this doesn't take place. On a slow link this may cause
356 problems if the event order is important. I'm not yet seen
357 of any problems. Jon 7/6/96.
359 if ((current_input_type
== X11DRV_INPUT_ABSOLUTE
) &&
360 (in_transition
== FALSE
))
361 /* Only cumulate events if in absolute mode */
362 while (TSXCheckTypedWindowEvent(display
,((XAnyEvent
*)event
)->window
,
363 MotionNotify
, event
));
364 EVENT_MotionNotify( hWnd
, (XMotionEvent
*)event
);
369 WND
*pWndLastFocus
= 0;
370 XWindowAttributes win_attr
;
372 XFocusChangeEvent
*xfocChange
= (XFocusChangeEvent
*)event
;
374 if (!hWnd
|| bUserRepaintDisabled
) return;
376 bIsDisabled
= GetWindowLongA( hWnd
, GWL_STYLE
) & WS_DISABLED
;
378 /* If the window has been disabled and we are in managed mode,
379 * revert the X focus back to the last focus window. This is to disallow
380 * the window manager from switching focus away while the app is
383 if ( Options
.managed
&& bIsDisabled
&& glastXFocusWin
)
385 /* Change focus only if saved focus window is registered and viewable */
386 if ( TSXFindContext( xfocChange
->display
, glastXFocusWin
, winContext
,
387 (char **)&pWndLastFocus
) == 0 )
389 if ( TSXGetWindowAttributes( display
, glastXFocusWin
, &win_attr
) &&
390 (win_attr
.map_state
== IsViewable
) )
392 TSXSetInputFocus( xfocChange
->display
, glastXFocusWin
, RevertToParent
, CurrentTime
);
399 EVENT_FocusIn( hWnd
, xfocChange
);
405 /* Save the last window which had the focus */
406 XFocusChangeEvent
*xfocChange
= (XFocusChangeEvent
*)event
;
407 glastXFocusWin
= xfocChange
->window
;
408 if (!hWnd
|| bUserRepaintDisabled
) return;
409 if (GetWindowLongA( hWnd
, GWL_STYLE
) & WS_DISABLED
) glastXFocusWin
= 0;
410 EVENT_FocusOut( hWnd
, (XFocusChangeEvent
*)event
);
415 if (bUserRepaintDisabled
) return;
416 EVENT_Expose( hWnd
, (XExposeEvent
*)event
);
420 if (bUserRepaintDisabled
) return;
421 EVENT_GraphicsExpose( hWnd
, (XGraphicsExposeEvent
*)event
);
424 case ConfigureNotify
:
425 if (!hWnd
|| bUserRepaintDisabled
) return;
426 EVENT_ConfigureNotify( hWnd
, (XConfigureEvent
*)event
);
429 case SelectionRequest
:
430 if (!hWnd
|| bUserRepaintDisabled
) return;
431 EVENT_SelectionRequest( hWnd
, (XSelectionRequestEvent
*)event
, FALSE
);
435 if (!hWnd
|| bUserRepaintDisabled
) return;
436 EVENT_SelectionClear( hWnd
, (XSelectionClearEvent
*) event
);
440 EVENT_PropertyNotify( (XPropertyEvent
*)event
);
444 if (!hWnd
|| bUserRepaintDisabled
) return;
445 EVENT_ClientMessage( hWnd
, (XClientMessageEvent
*) event
);
450 EVENT_EnterNotify( hWnd
, (XCrossingEvent
*) event
);
458 if (!hWnd
|| bUserRepaintDisabled
) return;
459 EVENT_MapNotify( hWnd
, (XMapEvent
*)event
);
463 if (!hWnd
|| bUserRepaintDisabled
) return;
464 EVENT_UnmapNotify( hWnd
, (XUnmapEvent
*)event
);
468 EVENT_MappingNotify( (XMappingEvent
*) event
);
472 WARN("Unprocessed event %s for hwnd %04x\n",
473 event_names
[event
->type
], hWnd
);
476 TRACE( "returns.\n" );
479 /***********************************************************************
482 * Synchronize internal z-order with the window manager's.
484 static BOOL
__check_query_condition( WND
** pWndA
, WND
** pWndB
)
486 /* return TRUE if we have at least two managed windows */
488 for( *pWndB
= NULL
; *pWndA
; *pWndA
= (*pWndA
)->next
)
489 if( ((*pWndA
)->dwExStyle
& WS_EX_MANAGED
) &&
490 ((*pWndA
)->dwStyle
& WS_VISIBLE
)) break;
492 for( *pWndB
= (*pWndA
)->next
; *pWndB
; *pWndB
= (*pWndB
)->next
)
493 if( ((*pWndB
)->dwExStyle
& WS_EX_MANAGED
) &&
494 ((*pWndB
)->dwStyle
& WS_VISIBLE
)) break;
495 return ((*pWndB
) != NULL
);
498 static Window
__get_common_ancestor( Window A
, Window B
,
499 Window
** children
, unsigned* total
)
501 /* find the real root window */
503 Window root
, *childrenB
;
508 TSXQueryTree( display
, A
, &root
, &A
, children
, total
);
509 TSXQueryTree( display
, B
, &root
, &B
, &childrenB
, &totalB
);
510 if( childrenB
) TSXFree( childrenB
);
511 if( *children
) TSXFree( *children
), *children
= NULL
;
512 } while( A
!= B
&& A
&& B
);
516 TSXQueryTree( display
, A
, &root
, &B
, children
, total
);
522 static Window
__get_top_decoration( Window w
, Window ancestor
)
524 Window
* children
, root
, prev
= w
, parent
= w
;
530 TSXQueryTree( display
, w
, &root
, &parent
, &children
, &total
);
531 if( children
) TSXFree( children
);
532 } while( parent
&& parent
!= ancestor
);
533 TRACE("\t%08x -> %08x\n", (unsigned)prev
, (unsigned)w
);
534 return ( parent
) ? w
: 0 ;
537 static unsigned __td_lookup( Window w
, Window
* list
, unsigned max
)
540 for( i
= max
- 1; i
>= 0; i
-- ) if( list
[i
] == w
) break;
544 static HWND
EVENT_QueryZOrder( HWND hWndCheck
)
546 HWND hwndInsertAfter
= HWND_TOP
;
547 WND
*pWndCheck
= WIN_FindWndPtr(hWndCheck
);
548 WND
*pDesktop
= WIN_GetDesktop();
549 WND
*pWnd
, *pWndZ
= WIN_LockWndPtr(pDesktop
->child
);
550 Window w
, parent
, *children
= NULL
;
551 unsigned total
, check
, pos
, best
;
553 if( !__check_query_condition(&pWndZ
, &pWnd
) )
555 WIN_ReleaseWndPtr(pWndCheck
);
556 WIN_ReleaseWndPtr(pDesktop
->child
);
557 WIN_ReleaseDesktop();
558 return hwndInsertAfter
;
560 WIN_LockWndPtr(pWndZ
);
561 WIN_LockWndPtr(pWnd
);
562 WIN_ReleaseWndPtr(pDesktop
->child
);
563 WIN_ReleaseDesktop();
565 parent
= __get_common_ancestor( X11DRV_WND_GetXWindow(pWndZ
),
566 X11DRV_WND_GetXWindow(pWnd
),
568 if( parent
&& children
)
570 /* w is the ancestor if pWndCheck that is a direct descendant of 'parent' */
572 w
= __get_top_decoration( X11DRV_WND_GetXWindow(pWndCheck
), parent
);
574 if( w
!= children
[total
-1] ) /* check if at the top */
576 /* X child at index 0 is at the bottom, at index total-1 is at the top */
577 check
= __td_lookup( w
, children
, total
);
580 for( WIN_UpdateWndPtr(&pWnd
,pWndZ
); pWnd
;WIN_UpdateWndPtr(&pWnd
,pWnd
->next
))
582 /* go through all windows in Wine z-order... */
584 if( pWnd
!= pWndCheck
)
586 if( !(pWnd
->dwExStyle
& WS_EX_MANAGED
) ||
587 !(w
= __get_top_decoration( X11DRV_WND_GetXWindow(pWnd
), parent
)) )
589 pos
= __td_lookup( w
, children
, total
);
590 if( pos
< best
&& pos
> check
)
592 /* find a nearest Wine window precedes
593 * pWndCheck in the real z-order... */
595 hwndInsertAfter
= pWnd
->hwndSelf
;
597 if( best
- check
== 1 ) break;
602 if( children
) TSXFree( children
);
603 WIN_ReleaseWndPtr(pWnd
);
604 WIN_ReleaseWndPtr(pWndZ
);
605 WIN_ReleaseWndPtr(pWndCheck
);
606 return hwndInsertAfter
;
609 /***********************************************************************
610 * X11DRV_EVENT_XStateToKeyState
612 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
613 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
615 WORD
X11DRV_EVENT_XStateToKeyState( int state
)
619 if (state
& Button1Mask
) kstate
|= MK_LBUTTON
;
620 if (state
& Button2Mask
) kstate
|= MK_MBUTTON
;
621 if (state
& Button3Mask
) kstate
|= MK_RBUTTON
;
622 if (state
& ShiftMask
) kstate
|= MK_SHIFT
;
623 if (state
& ControlMask
) kstate
|= MK_CONTROL
;
627 /***********************************************************************
630 static void EVENT_Expose( HWND hWnd
, XExposeEvent
*event
)
633 int offx
= 0,offy
= 0;
635 WND
*pWnd
= WIN_FindWndPtr(hWnd
);
636 /* Make position relative to client area instead of window */
637 offx
= (pWnd
? (pWnd
->rectClient
.left
- pWnd
->rectWindow
.left
) : 0);
638 offy
= (pWnd
? (pWnd
->rectClient
.top
- pWnd
->rectWindow
.top
) : 0);
640 rect
.left
= event
->x
- offx
;
641 rect
.top
= event
->y
- offy
;
643 rect
.right
= rect
.left
+ event
->width
;
644 rect
.bottom
= rect
.top
+ event
->height
;
646 WIN_ReleaseWndPtr(pWnd
);
648 RedrawWindow( hWnd
, &rect
, 0, RDW_INVALIDATE
| RDW_FRAME
| RDW_ALLCHILDREN
| RDW_ERASE
);
650 if (event
->count
== 0)
651 SendNotifyMessageA(hWnd
,WM_SYNCPAINT
, 0, 0);
655 /***********************************************************************
656 * EVENT_GraphicsExpose
658 * This is needed when scrolling area is partially obscured
659 * by non-Wine X window.
661 static void EVENT_GraphicsExpose( HWND hWnd
, XGraphicsExposeEvent
*event
)
664 int offx
= 0,offy
= 0;
666 WND
*pWnd
= WIN_FindWndPtr(hWnd
);
667 /* Make position relative to client area instead of window */
668 offx
= (pWnd
? (pWnd
->rectClient
.left
- pWnd
->rectWindow
.left
) : 0);
669 offy
= (pWnd
? (pWnd
->rectClient
.top
- pWnd
->rectWindow
.top
) : 0);
671 rect
.left
= event
->x
- offx
;
672 rect
.top
= event
->y
- offy
;
674 rect
.right
= rect
.left
+ event
->width
;
675 rect
.bottom
= rect
.top
+ event
->height
;
677 WIN_ReleaseWndPtr(pWnd
);
679 RedrawWindow( hWnd
, &rect
, 0, RDW_INVALIDATE
| RDW_ALLCHILDREN
| RDW_ERASE
);
681 if (event
->count
== 0)
682 SendNotifyMessageA(hWnd
,WM_SYNCPAINT
, 0, 0);
686 /***********************************************************************
689 * Handle a X key event
691 static void EVENT_Key( HWND hWnd
, XKeyEvent
*event
)
693 WND
*pWnd
= WIN_FindWndPtr(hWnd
);
694 X11DRV_KEYBOARD_HandleEvent( pWnd
, event
);
695 WIN_ReleaseWndPtr(pWnd
);
700 /***********************************************************************
703 static void EVENT_MotionNotify( HWND hWnd
, XMotionEvent
*event
)
705 if (current_input_type
== X11DRV_INPUT_ABSOLUTE
) {
706 WND
*pWnd
= WIN_FindWndPtr(hWnd
);
707 int xOffset
= pWnd
? pWnd
->rectWindow
.left
: 0;
708 int yOffset
= pWnd
? pWnd
->rectWindow
.top
: 0;
709 WIN_ReleaseWndPtr(pWnd
);
711 X11DRV_SendEvent( MOUSEEVENTF_MOVE
| MOUSEEVENTF_ABSOLUTE
,
712 xOffset
+ event
->x
, yOffset
+ event
->y
,
713 X11DRV_EVENT_XStateToKeyState( event
->state
),
714 event
->time
- X11DRV_server_startticks
, hWnd
);
716 X11DRV_SendEvent( MOUSEEVENTF_MOVE
,
717 event
->x_root
, event
->y_root
,
718 X11DRV_EVENT_XStateToKeyState( event
->state
),
719 event
->time
- X11DRV_server_startticks
, hWnd
);
724 /***********************************************************************
727 static void EVENT_ButtonPress( HWND hWnd
, XButtonEvent
*event
)
729 static WORD statusCodes
[NB_BUTTONS
] =
730 { MOUSEEVENTF_LEFTDOWN
, MOUSEEVENTF_MIDDLEDOWN
, MOUSEEVENTF_RIGHTDOWN
, MOUSEEVENTF_WHEEL
, MOUSEEVENTF_WHEEL
};
731 int buttonNum
= event
->button
- 1;
733 WND
*pWnd
= WIN_FindWndPtr(hWnd
);
734 int xOffset
= pWnd
? pWnd
->rectWindow
.left
: 0;
735 int yOffset
= pWnd
? pWnd
->rectWindow
.top
: 0;
736 WORD keystate
,wData
= 0;
738 WIN_ReleaseWndPtr(pWnd
);
740 if (buttonNum
>= NB_BUTTONS
) return;
743 * Get the compatible keystate
745 keystate
= X11DRV_EVENT_XStateToKeyState( event
->state
);
748 * Make sure that the state of the button that was just
754 keystate
|= MK_LBUTTON
;
757 keystate
|= MK_MBUTTON
;
760 keystate
|= MK_RBUTTON
;
766 wData
= -WHEEL_DELTA
;
770 X11DRV_SendEvent( statusCodes
[buttonNum
],
771 xOffset
+ event
->x
, yOffset
+ event
->y
,
772 MAKEWPARAM(keystate
,wData
),
773 event
->time
- X11DRV_server_startticks
, hWnd
);
777 /***********************************************************************
778 * EVENT_ButtonRelease
780 static void EVENT_ButtonRelease( HWND hWnd
, XButtonEvent
*event
)
782 static WORD statusCodes
[NB_BUTTONS
] =
783 { MOUSEEVENTF_LEFTUP
, MOUSEEVENTF_MIDDLEUP
, MOUSEEVENTF_RIGHTUP
};
784 int buttonNum
= event
->button
- 1;
785 WND
*pWnd
= WIN_FindWndPtr(hWnd
);
786 int xOffset
= pWnd
? pWnd
->rectWindow
.left
: 0;
787 int yOffset
= pWnd
? pWnd
->rectWindow
.top
: 0;
790 WIN_ReleaseWndPtr(pWnd
);
792 if (buttonNum
>= NB_BUTTONS
) return;
795 * Get the compatible keystate
797 keystate
= X11DRV_EVENT_XStateToKeyState( event
->state
);
800 * Make sure that the state of the button that was just
806 keystate
&= ~MK_LBUTTON
;
809 keystate
&= ~MK_MBUTTON
;
812 keystate
&= ~MK_RBUTTON
;
818 X11DRV_SendEvent( statusCodes
[buttonNum
],
819 xOffset
+ event
->x
, yOffset
+ event
->y
,
820 keystate
, event
->time
- X11DRV_server_startticks
, hWnd
);
824 /**********************************************************************
827 static void EVENT_FocusIn( HWND hWnd
, XFocusChangeEvent
*event
)
829 if (event
->detail
!= NotifyPointer
)
830 if (hWnd
!= GetForegroundWindow())
832 SetForegroundWindow( hWnd
);
833 X11DRV_KEYBOARD_UpdateState();
838 /**********************************************************************
841 * Note: only top-level override-redirect windows get FocusOut events.
843 static void EVENT_FocusOut( HWND hWnd
, XFocusChangeEvent
*event
)
845 if (event
->detail
!= NotifyPointer
)
846 if (hWnd
== GetForegroundWindow())
848 SendMessageA( hWnd
, WM_CANCELMODE
, 0, 0 );
851 /* don't reset the foreground window, if the window who's
852 getting the focus is a Wine window */
853 if (!X11DRV_CheckFocus())
855 /* Abey : 6-Oct-99. Check again if the focus out window is the
856 Foreground window, because in most cases the messages sent
857 above must have already changed the foreground window, in which
858 case we don't have to change the foreground window to 0 */
860 if (hWnd
== GetForegroundWindow())
861 SetForegroundWindow( 0 );
866 /**********************************************************************
869 BOOL
X11DRV_CheckFocus(void)
875 TSXGetInputFocus(display
, &xW
, &state
);
877 TSXFindContext(display
, xW
, winContext
, (char **)&hWnd
) )
882 /**********************************************************************
885 * Helper function for ConfigureNotify handling.
886 * Get the new geometry of a window relative to the root window.
888 static void EVENT_GetGeometry( Window win
, int *px
, int *py
,
889 unsigned int *pwidth
, unsigned int *pheight
)
892 int x
, y
, width
, height
, border
, depth
;
894 EnterCriticalSection( &X11DRV_CritSection
);
896 /* Get the geometry of the window */
897 XGetGeometry( display
, win
, &root
, &x
, &y
, &width
, &height
,
900 /* Translate the window origin to root coordinates */
901 XTranslateCoordinates( display
, win
, root
, 0, 0, &x
, &y
, &top
);
903 LeaveCriticalSection( &X11DRV_CritSection
);
911 /**********************************************************************
912 * EVENT_ConfigureNotify
914 * The ConfigureNotify event is only selected on top-level windows
915 * when the -managed flag is used.
917 static void EVENT_ConfigureNotify( HWND hWnd
, XConfigureEvent
*event
)
921 unsigned int width
, height
;
922 HWND newInsertAfter
, oldInsertAfter
;
924 /* Get geometry and Z-order according to X */
926 EVENT_GetGeometry( event
->window
, &x
, &y
, &width
, &height
);
927 newInsertAfter
= EVENT_QueryZOrder( hWnd
);
929 /* Get geometry and Z-order according to Wine */
932 * Needs to find the first Visible Window above the current one
934 oldInsertAfter
= hWnd
;
937 oldInsertAfter
= GetWindow( oldInsertAfter
, GW_HWNDPREV
);
940 oldInsertAfter
= HWND_TOP
;
943 if (GetWindowLongA( oldInsertAfter
, GWL_STYLE
) & WS_VISIBLE
) break;
946 /* Compare what has changed */
948 GetWindowRect( hWnd
, &rectWindow
);
949 if ( rectWindow
.left
== x
&& rectWindow
.top
== y
)
952 TRACE_(win
)( "%04x moving from (%d,%d) to (%d,%d)\n", hWnd
,
953 rectWindow
.left
, rectWindow
.top
, x
, y
);
955 if ( rectWindow
.right
- rectWindow
.left
== width
956 && rectWindow
.bottom
- rectWindow
.top
== height
)
959 TRACE_(win
)( "%04x resizing from (%d,%d) to (%d,%d)\n", hWnd
,
960 rectWindow
.right
- rectWindow
.left
,
961 rectWindow
.bottom
- rectWindow
.top
, width
, height
);
963 if ( newInsertAfter
== oldInsertAfter
)
964 flags
|= SWP_NOZORDER
;
966 TRACE_(win
)( "%04x restacking from after %04x to after %04x\n", hWnd
,
967 oldInsertAfter
, newInsertAfter
);
969 /* If anything changed, call SetWindowPos */
971 if ( flags
!= (SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
) )
972 SetWindowPos( hWnd
, newInsertAfter
, x
, y
, width
, height
,
973 flags
| SWP_NOACTIVATE
| SWP_WINE_NOHOSTMOVE
);
977 /***********************************************************************
978 * EVENT_SelectionRequest_TARGETS
979 * Service a TARGETS selection request event
981 static Atom
EVENT_SelectionRequest_TARGETS( Window requestor
, Atom target
, Atom rprop
)
983 Atom xaTargets
= TSXInternAtom(display
, "TARGETS", False
);
987 unsigned long cTargets
;
991 TRACE("Request for %s\n", TSXGetAtomName(display
, target
));
994 * Count the number of items we wish to expose as selection targets.
995 * We include the TARGETS item, and a PIXMAP if we have CF_DIB or CF_BITMAP
997 cTargets
= CountClipboardFormats() + 1;
998 if ( CLIPBOARD_IsPresent(CF_DIB
) || CLIPBOARD_IsPresent(CF_BITMAP
) )
1001 /* Allocate temp buffer */
1002 targets
= (Atom
*)HeapAlloc( GetProcessHeap(), 0, cTargets
* sizeof(Atom
));
1003 if(targets
== NULL
) return None
;
1005 /* Create TARGETS property list (First item in list is TARGETS itself) */
1007 for ( targets
[0] = xaTargets
, cTargets
= 1, wFormat
= 0, bHavePixmap
= FALSE
;
1008 (wFormat
= EnumClipboardFormats( wFormat
)); )
1010 if ( (prop
= X11DRV_CLIPBOARD_MapFormatToProperty(wFormat
)) != None
)
1012 /* Scan through what we have so far to avoid duplicates */
1015 for (i
= 0, bExists
= FALSE
; i
< cTargets
; i
++)
1017 if (targets
[i
] == prop
)
1025 targets
[cTargets
++] = prop
;
1027 /* Add PIXMAP prop for bitmaps additionally */
1028 if ( (wFormat
== CF_DIB
|| wFormat
== CF_BITMAP
)
1031 targets
[cTargets
++] = XA_PIXMAP
;
1038 if (TRACE_ON(event
))
1041 for ( i
= 0; i
< cTargets
; i
++)
1045 char *itemFmtName
= TSXGetAtomName(display
, targets
[i
]);
1046 TRACE("\tAtom# %d: Type %s\n", i
, itemFmtName
);
1047 TSXFree(itemFmtName
);
1052 /* Update the X property */
1053 TRACE("\tUpdating property %s...", TSXGetAtomName(display
, rprop
));
1055 /* We may want to consider setting the type to xaTargets instead,
1056 * in case some apps expect this instead of XA_ATOM */
1057 xRc
= TSXChangeProperty(display
, requestor
, rprop
,
1058 XA_ATOM
, 32, PropModeReplace
,
1059 (unsigned char *)targets
, cTargets
);
1060 TRACE("(Rc=%d)\n", xRc
);
1062 HeapFree( GetProcessHeap(), 0, targets
);
1068 /***********************************************************************
1069 * EVENT_SelectionRequest_STRING
1070 * Service a STRING selection request event
1072 static Atom
EVENT_SelectionRequest_STRING( Window requestor
, Atom target
, Atom rprop
)
1074 static UINT text_cp
= (UINT
)-1;
1075 HANDLE hUnicodeText
;
1083 if(text_cp
== (UINT
)-1)
1084 text_cp
= PROFILE_GetWineIniInt("x11drv", "TextCP", CP_ACP
);
1087 * Map the requested X selection property type atom name to a
1088 * windows clipboard format ID.
1090 itemFmtName
= TSXGetAtomName(display
, target
);
1091 TRACE("Request for %s (wFormat=%x %s)\n",
1092 itemFmtName
, CF_UNICODETEXT
, CLIPBOARD_GetFormatName(CF_UNICODETEXT
));
1093 TSXFree(itemFmtName
);
1095 hUnicodeText
= GetClipboardData(CF_UNICODETEXT
);
1098 uni_text
= GlobalLock(hUnicodeText
);
1102 size
= WideCharToMultiByte(text_cp
, 0, uni_text
, -1, NULL
, 0, NULL
, NULL
);
1103 text
= HeapAlloc(GetProcessHeap(), 0, size
);
1106 WideCharToMultiByte(text_cp
, 0, uni_text
, -1, text
, size
, NULL
, NULL
);
1108 /* remove carriage returns */
1110 lpstr
= (char*)HeapAlloc( GetProcessHeap(), 0, size
-- );
1111 if(lpstr
== NULL
) return None
;
1112 for(i
=0,j
=0; i
< size
&& text
[i
]; i
++ )
1114 if( text
[i
] == '\r' &&
1115 (text
[i
+1] == '\n' || text
[i
+1] == '\0') ) continue;
1116 lpstr
[j
++] = text
[i
];
1120 /* Update the X property */
1121 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display
, rprop
));
1122 xRc
= TSXChangeProperty(display
, requestor
, rprop
,
1123 XA_STRING
, 8, PropModeReplace
,
1125 TRACE("(Rc=%d)\n", xRc
);
1127 GlobalUnlock(hUnicodeText
);
1128 HeapFree(GetProcessHeap(), 0, text
);
1129 HeapFree( GetProcessHeap(), 0, lpstr
);
1134 /***********************************************************************
1135 * EVENT_SelectionRequest_PIXMAP
1136 * Service a PIXMAP selection request event
1138 static Atom
EVENT_SelectionRequest_PIXMAP( Window requestor
, Atom target
, Atom rprop
)
1140 HANDLE hClipData
= 0;
1146 XSetWindowAttributes win_attr
;
1147 XWindowAttributes win_attr_src
;
1151 * Map the requested X selection property type atom name to a
1152 * windows clipboard format ID.
1154 itemFmtName
= TSXGetAtomName(display
, target
);
1155 wFormat
= X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName
);
1156 TRACE("Request for %s (wFormat=%x %s)\n",
1157 itemFmtName
, wFormat
, CLIPBOARD_GetFormatName( wFormat
));
1158 TSXFree(itemFmtName
);
1160 hClipData
= GetClipboardData(wFormat
);
1163 TRACE("Could not retrieve a Pixmap compatible format from clipboard!\n");
1164 rprop
= None
; /* Fail the request */
1168 if (wFormat
== CF_DIB
)
1170 HWND hwnd
= GetOpenClipboardWindow();
1171 HDC hdc
= GetDC(hwnd
);
1173 /* For convert from packed DIB to Pixmap */
1174 pixmap
= X11DRV_DIB_CreatePixmapFromDIB(hClipData
, hdc
);
1176 ReleaseDC(hdc
, hwnd
);
1178 else if (wFormat
== CF_BITMAP
)
1180 HWND hwnd
= GetOpenClipboardWindow();
1181 HDC hdc
= GetDC(hwnd
);
1183 pixmap
= X11DRV_BITMAP_CreatePixmapFromBitmap(hClipData
, hdc
);
1185 ReleaseDC(hdc
, hwnd
);
1189 FIXME("%s to PIXMAP conversion not yet implemented!\n",
1190 CLIPBOARD_GetFormatName(wFormat
));
1195 TRACE("\tUpdating property %s on Window %ld with %s %ld...\n",
1196 TSXGetAtomName(display
, rprop
), (long)requestor
,
1197 TSXGetAtomName(display
, target
), pixmap
);
1199 /* Store the Pixmap handle in the property */
1200 xRc
= TSXChangeProperty(display
, requestor
, rprop
, target
,
1201 32, PropModeReplace
,
1202 (unsigned char *)&pixmap
, 1);
1203 TRACE("(Rc=%d)\n", xRc
);
1205 /* Enable the code below if you want to handle destroying Pixmap resources
1206 * in response to property notify events. Clients like XPaint don't
1207 * appear to be duplicating Pixmaps so they don't like us deleting,
1208 * the resource in response to the property being deleted.
1211 /* Express interest in property notify events so that we can delete the
1212 * pixmap when the client deletes the property atom.
1214 xRc
= TSXGetWindowAttributes(display
, requestor
, &win_attr_src
);
1215 TRACE("Turning on PropertyChangeEvent notifications from window %ld\n",
1217 win_attr
.event_mask
= win_attr_src
.your_event_mask
| PropertyChangeMask
;
1218 TSXChangeWindowAttributes(display
, requestor
, CWEventMask
, &win_attr
);
1220 /* Register the Pixmap we created with the request property Atom.
1221 * When this property is destroyed we also destroy the Pixmap in
1222 * response to the PropertyNotify event.
1224 X11DRV_CLIPBOARD_RegisterPixmapResource( rprop
, pixmap
);
1232 /***********************************************************************
1233 * EVENT_SelectionRequest_WCF
1234 * Service a Wine Clipboard Format selection request event.
1235 * For <WCF>* data types we simply copy the data to X without conversion.
1237 static Atom
EVENT_SelectionRequest_WCF( Window requestor
, Atom target
, Atom rprop
)
1239 HANDLE hClipData
= 0;
1247 * Map the requested X selection property type atom name to a
1248 * windows clipboard format ID.
1250 itemFmtName
= TSXGetAtomName(display
, target
);
1251 wFormat
= X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName
);
1252 TRACE("Request for %s (wFormat=%x %s)\n",
1253 itemFmtName
, wFormat
, CLIPBOARD_GetFormatName( wFormat
));
1254 TSXFree(itemFmtName
);
1256 hClipData
= GetClipboardData16(wFormat
);
1258 if( hClipData
&& (lpClipData
= GlobalLock16(hClipData
)) )
1260 cBytes
= GlobalSize16(hClipData
);
1262 TRACE("\tUpdating property %s, %d bytes...\n",
1263 TSXGetAtomName(display
, rprop
), cBytes
);
1265 xRc
= TSXChangeProperty(display
, requestor
, rprop
,
1266 target
, 8, PropModeReplace
,
1267 (unsigned char *)lpClipData
, cBytes
);
1268 TRACE("(Rc=%d)\n", xRc
);
1270 GlobalUnlock16(hClipData
);
1274 TRACE("\tCould not retrieve native format!\n");
1275 rprop
= None
; /* Fail the request */
1282 /***********************************************************************
1283 * EVENT_SelectionRequest_MULTIPLE
1284 * Service a MULTIPLE selection request event
1285 * rprop contains a list of (target,property) atom pairs.
1286 * The first atom names a target and the second names a property.
1287 * The effect is as if we have received a sequence of SelectionRequest events
1288 * (one for each atom pair) except that:
1289 * 1. We reply with a SelectionNotify only when all the requested conversions
1290 * have been performed.
1291 * 2. If we fail to convert the target named by an atom in the MULTIPLE property,
1292 * we replace the atom in the property by None.
1294 static Atom
EVENT_SelectionRequest_MULTIPLE( HWND hWnd
, XSelectionRequestEvent
*pevent
)
1297 Atom atype
=AnyPropertyType
;
1299 unsigned long remain
;
1300 Atom
* targetPropList
=NULL
;
1301 unsigned long cTargetPropList
= 0;
1302 /* Atom xAtomPair = TSXInternAtom(display, "ATOM_PAIR", False); */
1304 /* If the specified property is None the requestor is an obsolete client.
1305 * We support these by using the specified target atom as the reply property.
1307 rprop
= pevent
->property
;
1309 rprop
= pevent
->target
;
1313 /* Read the MULTIPLE property contents. This should contain a list of
1314 * (target,property) atom pairs.
1316 if(TSXGetWindowProperty(display
, pevent
->requestor
, rprop
,
1317 0, 0x3FFF, False
, AnyPropertyType
, &atype
,&aformat
,
1318 &cTargetPropList
, &remain
,
1319 (unsigned char**)&targetPropList
) != Success
)
1320 TRACE("\tCouldn't read MULTIPLE property\n");
1323 TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
1324 TSXGetAtomName(display
, atype
), aformat
, cTargetPropList
, remain
);
1327 * Make sure we got what we expect.
1328 * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
1329 * in a MULTIPLE selection request should be of type ATOM_PAIR.
1330 * However some X apps(such as XPaint) are not compliant with this and return
1331 * a user defined atom in atype when XGetWindowProperty is called.
1332 * The data *is* an atom pair but is not denoted as such.
1334 if(aformat
== 32 /* atype == xAtomPair */ )
1338 /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
1339 * for each (target,property) pair */
1341 for (i
= 0; i
< cTargetPropList
; i
+=2)
1343 char *targetName
= TSXGetAtomName(display
, targetPropList
[i
]);
1344 char *propName
= TSXGetAtomName(display
, targetPropList
[i
+1]);
1345 XSelectionRequestEvent event
;
1347 TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
1348 i
/2, targetName
, propName
);
1349 TSXFree(targetName
);
1352 /* We must have a non "None" property to service a MULTIPLE target atom */
1353 if ( !targetPropList
[i
+1] )
1355 TRACE("\tMULTIPLE(%d): Skipping target with empty property!", i
);
1359 /* Set up an XSelectionRequestEvent for this (target,property) pair */
1360 memcpy( &event
, pevent
, sizeof(XSelectionRequestEvent
) );
1361 event
.target
= targetPropList
[i
];
1362 event
.property
= targetPropList
[i
+1];
1364 /* Fire a SelectionRequest, informing the handler that we are processing
1365 * a MULTIPLE selection request event.
1367 EVENT_SelectionRequest( hWnd
, &event
, TRUE
);
1371 /* Free the list of targets/properties */
1372 TSXFree(targetPropList
);
1380 /***********************************************************************
1381 * EVENT_SelectionRequest
1382 * Process an event selection request event.
1383 * The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
1384 * recursively while servicing a "MULTIPLE" selection target.
1386 * Note: We only receive this event when WINE owns the X selection
1388 static void EVENT_SelectionRequest( HWND hWnd
, XSelectionRequestEvent
*event
, BOOL bIsMultiple
)
1390 XSelectionEvent result
;
1392 Window request
= event
->requestor
;
1393 BOOL couldOpen
= FALSE
;
1394 Atom xaClipboard
= TSXInternAtom(display
, "CLIPBOARD", False
);
1395 Atom xaTargets
= TSXInternAtom(display
, "TARGETS", False
);
1396 Atom xaMultiple
= TSXInternAtom(display
, "MULTIPLE", False
);
1399 * We can only handle the selection request if :
1400 * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
1401 * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
1402 * since this has been already done.
1406 if ( ( (event
->selection
!= XA_PRIMARY
) && (event
->selection
!= xaClipboard
) )
1407 || !(couldOpen
= OpenClipboard(hWnd
)) )
1411 /* If the specified property is None the requestor is an obsolete client.
1412 * We support these by using the specified target atom as the reply property.
1414 rprop
= event
->property
;
1416 rprop
= event
->target
;
1418 if(event
->target
== xaTargets
) /* Return a list of all supported targets */
1420 /* TARGETS selection request */
1421 rprop
= EVENT_SelectionRequest_TARGETS( request
, event
->target
, rprop
);
1423 else if(event
->target
== xaMultiple
) /* rprop contains a list of (target, property) atom pairs */
1425 /* MULTIPLE selection request */
1426 rprop
= EVENT_SelectionRequest_MULTIPLE( hWnd
, event
);
1428 else if(event
->target
== XA_STRING
) /* treat CF_TEXT as Unix text */
1430 /* XA_STRING selection request */
1431 rprop
= EVENT_SelectionRequest_STRING( request
, event
->target
, rprop
);
1433 else if(event
->target
== XA_PIXMAP
) /* Convert DIB's to Pixmaps */
1435 /* XA_PIXMAP selection request */
1436 rprop
= EVENT_SelectionRequest_PIXMAP( request
, event
->target
, rprop
);
1438 else if(event
->target
== XA_BITMAP
) /* Convert DIB's to 1-bit Pixmaps */
1440 /* XA_BITMAP selection request - TODO: create a monochrome Pixmap */
1441 rprop
= EVENT_SelectionRequest_PIXMAP( request
, XA_PIXMAP
, rprop
);
1443 else if(X11DRV_CLIPBOARD_IsNativeProperty(event
->target
)) /* <WCF>* */
1445 /* All <WCF> selection requests */
1446 rprop
= EVENT_SelectionRequest_WCF( request
, event
->target
, rprop
);
1449 rprop
= None
; /* Don't support this format */
1452 /* close clipboard only if we opened before */
1453 if(couldOpen
) CloseClipboard();
1456 TRACE("\tRequest ignored\n");
1459 * SelectionNotify should be sent only at the end of a MULTIPLE request
1463 result
.type
= SelectionNotify
;
1464 result
.display
= display
;
1465 result
.requestor
= request
;
1466 result
.selection
= event
->selection
;
1467 result
.property
= rprop
;
1468 result
.target
= event
->target
;
1469 result
.time
= event
->time
;
1470 TRACE("Sending SelectionNotify event...\n");
1471 TSXSendEvent(display
,event
->requestor
,False
,NoEventMask
,(XEvent
*)&result
);
1475 /***********************************************************************
1476 * EVENT_SelectionClear
1478 static void EVENT_SelectionClear( HWND hWnd
, XSelectionClearEvent
*event
)
1480 Atom xaClipboard
= TSXInternAtom(display
, "CLIPBOARD", False
);
1482 if (event
->selection
== XA_PRIMARY
|| event
->selection
== xaClipboard
)
1483 X11DRV_CLIPBOARD_ReleaseSelection( event
->selection
, event
->window
, hWnd
);
1486 /***********************************************************************
1487 * EVENT_PropertyNotify
1488 * We use this to release resources like Pixmaps when a selection
1489 * client no longer needs them.
1491 static void EVENT_PropertyNotify( XPropertyEvent
*event
)
1493 /* Check if we have any resources to free */
1494 TRACE("Received PropertyNotify event: ");
1496 switch(event
->state
)
1498 case PropertyDelete
:
1500 TRACE("\tPropertyDelete for atom %s on window %ld\n",
1501 TSXGetAtomName(event
->display
, event
->atom
), (long)event
->window
);
1503 if (X11DRV_IsSelectionOwner())
1504 X11DRV_CLIPBOARD_FreeResources( event
->atom
);
1508 case PropertyNewValue
:
1510 TRACE("\tPropertyNewValue for atom %s on window %ld\n\n",
1511 TSXGetAtomName(event
->display
, event
->atom
), (long)event
->window
);
1520 /**********************************************************************
1521 * EVENT_DropFromOffix
1523 * don't know if it still works (last Changlog is from 96/11/04)
1525 static void EVENT_DropFromOffiX( HWND hWnd
, XClientMessageEvent
*event
)
1527 unsigned long data_length
;
1528 unsigned long aux_long
;
1529 unsigned char* p_data
= NULL
;
1540 HGLOBAL16 hDragInfo
= GlobalAlloc16( GMEM_SHARE
| GMEM_ZEROINIT
, sizeof(DRAGINFO16
));
1541 LPDRAGINFO16 lpDragInfo
= (LPDRAGINFO16
) GlobalLock16(hDragInfo
);
1542 SEGPTR spDragInfo
= (SEGPTR
) WIN16_GlobalLock16(hDragInfo
);
1543 Window w_aux_root
, w_aux_child
;
1547 if( !lpDragInfo
|| !spDragInfo
) return;
1549 pWnd
= WIN_FindWndPtr(hWnd
);
1551 TSXQueryPointer( display
, X11DRV_WND_GetXWindow(pWnd
), &w_aux_root
, &w_aux_child
,
1552 &x
, &y
, (int *) &u
.pt_aux
.x
, (int *) &u
.pt_aux
.y
,
1553 (unsigned int*)&aux_long
);
1555 lpDragInfo
->hScope
= hWnd
;
1556 lpDragInfo
->pt
.x
= (INT16
)x
; lpDragInfo
->pt
.y
= (INT16
)y
;
1558 /* find out drop point and drop window */
1559 if( x
< 0 || y
< 0 ||
1560 x
> (pWnd
->rectWindow
.right
- pWnd
->rectWindow
.left
) ||
1561 y
> (pWnd
->rectWindow
.bottom
- pWnd
->rectWindow
.top
) )
1562 { bAccept
= pWnd
->dwExStyle
& WS_EX_ACCEPTFILES
; x
= y
= 0; }
1565 bAccept
= DRAG_QueryUpdate( hWnd
, spDragInfo
, TRUE
);
1566 x
= lpDragInfo
->pt
.x
; y
= lpDragInfo
->pt
.y
;
1568 pDropWnd
= WIN_FindWndPtr( lpDragInfo
->hScope
);
1569 WIN_ReleaseWndPtr(pWnd
);
1571 GlobalFree16( hDragInfo
);
1575 TSXGetWindowProperty( display
, DefaultRootWindow(display
),
1576 dndSelection
, 0, 65535, FALSE
,
1577 AnyPropertyType
, &u
.atom_aux
, (int *) &u
.pt_aux
.y
,
1578 &data_length
, &aux_long
, &p_data
);
1580 if( !aux_long
&& p_data
) /* don't bother if > 64K */
1582 char *p
= (char*) p_data
;
1586 while( *p
) /* calculate buffer size */
1589 if((u
.i
= *p
) != -1 )
1591 INT len
= GetShortPathNameA( p
, NULL
, 0 );
1592 if (len
) aux_long
+= len
+ 1;
1597 if( aux_long
&& aux_long
< 65535 )
1602 aux_long
+= sizeof(DROPFILES
) + 1;
1603 hDrop
= GlobalAlloc( GMEM_SHARE
, aux_long
);
1604 lpDrop
= (DROPFILES
*)GlobalLock( hDrop
);
1608 lpDrop
->pFiles
= sizeof(DROPFILES
);
1612 ( x
< (pDropWnd
->rectClient
.left
- pDropWnd
->rectWindow
.left
) ||
1613 y
< (pDropWnd
->rectClient
.top
- pDropWnd
->rectWindow
.top
) ||
1614 x
> (pDropWnd
->rectClient
.right
- pDropWnd
->rectWindow
.left
) ||
1615 y
> (pDropWnd
->rectClient
.bottom
- pDropWnd
->rectWindow
.top
) );
1616 lpDrop
->fWide
= FALSE
;
1617 p_drop
= (char *)(lpDrop
+ 1);
1621 if( *p
!= -1 ) /* use only "good" entries */
1623 GetShortPathNameA( p
, p_drop
, 65535 );
1624 p_drop
+= strlen( p_drop
) + 1;
1629 PostMessageA( hWnd
, WM_DROPFILES
, hDrop
, 0L );
1633 if( p_data
) TSXFree(p_data
);
1635 } /* WS_EX_ACCEPTFILES */
1637 WIN_ReleaseWndPtr(pDropWnd
);
1640 /**********************************************************************
1643 * drop items are separated by \n
1644 * each item is prefixed by its mime type
1646 * event->data.l[3], event->data.l[4] contains drop x,y position
1648 static void EVENT_DropURLs( HWND hWnd
, XClientMessageEvent
*event
)
1652 unsigned long data_length
;
1653 unsigned long aux_long
, drop_len
= 0;
1654 unsigned char *p_data
= NULL
; /* property data */
1655 char *p_drop
= NULL
;
1666 pWnd
= WIN_FindWndPtr(hWnd
);
1668 if (!(pWnd
->dwExStyle
& WS_EX_ACCEPTFILES
))
1670 WIN_ReleaseWndPtr(pWnd
);
1673 WIN_ReleaseWndPtr(pWnd
);
1675 TSXGetWindowProperty( display
, DefaultRootWindow(display
),
1676 dndSelection
, 0, 65535, FALSE
,
1677 AnyPropertyType
, &u
.atom_aux
, &u
.i
,
1678 &data_length
, &aux_long
, &p_data
);
1680 WARN("property too large, truncated!\n");
1681 TRACE("urls=%s\n", p_data
);
1683 if( !aux_long
&& p_data
) { /* don't bother if > 64K */
1684 /* calculate length */
1686 next
= strchr(p
, '\n');
1689 if (strncmp(p
,"file:",5) == 0 ) {
1690 INT len
= GetShortPathNameA( p
+5, NULL
, 0 );
1691 if (len
) drop_len
+= len
+ 1;
1696 next
= strchr(p
, '\n');
1702 if( drop_len
&& drop_len
< 65535 ) {
1703 TSXQueryPointer( display
, X11DRV_GetXRootWindow(), &u
.w_aux
, &u
.w_aux
,
1704 &x
, &y
, &u
.i
, &u
.i
, &u
.i
);
1706 pDropWnd
= WIN_FindWndPtr( hWnd
);
1708 drop_len
+= sizeof(DROPFILES
) + 1;
1709 hDrop
= (HDROP
)GlobalAlloc( GMEM_SHARE
, drop_len
);
1710 lpDrop
= (DROPFILES
*) GlobalLock( hDrop
);
1713 lpDrop
->pFiles
= sizeof(DROPFILES
);
1714 lpDrop
->pt
.x
= (INT
)x
;
1715 lpDrop
->pt
.y
= (INT
)y
;
1717 ( x
< (pDropWnd
->rectClient
.left
- pDropWnd
->rectWindow
.left
) ||
1718 y
< (pDropWnd
->rectClient
.top
- pDropWnd
->rectWindow
.top
) ||
1719 x
> (pDropWnd
->rectClient
.right
- pDropWnd
->rectWindow
.left
) ||
1720 y
> (pDropWnd
->rectClient
.bottom
- pDropWnd
->rectWindow
.top
) );
1721 lpDrop
->fWide
= FALSE
;
1722 p_drop
= (char*)(lpDrop
+ 1);
1725 /* create message content */
1728 next
= strchr(p
, '\n');
1731 if (strncmp(p
,"file:",5) == 0 ) {
1732 INT len
= GetShortPathNameA( p
+5, p_drop
, 65535 );
1734 TRACE("drop file %s as %s\n", p
+5, p_drop
);
1737 WARN("can't convert file %s to dos name \n", p
+5);
1740 WARN("unknown mime type %s\n", p
);
1745 next
= strchr(p
, '\n');
1752 GlobalUnlock(hDrop
);
1753 PostMessageA( hWnd
, WM_DROPFILES
, hDrop
, 0L );
1755 WIN_ReleaseWndPtr(pDropWnd
);
1757 if( p_data
) TSXFree(p_data
);
1761 /**********************************************************************
1762 * EVENT_ClientMessage
1764 static void EVENT_ClientMessage( HWND hWnd
, XClientMessageEvent
*event
)
1766 if (event
->message_type
!= None
&& event
->format
== 32) {
1767 if ((event
->message_type
== wmProtocols
) &&
1768 (((Atom
) event
->data
.l
[0]) == wmDeleteWindow
))
1770 /* Ignore the delete window request if the window has been disabled
1771 * and we are in managed mode. This is to disallow applications from
1772 * being closed by the window manager while in a modal state.
1775 bIsDisabled
= GetWindowLongA( hWnd
, GWL_STYLE
) & WS_DISABLED
;
1777 if ( !Options
.managed
|| !bIsDisabled
)
1778 PostMessage16( hWnd
, WM_SYSCOMMAND
, SC_CLOSE
, 0 );
1780 else if ( event
->message_type
== dndProtocol
&&
1781 (event
->data
.l
[0] == DndFile
|| event
->data
.l
[0] == DndFiles
) )
1782 EVENT_DropFromOffiX(hWnd
, event
);
1783 else if ( event
->message_type
== dndProtocol
&&
1784 event
->data
.l
[0] == DndURL
)
1785 EVENT_DropURLs(hWnd
, event
);
1788 /* enable this if you want to see the message */
1789 unsigned char* p_data
= NULL
;
1795 TSXGetWindowProperty( display
, DefaultRootWindow(display
),
1796 dndSelection
, 0, 65535, FALSE
,
1797 AnyPropertyType
, &u
.atom
, &u
.i
,
1798 &u
.l
, &u
.l
, &p_data
);
1799 TRACE("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1800 event
->message_type
, event
->data
.l
[0], event
->data
.l
[1],
1801 event
->data
.l
[2], event
->data
.l
[3], event
->data
.l
[4],
1804 TRACE("unrecognized ClientMessage\n" );
1809 /**********************************************************************
1812 * Install colormap when Wine window is focused in
1813 * self-managed mode with private colormap
1816 void EVENT_EnterNotify( HWND hWnd
, XCrossingEvent
*event
)
1818 if( !Options
.managed
&& X11DRV_GetXRootWindow() == DefaultRootWindow(display
) &&
1819 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE
) && GetFocus() )
1820 TSXInstallColormap( display
, X11DRV_PALETTE_GetColormap() );
1824 /**********************************************************************
1827 void EVENT_MapNotify( HWND hWnd
, XMapEvent
*event
)
1829 HWND hwndFocus
= GetFocus();
1830 WND
*wndFocus
= WIN_FindWndPtr(hwndFocus
);
1831 WND
*pWnd
= WIN_FindWndPtr(hWnd
);
1832 if (pWnd
&& (pWnd
->dwExStyle
& WS_EX_MANAGED
))
1834 DCE_InvalidateDCE( pWnd
, &pWnd
->rectWindow
);
1835 pWnd
->dwStyle
&= ~WS_MINIMIZE
;
1836 pWnd
->dwStyle
|= WS_VISIBLE
;
1837 WIN_InternalShowOwnedPopups(hWnd
,TRUE
,TRUE
);
1839 WIN_ReleaseWndPtr(pWnd
);
1841 if (hwndFocus
&& IsChild( hWnd
, hwndFocus
))
1842 X11DRV_WND_SetFocus(wndFocus
);
1844 WIN_ReleaseWndPtr(wndFocus
);
1850 /**********************************************************************
1853 void EVENT_UnmapNotify( HWND hWnd
, XUnmapEvent
*event
)
1855 WND
*pWnd
= WIN_FindWndPtr(hWnd
);
1856 if (pWnd
&& (pWnd
->dwExStyle
& WS_EX_MANAGED
))
1859 if( pWnd
->dwStyle
& WS_VISIBLE
)
1861 pWnd
->dwStyle
|= WS_MINIMIZE
;
1862 pWnd
->dwStyle
&= ~WS_VISIBLE
;
1863 WIN_InternalShowOwnedPopups(hWnd
,FALSE
,TRUE
);
1866 WIN_ReleaseWndPtr(pWnd
);
1869 /***********************************************************************
1870 * EVENT_MappingNotify
1872 static void EVENT_MappingNotify( XMappingEvent
*event
)
1874 TSXRefreshKeyboardMapping(event
);
1876 /* reinitialize Wine-X11 driver keyboard table */
1877 X11DRV_InitKeyboard();
1881 /**********************************************************************
1882 * X11DRV_EVENT_SetInputMethod
1884 INPUT_TYPE
X11DRV_EVENT_SetInputMethod(INPUT_TYPE type
)
1886 INPUT_TYPE prev
= current_input_type
;
1888 /* Flag not used yet */
1889 in_transition
= FALSE
;
1890 current_input_type
= type
;
1895 #ifdef HAVE_LIBXXF86DGA2
1896 /**********************************************************************
1897 * X11DRV_EVENT_SetDGAStatus
1899 void X11DRV_EVENT_SetDGAStatus(HWND hwnd
, int event_base
)
1901 if (event_base
< 0) {
1907 DGAMotionEventType
= event_base
+ MotionNotify
;
1908 DGAButtonPressEventType
= event_base
+ ButtonPress
;
1909 DGAButtonReleaseEventType
= event_base
+ ButtonRelease
;
1910 DGAKeyPressEventType
= event_base
+ KeyPress
;
1911 DGAKeyReleaseEventType
= event_base
+ KeyRelease
;
1915 /* DGA2 event handlers */
1916 static void EVENT_DGAMotionEvent( XDGAMotionEvent
*event
)
1918 X11DRV_SendEvent( MOUSEEVENTF_MOVE
,
1919 event
->dx
, event
->dy
,
1920 X11DRV_EVENT_XStateToKeyState( event
->state
),
1921 event
->time
- X11DRV_server_startticks
, DGAhwnd
);
1924 static void EVENT_DGAButtonPressEvent( XDGAButtonEvent
*event
)
1926 static WORD statusCodes
[NB_BUTTONS
] =
1927 { MOUSEEVENTF_LEFTDOWN
, MOUSEEVENTF_MIDDLEDOWN
, MOUSEEVENTF_RIGHTDOWN
};
1928 int buttonNum
= event
->button
- 1;
1932 if (buttonNum
>= NB_BUTTONS
) return;
1934 keystate
= X11DRV_EVENT_XStateToKeyState( event
->state
);
1939 keystate
|= MK_LBUTTON
;
1942 keystate
|= MK_MBUTTON
;
1945 keystate
|= MK_RBUTTON
;
1949 X11DRV_SendEvent( statusCodes
[buttonNum
], 0, 0, keystate
, event
->time
- X11DRV_server_startticks
, DGAhwnd
);
1952 static void EVENT_DGAButtonReleaseEvent( XDGAButtonEvent
*event
)
1954 static WORD statusCodes
[NB_BUTTONS
] =
1955 { MOUSEEVENTF_LEFTUP
, MOUSEEVENTF_MIDDLEUP
, MOUSEEVENTF_RIGHTUP
};
1956 int buttonNum
= event
->button
- 1;
1960 if (buttonNum
>= NB_BUTTONS
) return;
1962 keystate
= X11DRV_EVENT_XStateToKeyState( event
->state
);
1967 keystate
&= ~MK_LBUTTON
;
1970 keystate
&= ~MK_MBUTTON
;
1973 keystate
&= ~MK_RBUTTON
;
1977 X11DRV_SendEvent( statusCodes
[buttonNum
], 0, 0, keystate
, event
->time
- X11DRV_server_startticks
, DGAhwnd
);
1982 #ifdef HAVE_LIBXXSHM
1985 Normal XShm operation:
1987 X11 service thread app thread
1988 ------------- ----------------- ------------------------
1989 (idle) ddraw calls XShmPutImage
1990 (copies data) (waiting for shm_event)
1991 ShmCompletion -> (waiting for shm_event)
1992 (idle) signal shm_event ->
1993 (idle) returns to app
1995 However, this situation can occur for some reason:
1997 X11 service thread app thread
1998 ------------- ----------------- ------------------------
2001 (waiting for app) ddraw calls XShmPutImage
2002 (copies data) (waiting for app) (waiting for shm_event)
2003 ShmCompletion (waiting for app) (waiting for shm_event)
2004 (idle) DEADLOCK DEADLOCK
2006 which is why I also wait for shm_read and do XCheckTypedEvent()
2007 calls in the wait loop. This results in:
2009 X11 service thread app thread
2010 ------------- ----------------- ------------------------
2011 ShmCompletion (waiting for app) waking up on shm_read
2012 (idle) (waiting for app) XCheckTypedEvent() -> signal shm_event
2013 (waiting for app) returns
2023 /* FIXME: this is not pretty */
2024 static HANDLE shm_read
= 0;
2027 static volatile shm_qs shm_q
[SHM_MAX_Q
];
2029 static void EVENT_ShmCompletion( XShmCompletionEvent
*event
)
2033 TRACE("Got ShmCompletion for drawable %ld (time %ld)\n", event
->drawable
, GetTickCount() );
2035 for (n
=0; n
<SHM_MAX_Q
; n
++)
2036 if ((shm_q
[n
].draw
== event
->drawable
) && (shm_q
[n
].state
== 0)) {
2037 HANDLE sema
= shm_q
[n
].sema
;
2038 if (!InterlockedCompareExchange((PVOID
*)&shm_q
[n
].state
, (PVOID
)1, (PVOID
)0)) {
2039 ReleaseSemaphore(sema
, 1, NULL
);
2040 TRACE("Signaling ShmCompletion (#%d) (semaphore %x)\n", n
, sema
);
2045 ERR("Got ShmCompletion for unknown drawable %ld\n", event
->drawable
);
2048 int X11DRV_EVENT_PrepareShmCompletion( Drawable dw
)
2053 shm_read
= FILE_DupUnixHandle( ConnectionNumber(display
), GENERIC_READ
| SYNCHRONIZE
);
2055 for (n
=0; n
<SHM_MAX_Q
; n
++)
2057 if (!InterlockedCompareExchange((PVOID
*)&shm_q
[n
].draw
, (PVOID
)dw
, (PVOID
)0))
2061 ERR("Maximum number of outstanding ShmCompletions exceeded!\n");
2066 if (!shm_q
[n
].sema
) {
2067 shm_q
[n
].sema
= CreateSemaphoreA( NULL
, 0, 256, NULL
);
2068 TRACE("Allocated ShmCompletion slots have been increased to %d, new semaphore is %x\n", n
+1, shm_q
[n
].sema
);
2071 TRACE("Prepared ShmCompletion (#%d) wait for drawable %ld (thread %lx) (time %ld)\n", n
, dw
, GetCurrentThreadId(), GetTickCount() );
2075 static void X11DRV_EVENT_WaitReplaceShmCompletionInternal( int *compl, Drawable dw
, int creat
)
2081 if ((!n
) || (creat
&& (!shm_q
[n
-1].draw
))) {
2082 nn
= X11DRV_EVENT_PrepareShmCompletion(dw
);
2083 if (!(n
=(LONG
)InterlockedCompareExchange((PVOID
*)compl, (PVOID
)nn
, (PVOID
)n
)))
2085 /* race for compl lost, clear slot */
2086 shm_q
[nn
-1].draw
= 0;
2090 if (dw
&& (shm_q
[n
-1].draw
!= dw
)) {
2091 /* this shouldn't happen with the current ddraw implementation */
2092 FIXME("ShmCompletion replace with different drawable!\n");
2096 sema
= shm_q
[n
-1].sema
;
2098 /* nothing to wait on (PrepareShmCompletion not done yet?), so probably nothing to wait for */
2102 nn
= InterlockedExchangeAdd((PLONG
)&shm_q
[n
-1].waiter
, 1);
2103 if ((!shm_q
[n
-1].draw
) || (shm_q
[n
-1].state
== 2)) {
2104 /* too late, the wait was just cleared (wait complete) */
2105 TRACE("Wait skip for ShmCompletion (#%d) (thread %lx) (time %ld) (semaphore %x)\n", n
-1, GetCurrentThreadId(), GetTickCount(), sema
);
2107 TRACE("Waiting for ShmCompletion (#%d) (thread %lx) (time %ld) (semaphore %x)\n", n
-1, GetCurrentThreadId(), GetTickCount(), sema
);
2109 /* another thread is already waiting, let the primary waiter do the dirty work
2110 * (to avoid TSX critical section contention - that could get really slow) */
2111 WaitForSingleObject( sema
, INFINITE
);
2113 /* we're primary waiter - first check if it's already triggered */
2114 if ( WaitForSingleObject( sema
, 0 ) != WAIT_OBJECT_0
) {
2115 /* nope, may need to poll X event queue, in case the service thread is blocked */
2122 /* check X event queue */
2123 if (TSXCheckTypedEvent( display
, ShmCompletionType
, &event
)) {
2124 EVENT_ProcessEvent( &event
);
2126 } while ( WaitForMultipleObjects(2, hnd
, FALSE
, INFINITE
) > WAIT_OBJECT_0
);
2128 TRACE("Wait complete (thread %lx) (time %ld)\n", GetCurrentThreadId(), GetTickCount() );
2131 st
= InterlockedExchange((LPLONG
)&shm_q
[n
-1].state
, 2);
2133 /* first waiter to return, release all other waiters */
2134 nn
= shm_q
[n
-1].waiter
;
2135 TRACE("Signaling %ld additional ShmCompletion (#%d) waiter(s), semaphore %x\n", nn
-1, n
-1, sema
);
2136 ReleaseSemaphore(sema
, nn
-1, NULL
);
2139 nn
= InterlockedDecrement((LPLONG
)&shm_q
[n
-1].waiter
);
2141 /* last waiter to return, replace drawable and prepare new wait */
2142 shm_q
[n
-1].draw
= dw
;
2143 shm_q
[n
-1].state
= 0;
2147 void X11DRV_EVENT_WaitReplaceShmCompletion( int *compl, Drawable dw
)
2149 X11DRV_EVENT_WaitReplaceShmCompletionInternal( compl, dw
, 1 );
2152 void X11DRV_EVENT_WaitShmCompletion( int compl )
2155 X11DRV_EVENT_WaitReplaceShmCompletionInternal( &compl, 0, 0 );
2158 void X11DRV_EVENT_WaitShmCompletions( Drawable dw
)
2162 for (n
=0; n
<SHM_MAX_Q
; n
++)
2163 if (shm_q
[n
].draw
== dw
)
2164 X11DRV_EVENT_WaitShmCompletion( n
+1 );
2167 #endif /* defined(HAVE_LIBXXSHM) */