4 * Copyright 1993 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #ifdef HAVE_SYS_POLL_H
30 #include <X11/Xatom.h>
31 #include <X11/keysym.h>
33 #include <X11/Xresource.h>
34 #include <X11/Xutil.h>
40 #define NONAMELESSUNION
41 #define NONAMELESSSTRUCT
49 /* avoid conflict with field names in included win32 headers */
51 #include "shlobj.h" /* DROPFILES */
54 #include "wine/server.h"
55 #include "wine/debug.h"
57 WINE_DEFAULT_DEBUG_CHANNEL(event
);
59 extern BOOL ximInComposeMode
;
61 #define DndNotDnd -1 /* OffiX drag&drop */
73 #define DndURL 128 /* KDE drag&drop */
76 static void X11DRV_FocusIn( HWND hwnd
, XEvent
*event
);
77 static void X11DRV_FocusOut( HWND hwnd
, XEvent
*event
);
78 static void X11DRV_Expose( HWND hwnd
, XEvent
*event
);
79 static void X11DRV_MapNotify( HWND hwnd
, XEvent
*event
);
80 static void X11DRV_PropertyNotify( HWND hwnd
, XEvent
*event
);
81 static void X11DRV_ClientMessage( HWND hwnd
, XEvent
*event
);
85 int type
; /* event type */
86 x11drv_event_handler handler
; /* corresponding handler function */
89 #define MAX_EVENT_HANDLERS 64
91 static struct event_handler handlers
[MAX_EVENT_HANDLERS
] =
93 /* list must be sorted by event type */
94 { KeyPress
, X11DRV_KeyEvent
},
95 { KeyRelease
, X11DRV_KeyEvent
},
96 { ButtonPress
, X11DRV_ButtonPress
},
97 { ButtonRelease
, X11DRV_ButtonRelease
},
98 { MotionNotify
, X11DRV_MotionNotify
},
99 { EnterNotify
, X11DRV_EnterNotify
},
101 { FocusIn
, X11DRV_FocusIn
},
102 { FocusOut
, X11DRV_FocusOut
},
103 { KeymapNotify
, X11DRV_KeymapNotify
},
104 { Expose
, X11DRV_Expose
},
107 /* VisibilityNotify */
109 { DestroyNotify
, X11DRV_DestroyNotify
},
111 { MapNotify
, X11DRV_MapNotify
},
114 { ConfigureNotify
, X11DRV_ConfigureNotify
},
115 /* ConfigureRequest */
118 /* CirculateNotify */
119 /* CirculateRequest */
120 { PropertyNotify
, X11DRV_PropertyNotify
},
121 { SelectionClear
, X11DRV_SelectionClear
},
122 { SelectionRequest
, X11DRV_SelectionRequest
},
123 /* SelectionNotify */
125 { ClientMessage
, X11DRV_ClientMessage
},
126 { MappingNotify
, X11DRV_MappingNotify
},
129 static int nb_event_handlers
= 18; /* change this if you add handlers above */
132 /* return the name of an X event */
133 static const char *dbgstr_event( int type
)
135 static const char * const event_names
[] =
137 "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
138 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
139 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
140 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
141 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
142 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
143 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
144 "ClientMessage", "MappingNotify"
147 if (type
>= KeyPress
&& type
<= MappingNotify
) return event_names
[type
- KeyPress
];
148 return wine_dbg_sprintf( "Extension event %d", type
);
152 /***********************************************************************
155 * Find the handler for a given event type. Caller must hold the x11 lock.
157 static inline x11drv_event_handler
find_handler( int type
)
159 int min
= 0, max
= nb_event_handlers
- 1;
163 int pos
= (min
+ max
) / 2;
164 if (handlers
[pos
].type
== type
) return handlers
[pos
].handler
;
165 if (handlers
[pos
].type
> type
) max
= pos
- 1;
172 /***********************************************************************
173 * X11DRV_register_event_handler
175 * Register a handler for a given event type.
176 * If already registered, overwrite the previous handler.
178 void X11DRV_register_event_handler( int type
, x11drv_event_handler handler
)
184 max
= nb_event_handlers
- 1;
187 int pos
= (min
+ max
) / 2;
188 if (handlers
[pos
].type
== type
)
190 handlers
[pos
].handler
= handler
;
193 if (handlers
[pos
].type
> type
) max
= pos
- 1;
196 /* insert it between max and min */
197 memmove( &handlers
[min
+1], &handlers
[min
], (nb_event_handlers
- min
) * sizeof(handlers
[0]) );
198 handlers
[min
].type
= type
;
199 handlers
[min
].handler
= handler
;
201 assert( nb_event_handlers
<= MAX_EVENT_HANDLERS
);
204 TRACE("registered handler %p for event %d count %d\n", handler
, type
, nb_event_handlers
);
208 /***********************************************************************
211 static Bool
filter_event( Display
*display
, XEvent
*event
, char *arg
)
213 ULONG_PTR mask
= (ULONG_PTR
)arg
;
215 if ((mask
& QS_ALLINPUT
) == QS_ALLINPUT
) return 1;
223 return (mask
& QS_KEY
) != 0;
226 return (mask
& QS_MOUSEBUTTON
) != 0;
230 return (mask
& QS_MOUSEMOVE
) != 0;
232 return (mask
& QS_PAINT
) != 0;
237 case ConfigureNotify
:
240 return (mask
& QS_POSTMESSAGE
) != 0;
242 return (mask
& QS_SENDMESSAGE
) != 0;
247 enum event_merge_action
249 MERGE_DISCARD
, /* discard the old event */
250 MERGE_HANDLE
, /* handle the old event */
251 MERGE_KEEP
/* keep the old event for future merging */
254 /***********************************************************************
257 * Try to merge 2 consecutive events.
259 static enum event_merge_action
merge_events( XEvent
*prev
, XEvent
*next
)
263 case ConfigureNotify
:
266 case ConfigureNotify
:
267 if (prev
->xany
.window
== next
->xany
.window
)
269 TRACE( "discarding duplicate ConfigureNotify for window %lx\n", prev
->xany
.window
);
270 return MERGE_DISCARD
;
279 if (prev
->xany
.window
== next
->xany
.window
&& next
->type
== MotionNotify
)
281 TRACE( "discarding duplicate MotionNotify for window %lx\n", prev
->xany
.window
);
282 return MERGE_DISCARD
;
290 /***********************************************************************
293 static inline void call_event_handler( Display
*display
, XEvent
*event
)
296 x11drv_event_handler handler
;
298 struct x11drv_thread_data
*thread_data
;
300 if (!(handler
= find_handler( event
->type
)))
302 TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event
->type
), event
->xany
.window
);
303 return; /* no handler, ignore it */
306 if (XFindContext( display
, event
->xany
.window
, winContext
, (char **)&hwnd
) != 0)
307 hwnd
= 0; /* not for a registered window */
308 if (!hwnd
&& event
->xany
.window
== root_window
) hwnd
= GetDesktopWindow();
310 TRACE( "%s for hwnd/window %p/%lx\n",
311 dbgstr_event( event
->type
), hwnd
, event
->xany
.window
);
313 thread_data
= x11drv_thread_data();
314 prev
= thread_data
->current_event
;
315 thread_data
->current_event
= event
;
316 handler( hwnd
, event
);
317 thread_data
->current_event
= prev
;
322 /***********************************************************************
325 static int process_events( Display
*display
, Bool (*filter
)(), ULONG_PTR arg
)
327 XEvent event
, prev_event
;
329 enum event_merge_action action
= MERGE_DISCARD
;
333 while (XCheckIfEvent( display
, &event
, filter
, (char *)arg
))
336 if (XFilterEvent( &event
, None
)) continue; /* filtered, ignore it */
337 if (prev_event
.type
) action
= merge_events( &prev_event
, &event
);
340 case MERGE_DISCARD
: /* discard prev, keep new */
343 case MERGE_HANDLE
: /* handle prev, keep new */
344 call_event_handler( display
, &prev_event
);
347 case MERGE_KEEP
: /* handle new, keep prev for future merging */
348 call_event_handler( display
, &event
);
352 XFlush( gdi_display
);
353 if (prev_event
.type
) call_event_handler( display
, &prev_event
);
355 if (count
) TRACE( "processed %d events\n", count
);
360 /***********************************************************************
361 * MsgWaitForMultipleObjectsEx (X11DRV.@)
363 DWORD
X11DRV_MsgWaitForMultipleObjectsEx( DWORD count
, const HANDLE
*handles
,
364 DWORD timeout
, DWORD mask
, DWORD flags
)
367 struct x11drv_thread_data
*data
= TlsGetValue( thread_data_tls_index
);
371 if (!count
&& !timeout
) return WAIT_TIMEOUT
;
372 return WaitForMultipleObjectsEx( count
, handles
, flags
& MWMO_WAITALL
,
373 timeout
, flags
& MWMO_ALERTABLE
);
376 if (data
->current_event
) mask
= 0; /* don't process nested events */
378 if (process_events( data
->display
, filter_event
, mask
)) ret
= count
- 1;
379 else if (count
|| timeout
)
381 ret
= WaitForMultipleObjectsEx( count
, handles
, flags
& MWMO_WAITALL
,
382 timeout
, flags
& MWMO_ALERTABLE
);
383 if (ret
== count
- 1) process_events( data
->display
, filter_event
, mask
);
385 else ret
= WAIT_TIMEOUT
;
390 /***********************************************************************
391 * EVENT_x11_time_to_win32_time
393 * Make our timer and the X timer line up as best we can
394 * Pass 0 to retrieve the current adjustment value (times -1)
396 DWORD
EVENT_x11_time_to_win32_time(Time time
)
398 static DWORD adjust
= 0;
399 DWORD now
= GetTickCount();
402 if (! adjust
&& time
!= 0)
409 /* If we got an event in the 'future', then our clock is clearly wrong.
410 If we got it more than 10000 ms in the future, then it's most likely
411 that the clock has wrapped. */
414 if (ret
> now
&& ((ret
- now
) < 10000) && time
!= 0)
425 /*******************************************************************
426 * can_activate_window
428 * Check if we can activate the specified window.
430 static inline BOOL
can_activate_window( HWND hwnd
)
432 LONG style
= GetWindowLongW( hwnd
, GWL_STYLE
);
433 if (!(style
& WS_VISIBLE
)) return FALSE
;
434 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return FALSE
;
435 if (hwnd
== GetDesktopWindow()) return FALSE
;
436 return !(style
& WS_DISABLED
);
440 /**********************************************************************
443 static void set_focus( HWND hwnd
, Time time
)
448 TRACE( "setting foreground window to %p\n", hwnd
);
449 SetForegroundWindow( hwnd
);
452 if (focus
) focus
= GetAncestor( focus
, GA_ROOT
);
453 win
= X11DRV_get_whole_window(focus
);
457 TRACE( "setting focus to %p (%lx) time=%ld\n", focus
, win
, time
);
459 XSetInputFocus( thread_display(), win
, RevertToParent
, time
);
465 /**********************************************************************
466 * handle_wm_protocols
468 static void handle_wm_protocols( HWND hwnd
, XClientMessageEvent
*event
)
470 Atom protocol
= (Atom
)event
->data
.l
[0];
472 if (!protocol
) return;
474 if (protocol
== x11drv_atom(WM_DELETE_WINDOW
))
476 /* Ignore the delete window request if the window has been disabled
477 * and we are in managed mode. This is to disallow applications from
478 * being closed by the window manager while in a modal state.
480 if (IsWindowEnabled(hwnd
))
484 if (GetClassLongW(hwnd
, GCL_STYLE
) & CS_NOCLOSE
) return;
485 hSysMenu
= GetSystemMenu(hwnd
, FALSE
);
488 UINT state
= GetMenuState(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
);
489 if (state
== 0xFFFFFFFF || (state
& (MF_DISABLED
| MF_GRAYED
)))
492 if (GetActiveWindow() != hwnd
)
494 LRESULT ma
= SendMessageW( hwnd
, WM_MOUSEACTIVATE
,
495 (WPARAM
)GetAncestor( hwnd
, GA_ROOT
),
496 MAKELONG(HTCLOSE
,WM_LBUTTONDOWN
) );
499 case MA_NOACTIVATEANDEAT
:
500 case MA_ACTIVATEANDEAT
:
506 SetActiveWindow(hwnd
);
509 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma
);
513 PostMessageW( hwnd
, WM_X11DRV_DELETE_WINDOW
, 0, 0 );
516 else if (protocol
== x11drv_atom(WM_TAKE_FOCUS
))
518 Time event_time
= (Time
)event
->data
.l
[1];
519 HWND last_focus
= x11drv_thread_data()->last_focus
;
521 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
522 hwnd
, IsWindowEnabled(hwnd
), IsWindowVisible(hwnd
), GetWindowLongW(hwnd
, GWL_STYLE
),
523 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus
);
525 if (can_activate_window(hwnd
))
527 /* simulate a mouse click on the caption to find out
528 * whether the window wants to be activated */
529 LRESULT ma
= SendMessageW( hwnd
, WM_MOUSEACTIVATE
,
530 (WPARAM
)GetAncestor( hwnd
, GA_ROOT
),
531 MAKELONG(HTCAPTION
,WM_LBUTTONDOWN
) );
532 if (ma
!= MA_NOACTIVATEANDEAT
&& ma
!= MA_NOACTIVATE
)
534 set_focus( hwnd
, event_time
);
538 /* try to find some other window to give the focus to */
540 if (hwnd
) hwnd
= GetAncestor( hwnd
, GA_ROOT
);
541 if (!hwnd
) hwnd
= GetActiveWindow();
542 if (!hwnd
) hwnd
= last_focus
;
543 if (hwnd
&& can_activate_window(hwnd
)) set_focus( hwnd
, event_time
);
545 else if (protocol
== x11drv_atom(_NET_WM_PING
))
547 XClientMessageEvent xev
;
550 TRACE("NET_WM Ping\n");
552 xev
.window
= DefaultRootWindow(xev
.display
);
553 XSendEvent(xev
.display
, xev
.window
, False
, SubstructureRedirectMask
| SubstructureNotifyMask
, (XEvent
*)&xev
);
555 /* this line is semi-stolen from gtk2 */
556 TRACE("NET_WM Pong\n");
561 static const char * const focus_details
[] =
567 "NotifyNonlinearVirtual",
573 /**********************************************************************
576 static void X11DRV_FocusIn( HWND hwnd
, XEvent
*xev
)
578 XFocusChangeEvent
*event
= &xev
->xfocus
;
583 TRACE( "win %p xwin %lx detail=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
] );
585 if (event
->detail
== NotifyPointer
) return;
587 if ((xic
= X11DRV_get_ic( hwnd
)))
593 if (use_take_focus
) return; /* ignore FocusIn if we are using take focus */
595 if (!can_activate_window(hwnd
))
597 HWND hwnd
= GetFocus();
598 if (hwnd
) hwnd
= GetAncestor( hwnd
, GA_ROOT
);
599 if (!hwnd
) hwnd
= GetActiveWindow();
600 if (!hwnd
) hwnd
= x11drv_thread_data()->last_focus
;
601 if (hwnd
&& can_activate_window(hwnd
)) set_focus( hwnd
, CurrentTime
);
603 else SetForegroundWindow( hwnd
);
607 /**********************************************************************
610 * Note: only top-level windows get FocusOut events.
612 static void X11DRV_FocusOut( HWND hwnd
, XEvent
*xev
)
614 XFocusChangeEvent
*event
= &xev
->xfocus
;
622 TRACE( "win %p xwin %lx detail=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
] );
624 if (event
->detail
== NotifyPointer
) return;
625 if (ximInComposeMode
) return;
627 x11drv_thread_data()->last_focus
= hwnd
;
628 if ((xic
= X11DRV_get_ic( hwnd
)))
631 XUnsetICFocus( xic
);
634 if (hwnd
!= GetForegroundWindow()) return;
635 SendMessageW( hwnd
, WM_CANCELMODE
, 0, 0 );
637 /* don't reset the foreground window, if the window which is
638 getting the focus is a Wine window */
641 XGetInputFocus( thread_display(), &focus_win
, &revert
);
644 if (XFindContext( thread_display(), focus_win
, winContext
, (char **)&hwnd_tmp
) != 0)
651 /* Abey : 6-Oct-99. Check again if the focus out window is the
652 Foreground window, because in most cases the messages sent
653 above must have already changed the foreground window, in which
654 case we don't have to change the foreground window to 0 */
655 if (hwnd
== GetForegroundWindow())
657 TRACE( "lost focus, setting fg to desktop\n" );
658 SetForegroundWindow( GetDesktopWindow() );
664 /***********************************************************************
667 static void X11DRV_Expose( HWND hwnd
, XEvent
*xev
)
669 XExposeEvent
*event
= &xev
->xexpose
;
671 struct x11drv_win_data
*data
;
672 int flags
= RDW_INVALIDATE
| RDW_ERASE
;
674 TRACE( "win %p (%lx) %d,%d %dx%d\n",
675 hwnd
, event
->window
, event
->x
, event
->y
, event
->width
, event
->height
);
677 if (!(data
= X11DRV_get_win_data( hwnd
))) return;
679 if (event
->window
== data
->whole_window
)
681 rect
.left
= data
->whole_rect
.left
+ event
->x
;
682 rect
.top
= data
->whole_rect
.top
+ event
->y
;
687 rect
.left
= data
->client_rect
.left
+ event
->x
;
688 rect
.top
= data
->client_rect
.top
+ event
->y
;
690 rect
.right
= rect
.left
+ event
->width
;
691 rect
.bottom
= rect
.top
+ event
->height
;
693 if (event
->window
!= root_window
)
695 SERVER_START_REQ( update_window_zorder
)
698 req
->rect
.left
= rect
.left
;
699 req
->rect
.top
= rect
.top
;
700 req
->rect
.right
= rect
.right
;
701 req
->rect
.bottom
= rect
.bottom
;
702 wine_server_call( req
);
706 /* make position relative to client area instead of parent */
707 OffsetRect( &rect
, -data
->client_rect
.left
, -data
->client_rect
.top
);
708 flags
|= RDW_ALLCHILDREN
;
711 RedrawWindow( hwnd
, &rect
, 0, flags
);
715 /**********************************************************************
718 static void X11DRV_MapNotify( HWND hwnd
, XEvent
*event
)
720 struct x11drv_win_data
*data
;
722 if (!(data
= X11DRV_get_win_data( hwnd
))) return;
723 if (!data
->mapped
) return;
727 HWND hwndFocus
= GetFocus();
728 if (hwndFocus
&& IsChild( hwnd
, hwndFocus
)) X11DRV_SetFocus(hwndFocus
); /* FIXME */
733 /***********************************************************************
734 * get_window_wm_state
736 int get_window_wm_state( Display
*display
, struct x11drv_win_data
*data
)
744 int format
, ret
= -1;
745 unsigned long count
, remaining
;
748 if (!XGetWindowProperty( display
, data
->whole_window
, x11drv_atom(WM_STATE
), 0,
749 sizeof(*state
)/sizeof(CARD32
), False
, x11drv_atom(WM_STATE
),
750 &type
, &format
, &count
, &remaining
, (unsigned char **)&state
))
752 if (type
== x11drv_atom(WM_STATE
) && get_property_size( format
, count
) >= sizeof(*state
))
761 /***********************************************************************
762 * handle_wm_state_notify
764 * Handle a PropertyNotify for WM_STATE.
766 static void handle_wm_state_notify( struct x11drv_win_data
*data
, XPropertyEvent
*event
,
772 data
->wm_state
= WithdrawnState
;
773 TRACE( "%p/%lx: WM_STATE deleted\n", data
->hwnd
, data
->whole_window
);
775 case PropertyNewValue
:
777 int new_state
= get_window_wm_state( event
->display
, data
);
778 if (new_state
!= -1 && new_state
!= data
->wm_state
)
780 TRACE( "%p/%lx: new WM_STATE %d\n", data
->hwnd
, data
->whole_window
, new_state
);
781 data
->wm_state
= new_state
;
787 if (!update_window
|| !data
->managed
|| !data
->mapped
) return;
789 if (data
->iconic
&& data
->wm_state
== NormalState
) /* restore window */
792 unsigned int width
, height
, border
, depth
;
799 XGetGeometry( event
->display
, data
->whole_window
, &root
, &x
, &y
, &width
, &height
,
801 XTranslateCoordinates( event
->display
, data
->whole_window
, root
, 0, 0, &x
, &y
, &top
);
805 rect
.right
= x
+ width
;
806 rect
.bottom
= y
+ height
;
807 OffsetRect( &rect
, virtual_screen_rect
.left
, virtual_screen_rect
.top
);
808 X11DRV_X_to_window_rect( data
, &rect
);
810 wp
.length
= sizeof(wp
);
811 GetWindowPlacement( data
->hwnd
, &wp
);
813 wp
.showCmd
= SW_RESTORE
;
814 wp
.rcNormalPosition
= rect
;
816 TRACE( "restoring win %p/%lx\n", data
->hwnd
, data
->whole_window
);
817 data
->iconic
= FALSE
;
818 SetWindowPlacement( data
->hwnd
, &wp
);
820 else if (!data
->iconic
&& data
->wm_state
== IconicState
)
822 TRACE( "minimizing win %p/%lx\n", data
->hwnd
, data
->whole_window
);
824 ShowWindow( data
->hwnd
, SW_MINIMIZE
);
829 /***********************************************************************
830 * X11DRV_PropertyNotify
832 static void X11DRV_PropertyNotify( HWND hwnd
, XEvent
*xev
)
834 XPropertyEvent
*event
= &xev
->xproperty
;
835 struct x11drv_win_data
*data
;
838 if (!(data
= X11DRV_get_win_data( hwnd
))) return;
840 if (event
->atom
== x11drv_atom(WM_STATE
)) handle_wm_state_notify( data
, event
, TRUE
);
844 /* event filter to wait for a WM_STATE change notification on a window */
845 static Bool
is_wm_state_notify( Display
*display
, XEvent
*event
, XPointer arg
)
847 if (event
->xany
.window
!= (Window
)arg
) return 0;
848 return (event
->type
== DestroyNotify
||
849 (event
->type
== PropertyNotify
&& event
->xproperty
.atom
== x11drv_atom(WM_STATE
)));
852 /***********************************************************************
853 * wait_for_withdrawn_state
855 void wait_for_withdrawn_state( Display
*display
, struct x11drv_win_data
*data
, BOOL set
)
857 DWORD end
= GetTickCount() + 2000;
859 if (!data
->managed
) return;
861 TRACE( "waiting for window %p/%lx to become %swithdrawn\n",
862 data
->hwnd
, data
->whole_window
, set
? "" : "not " );
864 while (data
->whole_window
&& ((data
->wm_state
== WithdrawnState
) == !set
))
870 while (XCheckIfEvent( display
, &event
, is_wm_state_notify
, (char *)data
->whole_window
))
873 if (XFilterEvent( &event
, None
)) continue; /* filtered, ignore it */
874 if (event
.type
== DestroyNotify
) call_event_handler( display
, &event
);
878 handle_wm_state_notify( data
, &event
.xproperty
, FALSE
);
887 int timeout
= end
- GetTickCount();
889 pfd
.fd
= ConnectionNumber(display
);
891 if (timeout
<= 0 || poll( &pfd
, 1, timeout
) != 1)
893 FIXME( "window %p/%lx wait timed out\n", data
->hwnd
, data
->whole_window
);
898 TRACE( "window %p/%lx state now %d\n", data
->hwnd
, data
->whole_window
, data
->wm_state
);
902 static HWND
find_drop_window( HWND hQueryWnd
, LPPOINT lpPt
)
906 if (!IsWindowEnabled(hQueryWnd
)) return 0;
908 GetWindowRect(hQueryWnd
, &tempRect
);
910 if(!PtInRect(&tempRect
, *lpPt
)) return 0;
912 if (!IsIconic( hQueryWnd
))
915 ScreenToClient( hQueryWnd
, &pt
);
916 GetClientRect( hQueryWnd
, &tempRect
);
918 if (PtInRect( &tempRect
, pt
))
920 HWND ret
= ChildWindowFromPointEx( hQueryWnd
, pt
, CWP_SKIPINVISIBLE
|CWP_SKIPDISABLED
);
921 if (ret
&& ret
!= hQueryWnd
)
923 ret
= find_drop_window( ret
, lpPt
);
929 if(!(GetWindowLongA( hQueryWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return 0;
931 ScreenToClient(hQueryWnd
, lpPt
);
936 /**********************************************************************
937 * EVENT_DropFromOffix
939 * don't know if it still works (last Changelog is from 96/11/04)
941 static void EVENT_DropFromOffiX( HWND hWnd
, XClientMessageEvent
*event
)
943 struct x11drv_win_data
*data
;
944 unsigned long data_length
;
945 unsigned long aux_long
;
946 unsigned char* p_data
= NULL
;
950 Window win
, w_aux_root
, w_aux_child
;
953 win
= X11DRV_get_whole_window(hWnd
);
955 XQueryPointer( event
->display
, win
, &w_aux_root
, &w_aux_child
,
956 &x
, &y
, &dummy
, &dummy
, (unsigned int*)&aux_long
);
957 x
+= virtual_screen_rect
.left
;
958 y
+= virtual_screen_rect
.top
;
961 if (!(data
= X11DRV_get_win_data( hWnd
))) return;
963 /* find out drop point and drop window */
964 if( x
< 0 || y
< 0 ||
965 x
> (data
->whole_rect
.right
- data
->whole_rect
.left
) ||
966 y
> (data
->whole_rect
.bottom
- data
->whole_rect
.top
) )
968 bAccept
= GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
;
975 HWND hwndDrop
= find_drop_window( hWnd
, &pt
);
989 if (!bAccept
) return;
992 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
993 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
994 AnyPropertyType
, &atom_aux
, &dummy
,
995 &data_length
, &aux_long
, &p_data
);
998 if( !aux_long
&& p_data
) /* don't bother if > 64K */
1000 char *p
= (char *)p_data
;
1004 while( *p
) /* calculate buffer size */
1006 INT len
= GetShortPathNameA( p
, NULL
, 0 );
1007 if (len
) aux_long
+= len
+ 1;
1010 if( aux_long
&& aux_long
< 65535 )
1015 aux_long
+= sizeof(DROPFILES
) + 1;
1016 hDrop
= GlobalAlloc( GMEM_SHARE
, aux_long
);
1017 lpDrop
= (DROPFILES
*)GlobalLock( hDrop
);
1021 lpDrop
->pFiles
= sizeof(DROPFILES
);
1024 lpDrop
->fNC
= FALSE
;
1025 lpDrop
->fWide
= FALSE
;
1026 p_drop
= (char *)(lpDrop
+ 1);
1030 if (GetShortPathNameA( p
, p_drop
, aux_long
- (p_drop
- (char *)lpDrop
) ))
1031 p_drop
+= strlen( p_drop
) + 1;
1035 PostMessageA( hWnd
, WM_DROPFILES
, (WPARAM
)hDrop
, 0L );
1040 if( p_data
) XFree(p_data
);
1041 wine_tsx11_unlock();
1044 /**********************************************************************
1047 * drop items are separated by \n
1048 * each item is prefixed by its mime type
1050 * event->data.l[3], event->data.l[4] contains drop x,y position
1052 static void EVENT_DropURLs( HWND hWnd
, XClientMessageEvent
*event
)
1054 struct x11drv_win_data
*win_data
;
1055 unsigned long data_length
;
1056 unsigned long aux_long
, drop_len
= 0;
1057 unsigned char *p_data
= NULL
; /* property data */
1058 char *p_drop
= NULL
;
1070 if (!(GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return;
1073 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
1074 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
1075 AnyPropertyType
, &u
.atom_aux
, &u
.i
,
1076 &data_length
, &aux_long
, &p_data
);
1077 wine_tsx11_unlock();
1079 WARN("property too large, truncated!\n");
1080 TRACE("urls=%s\n", p_data
);
1082 if( !aux_long
&& p_data
) { /* don't bother if > 64K */
1083 /* calculate length */
1085 next
= strchr(p
, '\n');
1088 if (strncmp(p
,"file:",5) == 0 ) {
1089 INT len
= GetShortPathNameA( p
+5, NULL
, 0 );
1090 if (len
) drop_len
+= len
+ 1;
1095 next
= strchr(p
, '\n');
1101 if( drop_len
&& drop_len
< 65535 ) {
1103 XQueryPointer( event
->display
, root_window
, &u
.w_aux
, &u
.w_aux
,
1104 &x
, &y
, &u
.i
, &u
.i
, &u
.u
);
1105 x
+= virtual_screen_rect
.left
;
1106 y
+= virtual_screen_rect
.top
;
1107 wine_tsx11_unlock();
1109 drop_len
+= sizeof(DROPFILES
) + 1;
1110 hDrop
= GlobalAlloc( GMEM_SHARE
, drop_len
);
1111 lpDrop
= (DROPFILES
*) GlobalLock( hDrop
);
1113 if( lpDrop
&& (win_data
= X11DRV_get_win_data( hWnd
)))
1115 lpDrop
->pFiles
= sizeof(DROPFILES
);
1119 ( x
< (win_data
->client_rect
.left
- win_data
->whole_rect
.left
) ||
1120 y
< (win_data
->client_rect
.top
- win_data
->whole_rect
.top
) ||
1121 x
> (win_data
->client_rect
.right
- win_data
->whole_rect
.left
) ||
1122 y
> (win_data
->client_rect
.bottom
- win_data
->whole_rect
.top
) );
1123 lpDrop
->fWide
= FALSE
;
1124 p_drop
= (char*)(lpDrop
+ 1);
1127 /* create message content */
1130 next
= strchr(p
, '\n');
1133 if (strncmp(p
,"file:",5) == 0 ) {
1134 INT len
= GetShortPathNameA( p
+5, p_drop
, 65535 );
1136 TRACE("drop file %s as %s\n", p
+5, p_drop
);
1139 WARN("can't convert file %s to dos name\n", p
+5);
1142 WARN("unknown mime type %s\n", p
);
1147 next
= strchr(p
, '\n');
1154 GlobalUnlock(hDrop
);
1155 PostMessageA( hWnd
, WM_DROPFILES
, (WPARAM
)hDrop
, 0L );
1159 if( p_data
) XFree(p_data
);
1160 wine_tsx11_unlock();
1164 /**********************************************************************
1165 * handle_dnd_protocol
1167 static void handle_dnd_protocol( HWND hwnd
, XClientMessageEvent
*event
)
1170 int root_x
, root_y
, child_x
, child_y
;
1173 /* query window (drag&drop event contains only drag window) */
1175 XQueryPointer( event
->display
, root_window
, &root
, &child
,
1176 &root_x
, &root_y
, &child_x
, &child_y
, &u
);
1177 if (XFindContext( event
->display
, child
, winContext
, (char **)&hwnd
) != 0) hwnd
= 0;
1178 wine_tsx11_unlock();
1180 if (event
->data
.l
[0] == DndFile
|| event
->data
.l
[0] == DndFiles
)
1181 EVENT_DropFromOffiX(hwnd
, event
);
1182 else if (event
->data
.l
[0] == DndURL
)
1183 EVENT_DropURLs(hwnd
, event
);
1187 struct client_message_handler
1189 int atom
; /* protocol atom */
1190 void (*handler
)(HWND
, XClientMessageEvent
*); /* corresponding handler function */
1193 static const struct client_message_handler client_messages
[] =
1195 { XATOM_WM_PROTOCOLS
, handle_wm_protocols
},
1196 { XATOM_DndProtocol
, handle_dnd_protocol
},
1197 { XATOM_XdndEnter
, X11DRV_XDND_EnterEvent
},
1198 { XATOM_XdndPosition
, X11DRV_XDND_PositionEvent
},
1199 { XATOM_XdndDrop
, X11DRV_XDND_DropEvent
},
1200 { XATOM_XdndLeave
, X11DRV_XDND_LeaveEvent
}
1204 /**********************************************************************
1205 * X11DRV_ClientMessage
1207 static void X11DRV_ClientMessage( HWND hwnd
, XEvent
*xev
)
1209 XClientMessageEvent
*event
= &xev
->xclient
;
1214 if (event
->format
!= 32)
1216 WARN( "Don't know how to handle format %d\n", event
->format
);
1220 for (i
= 0; i
< sizeof(client_messages
)/sizeof(client_messages
[0]); i
++)
1222 if (event
->message_type
== X11DRV_Atoms
[client_messages
[i
].atom
- FIRST_XATOM
])
1224 client_messages
[i
].handler( hwnd
, event
);
1228 TRACE( "no handler found for %ld\n", event
->message_type
);
1232 /**********************************************************************
1233 * X11DRV_WindowMessage (X11DRV.@)
1235 LRESULT
X11DRV_WindowMessage( HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
1239 case WM_X11DRV_ACQUIRE_SELECTION
:
1240 return X11DRV_AcquireClipboard( hwnd
);
1241 case WM_X11DRV_DELETE_WINDOW
:
1242 return SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_CLOSE
, 0 );
1243 case WM_X11DRV_SET_WIN_FORMAT
:
1244 return X11DRV_set_win_format( hwnd
, (XID
)wp
);
1245 case WM_X11DRV_RESIZE_DESKTOP
:
1246 X11DRV_resize_desktop( LOWORD(lp
), HIWORD(lp
) );
1249 FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg
, hwnd
, wp
, lp
);
1255 /***********************************************************************
1256 * X11DRV_SendInput (X11DRV.@)
1258 UINT
X11DRV_SendInput( UINT count
, LPINPUT inputs
, int size
)
1262 for (i
= 0; i
< count
; i
++, inputs
++)
1264 switch(inputs
->type
)
1267 X11DRV_send_mouse_input( 0, inputs
->u
.mi
.dwFlags
, inputs
->u
.mi
.dx
, inputs
->u
.mi
.dy
,
1268 inputs
->u
.mi
.mouseData
, inputs
->u
.mi
.time
,
1269 inputs
->u
.mi
.dwExtraInfo
, LLMHF_INJECTED
);
1271 case INPUT_KEYBOARD
:
1272 X11DRV_send_keyboard_input( inputs
->u
.ki
.wVk
, inputs
->u
.ki
.wScan
, inputs
->u
.ki
.dwFlags
,
1273 inputs
->u
.ki
.time
, inputs
->u
.ki
.dwExtraInfo
, LLKHF_INJECTED
);
1275 case INPUT_HARDWARE
:
1276 FIXME( "INPUT_HARDWARE not supported\n" );