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
) && format
&& count
>= sizeof(*state
)/(format
/8))
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 data
->lock_changes
++;
747 SetWindowPlacement( data
->hwnd
, &wp
);
748 data
->lock_changes
--;
750 else if (!data
->iconic
&& data
->wm_state
== IconicState
)
752 TRACE( "minimizing win %p/%lx\n", data
->hwnd
, data
->whole_window
);
754 data
->lock_changes
++;
755 ShowWindow( data
->hwnd
, SW_MINIMIZE
);
756 data
->lock_changes
--;
761 /***********************************************************************
762 * EVENT_PropertyNotify
764 static void EVENT_PropertyNotify( HWND hwnd
, XEvent
*xev
)
766 XPropertyEvent
*event
= &xev
->xproperty
;
767 struct x11drv_win_data
*data
;
770 if (!(data
= X11DRV_get_win_data( hwnd
))) return;
772 if (event
->atom
== x11drv_atom(WM_STATE
)) handle_wm_state_notify( data
, event
, TRUE
);
776 /* event filter to wait for a WM_STATE change notification on a window */
777 static Bool
is_wm_state_notify( Display
*display
, XEvent
*event
, XPointer arg
)
779 if (event
->xany
.window
!= (Window
)arg
) return 0;
780 return (event
->type
== DestroyNotify
||
781 (event
->type
== PropertyNotify
&& event
->xproperty
.atom
== x11drv_atom(WM_STATE
)));
784 /***********************************************************************
785 * wait_for_withdrawn_state
787 void wait_for_withdrawn_state( Display
*display
, struct x11drv_win_data
*data
, BOOL set
)
789 DWORD end
= GetTickCount() + 2000;
791 if (!data
->managed
) return;
793 TRACE( "waiting for window %p/%lx to become %swithdrawn\n",
794 data
->hwnd
, data
->whole_window
, set
? "" : "not " );
796 while (data
->whole_window
&& ((data
->wm_state
== WithdrawnState
) == !set
))
802 while (XCheckIfEvent( display
, &event
, is_wm_state_notify
, (char *)data
->whole_window
))
805 if (XFilterEvent( &event
, None
)) continue; /* filtered, ignore it */
806 if (event
.type
== DestroyNotify
) call_event_handler( display
, &event
);
810 handle_wm_state_notify( data
, &event
.xproperty
, FALSE
);
819 int timeout
= end
- GetTickCount();
821 pfd
.fd
= ConnectionNumber(display
);
823 if (timeout
<= 0 || poll( &pfd
, 1, timeout
) != 1)
825 FIXME( "window %p/%lx wait timed out\n", data
->hwnd
, data
->whole_window
);
830 TRACE( "window %p/%lx state now %d\n", data
->hwnd
, data
->whole_window
, data
->wm_state
);
834 static HWND
find_drop_window( HWND hQueryWnd
, LPPOINT lpPt
)
838 if (!IsWindowEnabled(hQueryWnd
)) return 0;
840 GetWindowRect(hQueryWnd
, &tempRect
);
842 if(!PtInRect(&tempRect
, *lpPt
)) return 0;
844 if (!IsIconic( hQueryWnd
))
847 ScreenToClient( hQueryWnd
, &pt
);
848 GetClientRect( hQueryWnd
, &tempRect
);
850 if (PtInRect( &tempRect
, pt
))
852 HWND ret
= ChildWindowFromPointEx( hQueryWnd
, pt
, CWP_SKIPINVISIBLE
|CWP_SKIPDISABLED
);
853 if (ret
&& ret
!= hQueryWnd
)
855 ret
= find_drop_window( ret
, lpPt
);
861 if(!(GetWindowLongA( hQueryWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return 0;
863 ScreenToClient(hQueryWnd
, lpPt
);
868 /**********************************************************************
869 * EVENT_DropFromOffix
871 * don't know if it still works (last Changelog is from 96/11/04)
873 static void EVENT_DropFromOffiX( HWND hWnd
, XClientMessageEvent
*event
)
875 struct x11drv_win_data
*data
;
876 unsigned long data_length
;
877 unsigned long aux_long
;
878 unsigned char* p_data
= NULL
;
882 Window win
, w_aux_root
, w_aux_child
;
885 win
= X11DRV_get_whole_window(hWnd
);
887 XQueryPointer( event
->display
, win
, &w_aux_root
, &w_aux_child
,
888 &x
, &y
, &dummy
, &dummy
, (unsigned int*)&aux_long
);
889 x
+= virtual_screen_rect
.left
;
890 y
+= virtual_screen_rect
.top
;
893 if (!(data
= X11DRV_get_win_data( hWnd
))) return;
895 /* find out drop point and drop window */
896 if( x
< 0 || y
< 0 ||
897 x
> (data
->whole_rect
.right
- data
->whole_rect
.left
) ||
898 y
> (data
->whole_rect
.bottom
- data
->whole_rect
.top
) )
900 bAccept
= GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
;
907 HWND hwndDrop
= find_drop_window( hWnd
, &pt
);
921 if (!bAccept
) return;
924 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
925 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
926 AnyPropertyType
, &atom_aux
, &dummy
,
927 &data_length
, &aux_long
, &p_data
);
930 if( !aux_long
&& p_data
) /* don't bother if > 64K */
932 char *p
= (char *)p_data
;
936 while( *p
) /* calculate buffer size */
938 INT len
= GetShortPathNameA( p
, NULL
, 0 );
939 if (len
) aux_long
+= len
+ 1;
942 if( aux_long
&& aux_long
< 65535 )
947 aux_long
+= sizeof(DROPFILES
) + 1;
948 hDrop
= GlobalAlloc( GMEM_SHARE
, aux_long
);
949 lpDrop
= (DROPFILES
*)GlobalLock( hDrop
);
953 lpDrop
->pFiles
= sizeof(DROPFILES
);
957 lpDrop
->fWide
= FALSE
;
958 p_drop
= (char *)(lpDrop
+ 1);
962 if (GetShortPathNameA( p
, p_drop
, aux_long
- (p_drop
- (char *)lpDrop
) ))
963 p_drop
+= strlen( p_drop
) + 1;
967 PostMessageA( hWnd
, WM_DROPFILES
, (WPARAM
)hDrop
, 0L );
972 if( p_data
) XFree(p_data
);
976 /**********************************************************************
979 * drop items are separated by \n
980 * each item is prefixed by its mime type
982 * event->data.l[3], event->data.l[4] contains drop x,y position
984 static void EVENT_DropURLs( HWND hWnd
, XClientMessageEvent
*event
)
986 struct x11drv_win_data
*win_data
;
987 unsigned long data_length
;
988 unsigned long aux_long
, drop_len
= 0;
989 unsigned char *p_data
= NULL
; /* property data */
1002 if (!(GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return;
1005 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
1006 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
1007 AnyPropertyType
, &u
.atom_aux
, &u
.i
,
1008 &data_length
, &aux_long
, &p_data
);
1009 wine_tsx11_unlock();
1011 WARN("property too large, truncated!\n");
1012 TRACE("urls=%s\n", p_data
);
1014 if( !aux_long
&& p_data
) { /* don't bother if > 64K */
1015 /* calculate length */
1017 next
= strchr(p
, '\n');
1020 if (strncmp(p
,"file:",5) == 0 ) {
1021 INT len
= GetShortPathNameA( p
+5, NULL
, 0 );
1022 if (len
) drop_len
+= len
+ 1;
1027 next
= strchr(p
, '\n');
1033 if( drop_len
&& drop_len
< 65535 ) {
1035 XQueryPointer( event
->display
, root_window
, &u
.w_aux
, &u
.w_aux
,
1036 &x
, &y
, &u
.i
, &u
.i
, &u
.u
);
1037 x
+= virtual_screen_rect
.left
;
1038 y
+= virtual_screen_rect
.top
;
1039 wine_tsx11_unlock();
1041 drop_len
+= sizeof(DROPFILES
) + 1;
1042 hDrop
= GlobalAlloc( GMEM_SHARE
, drop_len
);
1043 lpDrop
= (DROPFILES
*) GlobalLock( hDrop
);
1045 if( lpDrop
&& (win_data
= X11DRV_get_win_data( hWnd
)))
1047 lpDrop
->pFiles
= sizeof(DROPFILES
);
1051 ( x
< (win_data
->client_rect
.left
- win_data
->whole_rect
.left
) ||
1052 y
< (win_data
->client_rect
.top
- win_data
->whole_rect
.top
) ||
1053 x
> (win_data
->client_rect
.right
- win_data
->whole_rect
.left
) ||
1054 y
> (win_data
->client_rect
.bottom
- win_data
->whole_rect
.top
) );
1055 lpDrop
->fWide
= FALSE
;
1056 p_drop
= (char*)(lpDrop
+ 1);
1059 /* create message content */
1062 next
= strchr(p
, '\n');
1065 if (strncmp(p
,"file:",5) == 0 ) {
1066 INT len
= GetShortPathNameA( p
+5, p_drop
, 65535 );
1068 TRACE("drop file %s as %s\n", p
+5, p_drop
);
1071 WARN("can't convert file %s to dos name\n", p
+5);
1074 WARN("unknown mime type %s\n", p
);
1079 next
= strchr(p
, '\n');
1086 GlobalUnlock(hDrop
);
1087 PostMessageA( hWnd
, WM_DROPFILES
, (WPARAM
)hDrop
, 0L );
1091 if( p_data
) XFree(p_data
);
1092 wine_tsx11_unlock();
1096 /**********************************************************************
1097 * handle_dnd_protocol
1099 static void handle_dnd_protocol( HWND hwnd
, XClientMessageEvent
*event
)
1102 int root_x
, root_y
, child_x
, child_y
;
1105 /* query window (drag&drop event contains only drag window) */
1107 XQueryPointer( event
->display
, root_window
, &root
, &child
,
1108 &root_x
, &root_y
, &child_x
, &child_y
, &u
);
1109 if (XFindContext( event
->display
, child
, winContext
, (char **)&hwnd
) != 0) hwnd
= 0;
1110 wine_tsx11_unlock();
1112 if (event
->data
.l
[0] == DndFile
|| event
->data
.l
[0] == DndFiles
)
1113 EVENT_DropFromOffiX(hwnd
, event
);
1114 else if (event
->data
.l
[0] == DndURL
)
1115 EVENT_DropURLs(hwnd
, event
);
1119 struct client_message_handler
1121 int atom
; /* protocol atom */
1122 void (*handler
)(HWND
, XClientMessageEvent
*); /* corresponding handler function */
1125 static const struct client_message_handler client_messages
[] =
1127 { XATOM_WM_PROTOCOLS
, handle_wm_protocols
},
1128 { XATOM_DndProtocol
, handle_dnd_protocol
},
1129 { XATOM_XdndEnter
, X11DRV_XDND_EnterEvent
},
1130 { XATOM_XdndPosition
, X11DRV_XDND_PositionEvent
},
1131 { XATOM_XdndDrop
, X11DRV_XDND_DropEvent
},
1132 { XATOM_XdndLeave
, X11DRV_XDND_LeaveEvent
}
1136 /**********************************************************************
1137 * EVENT_ClientMessage
1139 static void EVENT_ClientMessage( HWND hwnd
, XEvent
*xev
)
1141 XClientMessageEvent
*event
= &xev
->xclient
;
1146 if (event
->format
!= 32)
1148 WARN( "Don't know how to handle format %d\n", event
->format
);
1152 for (i
= 0; i
< sizeof(client_messages
)/sizeof(client_messages
[0]); i
++)
1154 if (event
->message_type
== X11DRV_Atoms
[client_messages
[i
].atom
- FIRST_XATOM
])
1156 client_messages
[i
].handler( hwnd
, event
);
1160 TRACE( "no handler found for %ld\n", event
->message_type
);
1164 /**********************************************************************
1165 * X11DRV_WindowMessage (X11DRV.@)
1167 LRESULT
X11DRV_WindowMessage( HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
1171 case WM_X11DRV_ACQUIRE_SELECTION
:
1172 return X11DRV_AcquireClipboard( hwnd
);
1173 case WM_X11DRV_DELETE_WINDOW
:
1174 return SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_CLOSE
, 0 );
1175 case WM_X11DRV_SET_WIN_FORMAT
:
1176 return X11DRV_set_win_format( hwnd
, (XID
)wp
);
1177 case WM_X11DRV_RESIZE_DESKTOP
:
1178 X11DRV_resize_desktop( LOWORD(lp
), HIWORD(lp
) );
1181 FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg
, hwnd
, wp
, lp
);
1187 /***********************************************************************
1188 * X11DRV_SendInput (X11DRV.@)
1190 UINT
X11DRV_SendInput( UINT count
, LPINPUT inputs
, int size
)
1194 for (i
= 0; i
< count
; i
++, inputs
++)
1196 switch(inputs
->type
)
1199 X11DRV_send_mouse_input( 0, inputs
->u
.mi
.dwFlags
, inputs
->u
.mi
.dx
, inputs
->u
.mi
.dy
,
1200 inputs
->u
.mi
.mouseData
, inputs
->u
.mi
.time
,
1201 inputs
->u
.mi
.dwExtraInfo
, LLMHF_INJECTED
);
1203 case INPUT_KEYBOARD
:
1204 X11DRV_send_keyboard_input( inputs
->u
.ki
.wVk
, inputs
->u
.ki
.wScan
, inputs
->u
.ki
.dwFlags
,
1205 inputs
->u
.ki
.time
, inputs
->u
.ki
.dwExtraInfo
, LLKHF_INJECTED
);
1207 case INPUT_HARDWARE
:
1208 FIXME( "INPUT_HARDWARE not supported\n" );