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/debug.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(event
);
58 extern BOOL ximInComposeMode
;
60 #define DndNotDnd -1 /* OffiX drag&drop */
72 #define DndURL 128 /* KDE drag&drop */
75 static void EVENT_FocusIn( HWND hwnd
, XEvent
*event
);
76 static void EVENT_FocusOut( HWND hwnd
, XEvent
*event
);
77 static void EVENT_PropertyNotify( HWND hwnd
, XEvent
*event
);
78 static void EVENT_ClientMessage( HWND hwnd
, XEvent
*event
);
82 int type
; /* event type */
83 x11drv_event_handler handler
; /* corresponding handler function */
86 #define MAX_EVENT_HANDLERS 64
88 static struct event_handler handlers
[MAX_EVENT_HANDLERS
] =
90 /* list must be sorted by event type */
91 { KeyPress
, X11DRV_KeyEvent
},
92 { KeyRelease
, X11DRV_KeyEvent
},
93 { ButtonPress
, X11DRV_ButtonPress
},
94 { ButtonRelease
, X11DRV_ButtonRelease
},
95 { MotionNotify
, X11DRV_MotionNotify
},
96 { EnterNotify
, X11DRV_EnterNotify
},
98 { FocusIn
, EVENT_FocusIn
},
99 { FocusOut
, EVENT_FocusOut
},
100 { KeymapNotify
, X11DRV_KeymapNotify
},
101 { Expose
, X11DRV_Expose
},
104 /* VisibilityNotify */
106 { DestroyNotify
, X11DRV_DestroyNotify
},
108 { MapNotify
, X11DRV_MapNotify
},
111 { ConfigureNotify
, X11DRV_ConfigureNotify
},
112 /* ConfigureRequest */
115 /* CirculateNotify */
116 /* CirculateRequest */
117 { PropertyNotify
, EVENT_PropertyNotify
},
118 { SelectionClear
, X11DRV_SelectionClear
},
119 { SelectionRequest
, X11DRV_SelectionRequest
},
120 /* SelectionNotify */
122 { ClientMessage
, EVENT_ClientMessage
},
123 { MappingNotify
, X11DRV_MappingNotify
},
126 static int nb_event_handlers
= 18; /* change this if you add handlers above */
129 /* return the name of an X event */
130 static const char *dbgstr_event( int type
)
132 static const char * const event_names
[] =
134 "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
135 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
136 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
137 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
138 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
139 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
140 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
141 "ClientMessage", "MappingNotify"
144 if (type
>= KeyPress
&& type
<= MappingNotify
) return event_names
[type
- KeyPress
];
145 return wine_dbg_sprintf( "Extension event %d", type
);
149 /***********************************************************************
152 * Find the handler for a given event type. Caller must hold the x11 lock.
154 static inline x11drv_event_handler
find_handler( int type
)
156 int min
= 0, max
= nb_event_handlers
- 1;
160 int pos
= (min
+ max
) / 2;
161 if (handlers
[pos
].type
== type
) return handlers
[pos
].handler
;
162 if (handlers
[pos
].type
> type
) max
= pos
- 1;
169 /***********************************************************************
170 * X11DRV_register_event_handler
172 * Register a handler for a given event type.
173 * If already registered, overwrite the previous handler.
175 void X11DRV_register_event_handler( int type
, x11drv_event_handler handler
)
181 max
= nb_event_handlers
- 1;
184 int pos
= (min
+ max
) / 2;
185 if (handlers
[pos
].type
== type
)
187 handlers
[pos
].handler
= handler
;
190 if (handlers
[pos
].type
> type
) max
= pos
- 1;
193 /* insert it between max and min */
194 memmove( &handlers
[min
+1], &handlers
[min
], (nb_event_handlers
- min
) * sizeof(handlers
[0]) );
195 handlers
[min
].type
= type
;
196 handlers
[min
].handler
= handler
;
198 assert( nb_event_handlers
<= MAX_EVENT_HANDLERS
);
201 TRACE("registered handler %p for event %d count %d\n", handler
, type
, nb_event_handlers
);
205 /***********************************************************************
208 static Bool
filter_event( Display
*display
, XEvent
*event
, char *arg
)
210 ULONG_PTR mask
= (ULONG_PTR
)arg
;
212 if ((mask
& QS_ALLINPUT
) == QS_ALLINPUT
) return 1;
220 return (mask
& QS_KEY
) != 0;
223 return (mask
& QS_MOUSEBUTTON
) != 0;
227 return (mask
& QS_MOUSEMOVE
) != 0;
229 return (mask
& QS_PAINT
) != 0;
234 case ConfigureNotify
:
237 return (mask
& QS_POSTMESSAGE
) != 0;
239 return (mask
& QS_SENDMESSAGE
) != 0;
244 enum event_merge_action
246 MERGE_DISCARD
, /* discard the old event */
247 MERGE_HANDLE
, /* handle the old event */
248 MERGE_KEEP
/* keep the old event for future merging */
251 /***********************************************************************
254 * Try to merge 2 consecutive events.
256 static enum event_merge_action
merge_events( XEvent
*prev
, XEvent
*next
)
260 case ConfigureNotify
:
263 case ConfigureNotify
:
264 if (prev
->xany
.window
== next
->xany
.window
)
266 TRACE( "discarding duplicate ConfigureNotify for window %lx\n", prev
->xany
.window
);
267 return MERGE_DISCARD
;
276 if (prev
->xany
.window
== next
->xany
.window
&& next
->type
== MotionNotify
)
278 TRACE( "discarding duplicate MotionNotify for window %lx\n", prev
->xany
.window
);
279 return MERGE_DISCARD
;
287 /***********************************************************************
290 static inline void call_event_handler( Display
*display
, XEvent
*event
)
293 x11drv_event_handler handler
;
295 struct x11drv_thread_data
*thread_data
;
297 if (!(handler
= find_handler( event
->type
)))
299 TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event
->type
), event
->xany
.window
);
300 return; /* no handler, ignore it */
303 if (XFindContext( display
, event
->xany
.window
, winContext
, (char **)&hwnd
) != 0)
304 hwnd
= 0; /* not for a registered window */
305 if (!hwnd
&& event
->xany
.window
== root_window
) hwnd
= GetDesktopWindow();
307 TRACE( "%s for hwnd/window %p/%lx\n",
308 dbgstr_event( event
->type
), hwnd
, event
->xany
.window
);
310 thread_data
= x11drv_thread_data();
311 prev
= thread_data
->current_event
;
312 thread_data
->current_event
= event
;
313 handler( hwnd
, event
);
314 thread_data
->current_event
= prev
;
319 /***********************************************************************
322 static int process_events( Display
*display
, Bool (*filter
)(), ULONG_PTR arg
)
324 XEvent event
, prev_event
;
326 enum event_merge_action action
= MERGE_DISCARD
;
330 while (XCheckIfEvent( display
, &event
, filter
, (char *)arg
))
333 if (XFilterEvent( &event
, None
)) continue; /* filtered, ignore it */
334 if (prev_event
.type
) action
= merge_events( &prev_event
, &event
);
337 case MERGE_DISCARD
: /* discard prev, keep new */
340 case MERGE_HANDLE
: /* handle prev, keep new */
341 call_event_handler( display
, &prev_event
);
344 case MERGE_KEEP
: /* handle new, keep prev for future merging */
345 call_event_handler( display
, &event
);
349 XFlush( gdi_display
);
350 if (prev_event
.type
) call_event_handler( display
, &prev_event
);
352 if (count
) TRACE( "processed %d events\n", count
);
357 /***********************************************************************
358 * MsgWaitForMultipleObjectsEx (X11DRV.@)
360 DWORD
X11DRV_MsgWaitForMultipleObjectsEx( DWORD count
, const HANDLE
*handles
,
361 DWORD timeout
, DWORD mask
, DWORD flags
)
364 struct x11drv_thread_data
*data
= TlsGetValue( thread_data_tls_index
);
368 if (!count
&& !timeout
) return WAIT_TIMEOUT
;
369 return WaitForMultipleObjectsEx( count
, handles
, flags
& MWMO_WAITALL
,
370 timeout
, flags
& MWMO_ALERTABLE
);
373 if (data
->current_event
) mask
= 0; /* don't process nested events */
375 if (process_events( data
->display
, filter_event
, mask
)) ret
= count
- 1;
376 else if (count
|| timeout
)
378 ret
= WaitForMultipleObjectsEx( count
, handles
, flags
& MWMO_WAITALL
,
379 timeout
, flags
& MWMO_ALERTABLE
);
380 if (ret
== count
- 1) process_events( data
->display
, filter_event
, mask
);
382 else ret
= WAIT_TIMEOUT
;
387 /***********************************************************************
388 * EVENT_x11_time_to_win32_time
390 * Make our timer and the X timer line up as best we can
391 * Pass 0 to retrieve the current adjustment value (times -1)
393 DWORD
EVENT_x11_time_to_win32_time(Time time
)
395 static DWORD adjust
= 0;
396 DWORD now
= GetTickCount();
399 if (! adjust
&& time
!= 0)
406 /* If we got an event in the 'future', then our clock is clearly wrong.
407 If we got it more than 10000 ms in the future, then it's most likely
408 that the clock has wrapped. */
411 if (ret
> now
&& ((ret
- now
) < 10000) && time
!= 0)
422 /*******************************************************************
423 * can_activate_window
425 * Check if we can activate the specified window.
427 static inline BOOL
can_activate_window( HWND hwnd
)
429 LONG style
= GetWindowLongW( hwnd
, GWL_STYLE
);
430 if (!(style
& WS_VISIBLE
)) return FALSE
;
431 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return FALSE
;
432 if (hwnd
== GetDesktopWindow()) return FALSE
;
433 return !(style
& WS_DISABLED
);
437 /**********************************************************************
440 static void set_focus( HWND hwnd
, Time time
)
445 TRACE( "setting foreground window to %p\n", hwnd
);
446 SetForegroundWindow( hwnd
);
449 if (focus
) focus
= GetAncestor( focus
, GA_ROOT
);
450 win
= X11DRV_get_whole_window(focus
);
454 TRACE( "setting focus to %p (%lx) time=%ld\n", focus
, win
, time
);
456 XSetInputFocus( thread_display(), win
, RevertToParent
, time
);
462 /**********************************************************************
463 * handle_wm_protocols
465 static void handle_wm_protocols( HWND hwnd
, XClientMessageEvent
*event
)
467 Atom protocol
= (Atom
)event
->data
.l
[0];
469 if (!protocol
) return;
471 if (protocol
== x11drv_atom(WM_DELETE_WINDOW
))
473 /* Ignore the delete window request if the window has been disabled
474 * and we are in managed mode. This is to disallow applications from
475 * being closed by the window manager while in a modal state.
477 if (IsWindowEnabled(hwnd
))
481 if (GetClassLongW(hwnd
, GCL_STYLE
) & CS_NOCLOSE
) return;
482 hSysMenu
= GetSystemMenu(hwnd
, FALSE
);
485 UINT state
= GetMenuState(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
);
486 if (state
== 0xFFFFFFFF || (state
& (MF_DISABLED
| MF_GRAYED
)))
489 if (GetActiveWindow() != hwnd
)
491 LRESULT ma
= SendMessageW( hwnd
, WM_MOUSEACTIVATE
,
492 (WPARAM
)GetAncestor( hwnd
, GA_ROOT
),
493 MAKELONG(HTCLOSE
,WM_LBUTTONDOWN
) );
496 case MA_NOACTIVATEANDEAT
:
497 case MA_ACTIVATEANDEAT
:
503 SetActiveWindow(hwnd
);
506 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma
);
510 PostMessageW( hwnd
, WM_X11DRV_DELETE_WINDOW
, 0, 0 );
513 else if (protocol
== x11drv_atom(WM_TAKE_FOCUS
))
515 Time event_time
= (Time
)event
->data
.l
[1];
516 HWND last_focus
= x11drv_thread_data()->last_focus
;
518 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
519 hwnd
, IsWindowEnabled(hwnd
), IsWindowVisible(hwnd
), GetWindowLongW(hwnd
, GWL_STYLE
),
520 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus
);
522 if (can_activate_window(hwnd
))
524 /* simulate a mouse click on the caption to find out
525 * whether the window wants to be activated */
526 LRESULT ma
= SendMessageW( hwnd
, WM_MOUSEACTIVATE
,
527 (WPARAM
)GetAncestor( hwnd
, GA_ROOT
),
528 MAKELONG(HTCAPTION
,WM_LBUTTONDOWN
) );
529 if (ma
!= MA_NOACTIVATEANDEAT
&& ma
!= MA_NOACTIVATE
)
531 set_focus( hwnd
, event_time
);
535 /* try to find some other window to give the focus to */
537 if (hwnd
) hwnd
= GetAncestor( hwnd
, GA_ROOT
);
538 if (!hwnd
) hwnd
= GetActiveWindow();
539 if (!hwnd
) hwnd
= last_focus
;
540 if (hwnd
&& can_activate_window(hwnd
)) set_focus( hwnd
, event_time
);
542 else if (protocol
== x11drv_atom(_NET_WM_PING
))
544 XClientMessageEvent xev
;
547 TRACE("NET_WM Ping\n");
549 xev
.window
= DefaultRootWindow(xev
.display
);
550 XSendEvent(xev
.display
, xev
.window
, False
, SubstructureRedirectMask
| SubstructureNotifyMask
, (XEvent
*)&xev
);
552 /* this line is semi-stolen from gtk2 */
553 TRACE("NET_WM Pong\n");
558 static const char * const focus_details
[] =
564 "NotifyNonlinearVirtual",
570 /**********************************************************************
573 static void EVENT_FocusIn( HWND hwnd
, XEvent
*xev
)
575 XFocusChangeEvent
*event
= &xev
->xfocus
;
580 TRACE( "win %p xwin %lx detail=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
] );
582 if (event
->detail
== NotifyPointer
) return;
584 if ((xic
= X11DRV_get_ic( hwnd
)))
590 if (use_take_focus
) return; /* ignore FocusIn if we are using take focus */
592 if (!can_activate_window(hwnd
))
594 HWND hwnd
= GetFocus();
595 if (hwnd
) hwnd
= GetAncestor( hwnd
, GA_ROOT
);
596 if (!hwnd
) hwnd
= GetActiveWindow();
597 if (!hwnd
) hwnd
= x11drv_thread_data()->last_focus
;
598 if (hwnd
&& can_activate_window(hwnd
)) set_focus( hwnd
, CurrentTime
);
600 else SetForegroundWindow( hwnd
);
604 /**********************************************************************
607 * Note: only top-level windows get FocusOut events.
609 static void EVENT_FocusOut( HWND hwnd
, XEvent
*xev
)
611 XFocusChangeEvent
*event
= &xev
->xfocus
;
619 TRACE( "win %p xwin %lx detail=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
] );
621 if (event
->detail
== NotifyPointer
) return;
622 if (ximInComposeMode
) return;
624 x11drv_thread_data()->last_focus
= hwnd
;
625 if ((xic
= X11DRV_get_ic( hwnd
)))
628 XUnsetICFocus( xic
);
631 if (hwnd
!= GetForegroundWindow()) return;
632 SendMessageW( hwnd
, WM_CANCELMODE
, 0, 0 );
634 /* don't reset the foreground window, if the window which is
635 getting the focus is a Wine window */
638 XGetInputFocus( thread_display(), &focus_win
, &revert
);
641 if (XFindContext( thread_display(), focus_win
, winContext
, (char **)&hwnd_tmp
) != 0)
648 /* Abey : 6-Oct-99. Check again if the focus out window is the
649 Foreground window, because in most cases the messages sent
650 above must have already changed the foreground window, in which
651 case we don't have to change the foreground window to 0 */
652 if (hwnd
== GetForegroundWindow())
654 TRACE( "lost focus, setting fg to desktop\n" );
655 SetForegroundWindow( GetDesktopWindow() );
661 /***********************************************************************
662 * get_window_wm_state
664 int get_window_wm_state( Display
*display
, struct x11drv_win_data
*data
)
672 int format
, ret
= -1;
673 unsigned long count
, remaining
;
676 if (!XGetWindowProperty( display
, data
->whole_window
, x11drv_atom(WM_STATE
), 0,
677 sizeof(*state
)/sizeof(CARD32
), False
, x11drv_atom(WM_STATE
),
678 &type
, &format
, &count
, &remaining
, (unsigned char **)&state
))
680 if (type
== x11drv_atom(WM_STATE
) && get_property_size( format
, count
) >= sizeof(*state
))
689 /***********************************************************************
690 * handle_wm_state_notify
692 * Handle a PropertyNotify for WM_STATE.
694 static void handle_wm_state_notify( struct x11drv_win_data
*data
, XPropertyEvent
*event
,
700 data
->wm_state
= WithdrawnState
;
701 TRACE( "%p/%lx: WM_STATE deleted\n", data
->hwnd
, data
->whole_window
);
703 case PropertyNewValue
:
705 int new_state
= get_window_wm_state( event
->display
, data
);
706 if (new_state
!= -1 && new_state
!= data
->wm_state
)
708 TRACE( "%p/%lx: new WM_STATE %d\n", data
->hwnd
, data
->whole_window
, new_state
);
709 data
->wm_state
= new_state
;
715 if (!update_window
|| !data
->managed
|| !data
->mapped
) return;
717 if (data
->iconic
&& data
->wm_state
== NormalState
) /* restore window */
720 unsigned int width
, height
, border
, depth
;
727 XGetGeometry( event
->display
, data
->whole_window
, &root
, &x
, &y
, &width
, &height
,
729 XTranslateCoordinates( event
->display
, data
->whole_window
, root
, 0, 0, &x
, &y
, &top
);
733 rect
.right
= x
+ width
;
734 rect
.bottom
= y
+ height
;
735 OffsetRect( &rect
, virtual_screen_rect
.left
, virtual_screen_rect
.top
);
736 X11DRV_X_to_window_rect( data
, &rect
);
738 wp
.length
= sizeof(wp
);
739 GetWindowPlacement( data
->hwnd
, &wp
);
741 wp
.showCmd
= SW_RESTORE
;
742 wp
.rcNormalPosition
= rect
;
744 TRACE( "restoring win %p/%lx\n", data
->hwnd
, data
->whole_window
);
745 data
->iconic
= FALSE
;
746 SetWindowPlacement( data
->hwnd
, &wp
);
748 else if (!data
->iconic
&& data
->wm_state
== IconicState
)
750 TRACE( "minimizing win %p/%lx\n", data
->hwnd
, data
->whole_window
);
752 ShowWindow( data
->hwnd
, SW_MINIMIZE
);
757 /***********************************************************************
758 * EVENT_PropertyNotify
760 static void EVENT_PropertyNotify( HWND hwnd
, XEvent
*xev
)
762 XPropertyEvent
*event
= &xev
->xproperty
;
763 struct x11drv_win_data
*data
;
766 if (!(data
= X11DRV_get_win_data( hwnd
))) return;
768 if (event
->atom
== x11drv_atom(WM_STATE
)) handle_wm_state_notify( data
, event
, TRUE
);
772 /* event filter to wait for a WM_STATE change notification on a window */
773 static Bool
is_wm_state_notify( Display
*display
, XEvent
*event
, XPointer arg
)
775 if (event
->xany
.window
!= (Window
)arg
) return 0;
776 return (event
->type
== DestroyNotify
||
777 (event
->type
== PropertyNotify
&& event
->xproperty
.atom
== x11drv_atom(WM_STATE
)));
780 /***********************************************************************
781 * wait_for_withdrawn_state
783 void wait_for_withdrawn_state( Display
*display
, struct x11drv_win_data
*data
, BOOL set
)
785 DWORD end
= GetTickCount() + 2000;
787 if (!data
->managed
) return;
789 TRACE( "waiting for window %p/%lx to become %swithdrawn\n",
790 data
->hwnd
, data
->whole_window
, set
? "" : "not " );
792 while (data
->whole_window
&& ((data
->wm_state
== WithdrawnState
) == !set
))
798 while (XCheckIfEvent( display
, &event
, is_wm_state_notify
, (char *)data
->whole_window
))
801 if (XFilterEvent( &event
, None
)) continue; /* filtered, ignore it */
802 if (event
.type
== DestroyNotify
) call_event_handler( display
, &event
);
806 handle_wm_state_notify( data
, &event
.xproperty
, FALSE
);
815 int timeout
= end
- GetTickCount();
817 pfd
.fd
= ConnectionNumber(display
);
819 if (timeout
<= 0 || poll( &pfd
, 1, timeout
) != 1)
821 FIXME( "window %p/%lx wait timed out\n", data
->hwnd
, data
->whole_window
);
826 TRACE( "window %p/%lx state now %d\n", data
->hwnd
, data
->whole_window
, data
->wm_state
);
830 static HWND
find_drop_window( HWND hQueryWnd
, LPPOINT lpPt
)
834 if (!IsWindowEnabled(hQueryWnd
)) return 0;
836 GetWindowRect(hQueryWnd
, &tempRect
);
838 if(!PtInRect(&tempRect
, *lpPt
)) return 0;
840 if (!IsIconic( hQueryWnd
))
843 ScreenToClient( hQueryWnd
, &pt
);
844 GetClientRect( hQueryWnd
, &tempRect
);
846 if (PtInRect( &tempRect
, pt
))
848 HWND ret
= ChildWindowFromPointEx( hQueryWnd
, pt
, CWP_SKIPINVISIBLE
|CWP_SKIPDISABLED
);
849 if (ret
&& ret
!= hQueryWnd
)
851 ret
= find_drop_window( ret
, lpPt
);
857 if(!(GetWindowLongA( hQueryWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return 0;
859 ScreenToClient(hQueryWnd
, lpPt
);
864 /**********************************************************************
865 * EVENT_DropFromOffix
867 * don't know if it still works (last Changelog is from 96/11/04)
869 static void EVENT_DropFromOffiX( HWND hWnd
, XClientMessageEvent
*event
)
871 struct x11drv_win_data
*data
;
872 unsigned long data_length
;
873 unsigned long aux_long
;
874 unsigned char* p_data
= NULL
;
878 Window win
, w_aux_root
, w_aux_child
;
881 win
= X11DRV_get_whole_window(hWnd
);
883 XQueryPointer( event
->display
, win
, &w_aux_root
, &w_aux_child
,
884 &x
, &y
, &dummy
, &dummy
, (unsigned int*)&aux_long
);
885 x
+= virtual_screen_rect
.left
;
886 y
+= virtual_screen_rect
.top
;
889 if (!(data
= X11DRV_get_win_data( hWnd
))) return;
891 /* find out drop point and drop window */
892 if( x
< 0 || y
< 0 ||
893 x
> (data
->whole_rect
.right
- data
->whole_rect
.left
) ||
894 y
> (data
->whole_rect
.bottom
- data
->whole_rect
.top
) )
896 bAccept
= GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
;
903 HWND hwndDrop
= find_drop_window( hWnd
, &pt
);
917 if (!bAccept
) return;
920 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
921 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
922 AnyPropertyType
, &atom_aux
, &dummy
,
923 &data_length
, &aux_long
, &p_data
);
926 if( !aux_long
&& p_data
) /* don't bother if > 64K */
928 char *p
= (char *)p_data
;
932 while( *p
) /* calculate buffer size */
934 INT len
= GetShortPathNameA( p
, NULL
, 0 );
935 if (len
) aux_long
+= len
+ 1;
938 if( aux_long
&& aux_long
< 65535 )
943 aux_long
+= sizeof(DROPFILES
) + 1;
944 hDrop
= GlobalAlloc( GMEM_SHARE
, aux_long
);
945 lpDrop
= (DROPFILES
*)GlobalLock( hDrop
);
949 lpDrop
->pFiles
= sizeof(DROPFILES
);
953 lpDrop
->fWide
= FALSE
;
954 p_drop
= (char *)(lpDrop
+ 1);
958 if (GetShortPathNameA( p
, p_drop
, aux_long
- (p_drop
- (char *)lpDrop
) ))
959 p_drop
+= strlen( p_drop
) + 1;
963 PostMessageA( hWnd
, WM_DROPFILES
, (WPARAM
)hDrop
, 0L );
968 if( p_data
) XFree(p_data
);
972 /**********************************************************************
975 * drop items are separated by \n
976 * each item is prefixed by its mime type
978 * event->data.l[3], event->data.l[4] contains drop x,y position
980 static void EVENT_DropURLs( HWND hWnd
, XClientMessageEvent
*event
)
982 struct x11drv_win_data
*win_data
;
983 unsigned long data_length
;
984 unsigned long aux_long
, drop_len
= 0;
985 unsigned char *p_data
= NULL
; /* property data */
998 if (!(GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return;
1001 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
1002 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
1003 AnyPropertyType
, &u
.atom_aux
, &u
.i
,
1004 &data_length
, &aux_long
, &p_data
);
1005 wine_tsx11_unlock();
1007 WARN("property too large, truncated!\n");
1008 TRACE("urls=%s\n", p_data
);
1010 if( !aux_long
&& p_data
) { /* don't bother if > 64K */
1011 /* calculate length */
1013 next
= strchr(p
, '\n');
1016 if (strncmp(p
,"file:",5) == 0 ) {
1017 INT len
= GetShortPathNameA( p
+5, NULL
, 0 );
1018 if (len
) drop_len
+= len
+ 1;
1023 next
= strchr(p
, '\n');
1029 if( drop_len
&& drop_len
< 65535 ) {
1031 XQueryPointer( event
->display
, root_window
, &u
.w_aux
, &u
.w_aux
,
1032 &x
, &y
, &u
.i
, &u
.i
, &u
.u
);
1033 x
+= virtual_screen_rect
.left
;
1034 y
+= virtual_screen_rect
.top
;
1035 wine_tsx11_unlock();
1037 drop_len
+= sizeof(DROPFILES
) + 1;
1038 hDrop
= GlobalAlloc( GMEM_SHARE
, drop_len
);
1039 lpDrop
= (DROPFILES
*) GlobalLock( hDrop
);
1041 if( lpDrop
&& (win_data
= X11DRV_get_win_data( hWnd
)))
1043 lpDrop
->pFiles
= sizeof(DROPFILES
);
1047 ( x
< (win_data
->client_rect
.left
- win_data
->whole_rect
.left
) ||
1048 y
< (win_data
->client_rect
.top
- win_data
->whole_rect
.top
) ||
1049 x
> (win_data
->client_rect
.right
- win_data
->whole_rect
.left
) ||
1050 y
> (win_data
->client_rect
.bottom
- win_data
->whole_rect
.top
) );
1051 lpDrop
->fWide
= FALSE
;
1052 p_drop
= (char*)(lpDrop
+ 1);
1055 /* create message content */
1058 next
= strchr(p
, '\n');
1061 if (strncmp(p
,"file:",5) == 0 ) {
1062 INT len
= GetShortPathNameA( p
+5, p_drop
, 65535 );
1064 TRACE("drop file %s as %s\n", p
+5, p_drop
);
1067 WARN("can't convert file %s to dos name\n", p
+5);
1070 WARN("unknown mime type %s\n", p
);
1075 next
= strchr(p
, '\n');
1082 GlobalUnlock(hDrop
);
1083 PostMessageA( hWnd
, WM_DROPFILES
, (WPARAM
)hDrop
, 0L );
1087 if( p_data
) XFree(p_data
);
1088 wine_tsx11_unlock();
1092 /**********************************************************************
1093 * handle_dnd_protocol
1095 static void handle_dnd_protocol( HWND hwnd
, XClientMessageEvent
*event
)
1098 int root_x
, root_y
, child_x
, child_y
;
1101 /* query window (drag&drop event contains only drag window) */
1103 XQueryPointer( event
->display
, root_window
, &root
, &child
,
1104 &root_x
, &root_y
, &child_x
, &child_y
, &u
);
1105 if (XFindContext( event
->display
, child
, winContext
, (char **)&hwnd
) != 0) hwnd
= 0;
1106 wine_tsx11_unlock();
1108 if (event
->data
.l
[0] == DndFile
|| event
->data
.l
[0] == DndFiles
)
1109 EVENT_DropFromOffiX(hwnd
, event
);
1110 else if (event
->data
.l
[0] == DndURL
)
1111 EVENT_DropURLs(hwnd
, event
);
1115 struct client_message_handler
1117 int atom
; /* protocol atom */
1118 void (*handler
)(HWND
, XClientMessageEvent
*); /* corresponding handler function */
1121 static const struct client_message_handler client_messages
[] =
1123 { XATOM_WM_PROTOCOLS
, handle_wm_protocols
},
1124 { XATOM_DndProtocol
, handle_dnd_protocol
},
1125 { XATOM_XdndEnter
, X11DRV_XDND_EnterEvent
},
1126 { XATOM_XdndPosition
, X11DRV_XDND_PositionEvent
},
1127 { XATOM_XdndDrop
, X11DRV_XDND_DropEvent
},
1128 { XATOM_XdndLeave
, X11DRV_XDND_LeaveEvent
}
1132 /**********************************************************************
1133 * EVENT_ClientMessage
1135 static void EVENT_ClientMessage( HWND hwnd
, XEvent
*xev
)
1137 XClientMessageEvent
*event
= &xev
->xclient
;
1142 if (event
->format
!= 32)
1144 WARN( "Don't know how to handle format %d\n", event
->format
);
1148 for (i
= 0; i
< sizeof(client_messages
)/sizeof(client_messages
[0]); i
++)
1150 if (event
->message_type
== X11DRV_Atoms
[client_messages
[i
].atom
- FIRST_XATOM
])
1152 client_messages
[i
].handler( hwnd
, event
);
1156 TRACE( "no handler found for %ld\n", event
->message_type
);
1160 /**********************************************************************
1161 * X11DRV_WindowMessage (X11DRV.@)
1163 LRESULT
X11DRV_WindowMessage( HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
1167 case WM_X11DRV_ACQUIRE_SELECTION
:
1168 return X11DRV_AcquireClipboard( hwnd
);
1169 case WM_X11DRV_DELETE_WINDOW
:
1170 return SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_CLOSE
, 0 );
1171 case WM_X11DRV_SET_WIN_FORMAT
:
1172 return X11DRV_set_win_format( hwnd
, (XID
)wp
);
1173 case WM_X11DRV_RESIZE_DESKTOP
:
1174 X11DRV_resize_desktop( LOWORD(lp
), HIWORD(lp
) );
1177 FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg
, hwnd
, wp
, lp
);
1183 /***********************************************************************
1184 * X11DRV_SendInput (X11DRV.@)
1186 UINT
X11DRV_SendInput( UINT count
, LPINPUT inputs
, int size
)
1190 for (i
= 0; i
< count
; i
++, inputs
++)
1192 switch(inputs
->type
)
1195 X11DRV_send_mouse_input( 0, inputs
->u
.mi
.dwFlags
, inputs
->u
.mi
.dx
, inputs
->u
.mi
.dy
,
1196 inputs
->u
.mi
.mouseData
, inputs
->u
.mi
.time
,
1197 inputs
->u
.mi
.dwExtraInfo
, LLMHF_INJECTED
);
1199 case INPUT_KEYBOARD
:
1200 X11DRV_send_keyboard_input( inputs
->u
.ki
.wVk
, inputs
->u
.ki
.wScan
, inputs
->u
.ki
.dwFlags
,
1201 inputs
->u
.ki
.time
, inputs
->u
.ki
.dwExtraInfo
, LLKHF_INJECTED
);
1203 case INPUT_HARDWARE
:
1204 FIXME( "INPUT_HARDWARE not supported\n" );