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 */
107 { UnmapNotify
, X11DRV_UnmapNotify
},
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 /***********************************************************************
247 static int process_events( Display
*display
, Bool (*filter
)(), ULONG_PTR arg
)
252 x11drv_event_handler handler
;
255 while (XCheckIfEvent( display
, &event
, filter
, (char *)arg
))
258 if (XFilterEvent( &event
, None
)) continue; /* filtered, ignore it */
260 if (!(handler
= find_handler( event
.type
)))
262 TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event
.type
), event
.xany
.window
);
263 continue; /* no handler, ignore it */
266 if (XFindContext( display
, event
.xany
.window
, winContext
, (char **)&hwnd
) != 0)
267 hwnd
= 0; /* not for a registered window */
268 if (!hwnd
&& event
.xany
.window
== root_window
) hwnd
= GetDesktopWindow();
271 TRACE( "%s for hwnd/window %p/%lx\n",
272 dbgstr_event( event
.type
), hwnd
, event
.xany
.window
);
273 handler( hwnd
, &event
);
276 XFlush( gdi_display
);
278 if (count
) TRACE( "processed %d events\n", count
);
283 /***********************************************************************
284 * MsgWaitForMultipleObjectsEx (X11DRV.@)
286 DWORD
X11DRV_MsgWaitForMultipleObjectsEx( DWORD count
, const HANDLE
*handles
,
287 DWORD timeout
, DWORD mask
, DWORD flags
)
290 struct x11drv_thread_data
*data
= TlsGetValue( thread_data_tls_index
);
294 if (!count
&& !timeout
) return WAIT_TIMEOUT
;
295 return WaitForMultipleObjectsEx( count
, handles
, flags
& MWMO_WAITALL
,
296 timeout
, flags
& MWMO_ALERTABLE
);
299 if (data
->process_event_count
) mask
= 0; /* don't process nested events */
301 data
->process_event_count
++;
303 if (process_events( data
->display
, filter_event
, mask
)) ret
= count
- 1;
304 else if (count
|| timeout
)
306 ret
= WaitForMultipleObjectsEx( count
, handles
, flags
& MWMO_WAITALL
,
307 timeout
, flags
& MWMO_ALERTABLE
);
308 if (ret
== count
- 1) process_events( data
->display
, filter_event
, mask
);
310 else ret
= WAIT_TIMEOUT
;
312 data
->process_event_count
--;
316 /***********************************************************************
317 * EVENT_x11_time_to_win32_time
319 * Make our timer and the X timer line up as best we can
320 * Pass 0 to retrieve the current adjustment value (times -1)
322 DWORD
EVENT_x11_time_to_win32_time(Time time
)
324 static DWORD adjust
= 0;
325 DWORD now
= GetTickCount();
328 if (! adjust
&& time
!= 0)
335 /* If we got an event in the 'future', then our clock is clearly wrong.
336 If we got it more than 10000 ms in the future, then it's most likely
337 that the clock has wrapped. */
340 if (ret
> now
&& ((ret
- now
) < 10000) && time
!= 0)
351 /*******************************************************************
352 * can_activate_window
354 * Check if we can activate the specified window.
356 static inline BOOL
can_activate_window( HWND hwnd
)
358 LONG style
= GetWindowLongW( hwnd
, GWL_STYLE
);
359 if (!(style
& WS_VISIBLE
)) return FALSE
;
360 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return FALSE
;
361 if (hwnd
== GetDesktopWindow()) return FALSE
;
362 return !(style
& WS_DISABLED
);
366 /**********************************************************************
369 static void set_focus( HWND hwnd
, Time time
)
374 TRACE( "setting foreground window to %p\n", hwnd
);
375 SetForegroundWindow( hwnd
);
378 if (focus
) focus
= GetAncestor( focus
, GA_ROOT
);
379 win
= X11DRV_get_whole_window(focus
);
383 TRACE( "setting focus to %p (%lx) time=%ld\n", focus
, win
, time
);
385 XSetInputFocus( thread_display(), win
, RevertToParent
, time
);
391 /**********************************************************************
392 * handle_wm_protocols
394 static void handle_wm_protocols( HWND hwnd
, XClientMessageEvent
*event
)
396 Atom protocol
= (Atom
)event
->data
.l
[0];
398 if (!protocol
) return;
400 if (protocol
== x11drv_atom(WM_DELETE_WINDOW
))
402 /* Ignore the delete window request if the window has been disabled
403 * and we are in managed mode. This is to disallow applications from
404 * being closed by the window manager while in a modal state.
406 if (IsWindowEnabled(hwnd
))
410 if (GetClassLongW(hwnd
, GCL_STYLE
) & CS_NOCLOSE
) return;
411 hSysMenu
= GetSystemMenu(hwnd
, FALSE
);
414 UINT state
= GetMenuState(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
);
415 if (state
== 0xFFFFFFFF || (state
& (MF_DISABLED
| MF_GRAYED
)))
418 if (GetActiveWindow() != hwnd
)
420 LRESULT ma
= SendMessageW( hwnd
, WM_MOUSEACTIVATE
,
421 (WPARAM
)GetAncestor( hwnd
, GA_ROOT
),
422 MAKELONG(HTCLOSE
,WM_LBUTTONDOWN
) );
425 case MA_NOACTIVATEANDEAT
:
426 case MA_ACTIVATEANDEAT
:
432 SetActiveWindow(hwnd
);
435 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma
);
439 PostMessageW( hwnd
, WM_X11DRV_DELETE_WINDOW
, 0, 0 );
442 else if (protocol
== x11drv_atom(WM_TAKE_FOCUS
))
444 Time event_time
= (Time
)event
->data
.l
[1];
445 HWND last_focus
= x11drv_thread_data()->last_focus
;
447 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
448 hwnd
, IsWindowEnabled(hwnd
), IsWindowVisible(hwnd
), GetWindowLongW(hwnd
, GWL_STYLE
),
449 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus
);
451 if (can_activate_window(hwnd
))
453 /* simulate a mouse click on the caption to find out
454 * whether the window wants to be activated */
455 LRESULT ma
= SendMessageW( hwnd
, WM_MOUSEACTIVATE
,
456 (WPARAM
)GetAncestor( hwnd
, GA_ROOT
),
457 MAKELONG(HTCAPTION
,WM_LBUTTONDOWN
) );
458 if (ma
!= MA_NOACTIVATEANDEAT
&& ma
!= MA_NOACTIVATE
)
460 set_focus( hwnd
, event_time
);
464 /* try to find some other window to give the focus to */
466 if (hwnd
) hwnd
= GetAncestor( hwnd
, GA_ROOT
);
467 if (!hwnd
) hwnd
= GetActiveWindow();
468 if (!hwnd
) hwnd
= last_focus
;
469 if (hwnd
&& can_activate_window(hwnd
)) set_focus( hwnd
, event_time
);
471 else if (protocol
== x11drv_atom(_NET_WM_PING
))
473 XClientMessageEvent xev
;
476 TRACE("NET_WM Ping\n");
478 xev
.window
= DefaultRootWindow(xev
.display
);
479 XSendEvent(xev
.display
, xev
.window
, False
, SubstructureRedirectMask
| SubstructureNotifyMask
, (XEvent
*)&xev
);
481 /* this line is semi-stolen from gtk2 */
482 TRACE("NET_WM Pong\n");
487 static const char * const focus_details
[] =
493 "NotifyNonlinearVirtual",
499 /**********************************************************************
502 static void EVENT_FocusIn( HWND hwnd
, XEvent
*xev
)
504 XFocusChangeEvent
*event
= &xev
->xfocus
;
509 TRACE( "win %p xwin %lx detail=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
] );
511 if (event
->detail
== NotifyPointer
) return;
513 if ((xic
= X11DRV_get_ic( hwnd
)))
519 if (use_take_focus
) return; /* ignore FocusIn if we are using take focus */
521 if (!can_activate_window(hwnd
))
523 HWND hwnd
= GetFocus();
524 if (hwnd
) hwnd
= GetAncestor( hwnd
, GA_ROOT
);
525 if (!hwnd
) hwnd
= GetActiveWindow();
526 if (!hwnd
) hwnd
= x11drv_thread_data()->last_focus
;
527 if (hwnd
&& can_activate_window(hwnd
)) set_focus( hwnd
, CurrentTime
);
529 else SetForegroundWindow( hwnd
);
533 /**********************************************************************
536 * Note: only top-level windows get FocusOut events.
538 static void EVENT_FocusOut( HWND hwnd
, XEvent
*xev
)
540 XFocusChangeEvent
*event
= &xev
->xfocus
;
548 TRACE( "win %p xwin %lx detail=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
] );
550 if (event
->detail
== NotifyPointer
) return;
551 if (ximInComposeMode
) return;
553 x11drv_thread_data()->last_focus
= hwnd
;
554 if ((xic
= X11DRV_get_ic( hwnd
)))
557 XUnsetICFocus( xic
);
560 if (hwnd
!= GetForegroundWindow()) return;
561 SendMessageW( hwnd
, WM_CANCELMODE
, 0, 0 );
563 /* don't reset the foreground window, if the window which is
564 getting the focus is a Wine window */
567 XGetInputFocus( thread_display(), &focus_win
, &revert
);
570 if (XFindContext( thread_display(), focus_win
, winContext
, (char **)&hwnd_tmp
) != 0)
577 /* Abey : 6-Oct-99. Check again if the focus out window is the
578 Foreground window, because in most cases the messages sent
579 above must have already changed the foreground window, in which
580 case we don't have to change the foreground window to 0 */
581 if (hwnd
== GetForegroundWindow())
583 TRACE( "lost focus, setting fg to desktop\n" );
584 SetForegroundWindow( GetDesktopWindow() );
590 /***********************************************************************
591 * get_window_wm_state
593 int get_window_wm_state( Display
*display
, struct x11drv_win_data
*data
)
601 int format
, ret
= -1;
602 unsigned long count
, remaining
;
605 if (!XGetWindowProperty( display
, data
->whole_window
, x11drv_atom(WM_STATE
), 0,
606 sizeof(*state
)/sizeof(CARD32
), False
, x11drv_atom(WM_STATE
),
607 &type
, &format
, &count
, &remaining
, (unsigned char **)&state
))
609 if (type
== x11drv_atom(WM_STATE
) && format
&& count
>= sizeof(*state
)/(format
/8))
618 /***********************************************************************
619 * EVENT_PropertyNotify
621 static void EVENT_PropertyNotify( HWND hwnd
, XEvent
*xev
)
623 XPropertyEvent
*event
= &xev
->xproperty
;
624 struct x11drv_win_data
*data
;
627 if (!(data
= X11DRV_get_win_data( hwnd
))) return;
632 if (event
->atom
== x11drv_atom(WM_STATE
))
634 data
->wm_state
= WithdrawnState
;
635 TRACE( "%p/%lx: WM_STATE deleted\n", data
->hwnd
, data
->whole_window
);
639 case PropertyNewValue
:
640 if (event
->atom
== x11drv_atom(WM_STATE
))
642 int new_state
= get_window_wm_state( event
->display
, data
);
643 if (new_state
!= -1 && new_state
!= data
->wm_state
)
645 TRACE( "%p/%lx: new WM_STATE %d\n", data
->hwnd
, data
->whole_window
, new_state
);
646 data
->wm_state
= new_state
;
654 /* event filter to wait for a WM_STATE change notification on a window */
655 static Bool
is_wm_state_notify( Display
*display
, XEvent
*event
, XPointer arg
)
657 return (event
->type
== PropertyNotify
&&
658 event
->xproperty
.window
== (Window
)arg
&&
659 event
->xproperty
.atom
== x11drv_atom(WM_STATE
));
662 /***********************************************************************
663 * wait_for_withdrawn_state
665 void wait_for_withdrawn_state( Display
*display
, struct x11drv_win_data
*data
)
667 DWORD end
= GetTickCount() + 2000;
669 if (!data
->whole_window
|| !data
->managed
) return;
671 while (data
->wm_state
!= WithdrawnState
&&
672 !process_events( display
, is_wm_state_notify
, data
->whole_window
))
675 int timeout
= end
- GetTickCount();
677 TRACE( "waiting for window %p/%lx to become withdrawn\n", data
->hwnd
, data
->whole_window
);
678 pfd
.fd
= ConnectionNumber(display
);
680 if (timeout
<= 0 || poll( &pfd
, 1, timeout
) != 1)
682 FIXME( "window %p/%lx wait timed out\n", data
->hwnd
, data
->whole_window
);
689 static HWND
find_drop_window( HWND hQueryWnd
, LPPOINT lpPt
)
693 if (!IsWindowEnabled(hQueryWnd
)) return 0;
695 GetWindowRect(hQueryWnd
, &tempRect
);
697 if(!PtInRect(&tempRect
, *lpPt
)) return 0;
699 if (!IsIconic( hQueryWnd
))
702 ScreenToClient( hQueryWnd
, &pt
);
703 GetClientRect( hQueryWnd
, &tempRect
);
705 if (PtInRect( &tempRect
, pt
))
707 HWND ret
= ChildWindowFromPointEx( hQueryWnd
, pt
, CWP_SKIPINVISIBLE
|CWP_SKIPDISABLED
);
708 if (ret
&& ret
!= hQueryWnd
)
710 ret
= find_drop_window( ret
, lpPt
);
716 if(!(GetWindowLongA( hQueryWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return 0;
718 ScreenToClient(hQueryWnd
, lpPt
);
723 /**********************************************************************
724 * EVENT_DropFromOffix
726 * don't know if it still works (last Changelog is from 96/11/04)
728 static void EVENT_DropFromOffiX( HWND hWnd
, XClientMessageEvent
*event
)
730 struct x11drv_win_data
*data
;
731 unsigned long data_length
;
732 unsigned long aux_long
;
733 unsigned char* p_data
= NULL
;
737 Window win
, w_aux_root
, w_aux_child
;
740 win
= X11DRV_get_whole_window(hWnd
);
742 XQueryPointer( event
->display
, win
, &w_aux_root
, &w_aux_child
,
743 &x
, &y
, &dummy
, &dummy
, (unsigned int*)&aux_long
);
744 x
+= virtual_screen_rect
.left
;
745 y
+= virtual_screen_rect
.top
;
748 if (!(data
= X11DRV_get_win_data( hWnd
))) return;
750 /* find out drop point and drop window */
751 if( x
< 0 || y
< 0 ||
752 x
> (data
->whole_rect
.right
- data
->whole_rect
.left
) ||
753 y
> (data
->whole_rect
.bottom
- data
->whole_rect
.top
) )
755 bAccept
= GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
;
762 HWND hwndDrop
= find_drop_window( hWnd
, &pt
);
776 if (!bAccept
) return;
779 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
780 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
781 AnyPropertyType
, &atom_aux
, &dummy
,
782 &data_length
, &aux_long
, &p_data
);
785 if( !aux_long
&& p_data
) /* don't bother if > 64K */
787 char *p
= (char *)p_data
;
791 while( *p
) /* calculate buffer size */
793 INT len
= GetShortPathNameA( p
, NULL
, 0 );
794 if (len
) aux_long
+= len
+ 1;
797 if( aux_long
&& aux_long
< 65535 )
802 aux_long
+= sizeof(DROPFILES
) + 1;
803 hDrop
= GlobalAlloc( GMEM_SHARE
, aux_long
);
804 lpDrop
= (DROPFILES
*)GlobalLock( hDrop
);
808 lpDrop
->pFiles
= sizeof(DROPFILES
);
812 lpDrop
->fWide
= FALSE
;
813 p_drop
= (char *)(lpDrop
+ 1);
817 if (GetShortPathNameA( p
, p_drop
, aux_long
- (p_drop
- (char *)lpDrop
) ))
818 p_drop
+= strlen( p_drop
) + 1;
822 PostMessageA( hWnd
, WM_DROPFILES
, (WPARAM
)hDrop
, 0L );
827 if( p_data
) XFree(p_data
);
831 /**********************************************************************
834 * drop items are separated by \n
835 * each item is prefixed by its mime type
837 * event->data.l[3], event->data.l[4] contains drop x,y position
839 static void EVENT_DropURLs( HWND hWnd
, XClientMessageEvent
*event
)
841 struct x11drv_win_data
*win_data
;
842 unsigned long data_length
;
843 unsigned long aux_long
, drop_len
= 0;
844 unsigned char *p_data
= NULL
; /* property data */
857 if (!(GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return;
860 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
861 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
862 AnyPropertyType
, &u
.atom_aux
, &u
.i
,
863 &data_length
, &aux_long
, &p_data
);
866 WARN("property too large, truncated!\n");
867 TRACE("urls=%s\n", p_data
);
869 if( !aux_long
&& p_data
) { /* don't bother if > 64K */
870 /* calculate length */
872 next
= strchr(p
, '\n');
875 if (strncmp(p
,"file:",5) == 0 ) {
876 INT len
= GetShortPathNameA( p
+5, NULL
, 0 );
877 if (len
) drop_len
+= len
+ 1;
882 next
= strchr(p
, '\n');
888 if( drop_len
&& drop_len
< 65535 ) {
890 XQueryPointer( event
->display
, root_window
, &u
.w_aux
, &u
.w_aux
,
891 &x
, &y
, &u
.i
, &u
.i
, &u
.u
);
892 x
+= virtual_screen_rect
.left
;
893 y
+= virtual_screen_rect
.top
;
896 drop_len
+= sizeof(DROPFILES
) + 1;
897 hDrop
= GlobalAlloc( GMEM_SHARE
, drop_len
);
898 lpDrop
= (DROPFILES
*) GlobalLock( hDrop
);
900 if( lpDrop
&& (win_data
= X11DRV_get_win_data( hWnd
)))
902 lpDrop
->pFiles
= sizeof(DROPFILES
);
906 ( x
< (win_data
->client_rect
.left
- win_data
->whole_rect
.left
) ||
907 y
< (win_data
->client_rect
.top
- win_data
->whole_rect
.top
) ||
908 x
> (win_data
->client_rect
.right
- win_data
->whole_rect
.left
) ||
909 y
> (win_data
->client_rect
.bottom
- win_data
->whole_rect
.top
) );
910 lpDrop
->fWide
= FALSE
;
911 p_drop
= (char*)(lpDrop
+ 1);
914 /* create message content */
917 next
= strchr(p
, '\n');
920 if (strncmp(p
,"file:",5) == 0 ) {
921 INT len
= GetShortPathNameA( p
+5, p_drop
, 65535 );
923 TRACE("drop file %s as %s\n", p
+5, p_drop
);
926 WARN("can't convert file %s to dos name\n", p
+5);
929 WARN("unknown mime type %s\n", p
);
934 next
= strchr(p
, '\n');
942 PostMessageA( hWnd
, WM_DROPFILES
, (WPARAM
)hDrop
, 0L );
946 if( p_data
) XFree(p_data
);
951 /**********************************************************************
952 * handle_dnd_protocol
954 static void handle_dnd_protocol( HWND hwnd
, XClientMessageEvent
*event
)
957 int root_x
, root_y
, child_x
, child_y
;
960 /* query window (drag&drop event contains only drag window) */
962 XQueryPointer( event
->display
, root_window
, &root
, &child
,
963 &root_x
, &root_y
, &child_x
, &child_y
, &u
);
964 if (XFindContext( event
->display
, child
, winContext
, (char **)&hwnd
) != 0) hwnd
= 0;
967 if (event
->data
.l
[0] == DndFile
|| event
->data
.l
[0] == DndFiles
)
968 EVENT_DropFromOffiX(hwnd
, event
);
969 else if (event
->data
.l
[0] == DndURL
)
970 EVENT_DropURLs(hwnd
, event
);
974 struct client_message_handler
976 int atom
; /* protocol atom */
977 void (*handler
)(HWND
, XClientMessageEvent
*); /* corresponding handler function */
980 static const struct client_message_handler client_messages
[] =
982 { XATOM_WM_PROTOCOLS
, handle_wm_protocols
},
983 { XATOM_DndProtocol
, handle_dnd_protocol
},
984 { XATOM_XdndEnter
, X11DRV_XDND_EnterEvent
},
985 { XATOM_XdndPosition
, X11DRV_XDND_PositionEvent
},
986 { XATOM_XdndDrop
, X11DRV_XDND_DropEvent
},
987 { XATOM_XdndLeave
, X11DRV_XDND_LeaveEvent
}
991 /**********************************************************************
992 * EVENT_ClientMessage
994 static void EVENT_ClientMessage( HWND hwnd
, XEvent
*xev
)
996 XClientMessageEvent
*event
= &xev
->xclient
;
1001 if (event
->format
!= 32)
1003 WARN( "Don't know how to handle format %d\n", event
->format
);
1007 for (i
= 0; i
< sizeof(client_messages
)/sizeof(client_messages
[0]); i
++)
1009 if (event
->message_type
== X11DRV_Atoms
[client_messages
[i
].atom
- FIRST_XATOM
])
1011 client_messages
[i
].handler( hwnd
, event
);
1015 TRACE( "no handler found for %ld\n", event
->message_type
);
1019 /**********************************************************************
1020 * X11DRV_WindowMessage (X11DRV.@)
1022 LRESULT
X11DRV_WindowMessage( HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
1026 case WM_X11DRV_ACQUIRE_SELECTION
:
1027 return X11DRV_AcquireClipboard( hwnd
);
1028 case WM_X11DRV_DELETE_WINDOW
:
1029 return SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_CLOSE
, 0 );
1030 case WM_X11DRV_SET_WIN_FORMAT
:
1031 return X11DRV_set_win_format( hwnd
, (XID
)wp
);
1032 case WM_X11DRV_RESIZE_DESKTOP
:
1033 X11DRV_resize_desktop( LOWORD(lp
), HIWORD(lp
) );
1036 FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg
, hwnd
, wp
, lp
);
1042 /***********************************************************************
1043 * X11DRV_SendInput (X11DRV.@)
1045 UINT
X11DRV_SendInput( UINT count
, LPINPUT inputs
, int size
)
1049 for (i
= 0; i
< count
; i
++, inputs
++)
1051 switch(inputs
->type
)
1054 X11DRV_send_mouse_input( 0, inputs
->u
.mi
.dwFlags
, inputs
->u
.mi
.dx
, inputs
->u
.mi
.dy
,
1055 inputs
->u
.mi
.mouseData
, inputs
->u
.mi
.time
,
1056 inputs
->u
.mi
.dwExtraInfo
, LLMHF_INJECTED
);
1058 case INPUT_KEYBOARD
:
1059 X11DRV_send_keyboard_input( inputs
->u
.ki
.wVk
, inputs
->u
.ki
.wScan
, inputs
->u
.ki
.dwFlags
,
1060 inputs
->u
.ki
.time
, inputs
->u
.ki
.dwExtraInfo
, LLKHF_INJECTED
);
1062 case INPUT_HARDWARE
:
1063 FIXME( "INPUT_HARDWARE not supported\n" );