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
50 /* avoid conflict with field names in included win32 headers */
52 #include "shlobj.h" /* DROPFILES */
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 EVENT_FocusIn( HWND hwnd
, XEvent
*event
);
77 static void EVENT_FocusOut( HWND hwnd
, XEvent
*event
);
78 static void EVENT_PropertyNotify( HWND hwnd
, XEvent
*event
);
79 static void EVENT_ClientMessage( HWND hwnd
, XEvent
*event
);
83 int type
; /* event type */
84 x11drv_event_handler handler
; /* corresponding handler function */
87 #define MAX_EVENT_HANDLERS 64
89 static struct event_handler handlers
[MAX_EVENT_HANDLERS
] =
91 /* list must be sorted by event type */
92 { KeyPress
, X11DRV_KeyEvent
},
93 { KeyRelease
, X11DRV_KeyEvent
},
94 { ButtonPress
, X11DRV_ButtonPress
},
95 { ButtonRelease
, X11DRV_ButtonRelease
},
96 { MotionNotify
, X11DRV_MotionNotify
},
97 { EnterNotify
, X11DRV_EnterNotify
},
99 { FocusIn
, EVENT_FocusIn
},
100 { FocusOut
, EVENT_FocusOut
},
101 { KeymapNotify
, X11DRV_KeymapNotify
},
102 { Expose
, X11DRV_Expose
},
105 /* VisibilityNotify */
108 { UnmapNotify
, X11DRV_UnmapNotify
},
109 { MapNotify
, X11DRV_MapNotify
},
112 { ConfigureNotify
, X11DRV_ConfigureNotify
},
113 /* ConfigureRequest */
116 /* CirculateNotify */
117 /* CirculateRequest */
118 { PropertyNotify
, EVENT_PropertyNotify
},
119 { SelectionClear
, X11DRV_SelectionClear
},
120 { SelectionRequest
, X11DRV_SelectionRequest
},
121 /* SelectionNotify */
123 { ClientMessage
, EVENT_ClientMessage
},
124 { MappingNotify
, X11DRV_MappingNotify
},
127 static int nb_event_handlers
= 18; /* change this if you add handlers above */
130 /* return the name of an X event */
131 static const char *dbgstr_event( int type
)
133 static const char * const event_names
[] =
135 "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
136 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
137 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
138 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
139 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
140 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
141 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
142 "ClientMessage", "MappingNotify"
145 if (type
>= KeyPress
&& type
<= MappingNotify
) return event_names
[type
- KeyPress
];
146 return wine_dbg_sprintf( "Extension event %d", type
);
150 /***********************************************************************
153 * Find the handler for a given event type. Caller must hold the x11 lock.
155 static inline x11drv_event_handler
find_handler( int type
)
157 int min
= 0, max
= nb_event_handlers
- 1;
161 int pos
= (min
+ max
) / 2;
162 if (handlers
[pos
].type
== type
) return handlers
[pos
].handler
;
163 if (handlers
[pos
].type
> type
) max
= pos
- 1;
170 /***********************************************************************
171 * X11DRV_register_event_handler
173 * Register a handler for a given event type.
174 * If already registered, overwrite the previous handler.
176 void X11DRV_register_event_handler( int type
, x11drv_event_handler handler
)
182 max
= nb_event_handlers
- 1;
185 int pos
= (min
+ max
) / 2;
186 if (handlers
[pos
].type
== type
)
188 handlers
[pos
].handler
= handler
;
191 if (handlers
[pos
].type
> type
) max
= pos
- 1;
194 /* insert it between max and min */
195 memmove( &handlers
[min
+1], &handlers
[min
], (nb_event_handlers
- min
) * sizeof(handlers
[0]) );
196 handlers
[min
].type
= type
;
197 handlers
[min
].handler
= handler
;
199 assert( nb_event_handlers
<= MAX_EVENT_HANDLERS
);
202 TRACE("registered handler %p for event %d count %d\n", handler
, type
, nb_event_handlers
);
206 /***********************************************************************
209 static Bool
filter_event( Display
*display
, XEvent
*event
, char *arg
)
211 ULONG_PTR mask
= (ULONG_PTR
)arg
;
213 if ((mask
& QS_ALLINPUT
) == QS_ALLINPUT
) return 1;
221 return (mask
& QS_KEY
) != 0;
224 return (mask
& QS_MOUSEBUTTON
) != 0;
228 return (mask
& QS_MOUSEMOVE
) != 0;
230 return (mask
& QS_PAINT
) != 0;
235 case ConfigureNotify
:
238 return (mask
& QS_POSTMESSAGE
) != 0;
240 return (mask
& QS_SENDMESSAGE
) != 0;
245 /***********************************************************************
248 static int process_events( Display
*display
, Bool (*filter
)(), ULONG_PTR arg
)
253 x11drv_event_handler handler
;
256 while (XCheckIfEvent( display
, &event
, filter
, (char *)arg
))
259 if (XFilterEvent( &event
, None
)) continue; /* filtered, ignore it */
261 if (!(handler
= find_handler( event
.type
)))
263 TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event
.type
), event
.xany
.window
);
264 continue; /* no handler, ignore it */
267 if (XFindContext( display
, event
.xany
.window
, winContext
, (char **)&hwnd
) != 0)
268 hwnd
= 0; /* not for a registered window */
269 if (!hwnd
&& event
.xany
.window
== root_window
) hwnd
= GetDesktopWindow();
272 TRACE( "%s for hwnd/window %p/%lx\n",
273 dbgstr_event( event
.type
), hwnd
, event
.xany
.window
);
274 handler( hwnd
, &event
);
277 XFlush( gdi_display
);
279 if (count
) TRACE( "processed %d events\n", count
);
284 /***********************************************************************
285 * MsgWaitForMultipleObjectsEx (X11DRV.@)
287 DWORD
X11DRV_MsgWaitForMultipleObjectsEx( DWORD count
, const HANDLE
*handles
,
288 DWORD timeout
, DWORD mask
, DWORD flags
)
291 struct x11drv_thread_data
*data
= TlsGetValue( thread_data_tls_index
);
295 if (!count
&& !timeout
) return WAIT_TIMEOUT
;
296 return WaitForMultipleObjectsEx( count
, handles
, flags
& MWMO_WAITALL
,
297 timeout
, flags
& MWMO_ALERTABLE
);
300 if (data
->process_event_count
) mask
= 0; /* don't process nested events */
302 data
->process_event_count
++;
304 if (process_events( data
->display
, filter_event
, mask
)) ret
= count
- 1;
305 else if (count
|| timeout
)
307 ret
= WaitForMultipleObjectsEx( count
, handles
, flags
& MWMO_WAITALL
,
308 timeout
, flags
& MWMO_ALERTABLE
);
309 if (ret
== count
- 1) process_events( data
->display
, filter_event
, mask
);
311 else ret
= WAIT_TIMEOUT
;
313 data
->process_event_count
--;
317 /***********************************************************************
318 * EVENT_x11_time_to_win32_time
320 * Make our timer and the X timer line up as best we can
321 * Pass 0 to retrieve the current adjustment value (times -1)
323 DWORD
EVENT_x11_time_to_win32_time(Time time
)
325 static DWORD adjust
= 0;
326 DWORD now
= GetTickCount();
329 if (! adjust
&& time
!= 0)
336 /* If we got an event in the 'future', then our clock is clearly wrong.
337 If we got it more than 10000 ms in the future, then it's most likely
338 that the clock has wrapped. */
341 if (ret
> now
&& ((ret
- now
) < 10000) && time
!= 0)
352 /*******************************************************************
353 * can_activate_window
355 * Check if we can activate the specified window.
357 static inline BOOL
can_activate_window( HWND hwnd
)
359 LONG style
= GetWindowLongW( hwnd
, GWL_STYLE
);
360 if (!(style
& WS_VISIBLE
)) return FALSE
;
361 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return FALSE
;
362 if (hwnd
== GetDesktopWindow()) return FALSE
;
363 return !(style
& WS_DISABLED
);
367 /**********************************************************************
370 static void set_focus( HWND hwnd
, Time time
)
375 TRACE( "setting foreground window to %p\n", hwnd
);
376 SetForegroundWindow( hwnd
);
379 if (focus
) focus
= GetAncestor( focus
, GA_ROOT
);
380 win
= X11DRV_get_whole_window(focus
);
384 TRACE( "setting focus to %p (%lx) time=%ld\n", focus
, win
, time
);
386 XSetInputFocus( thread_display(), win
, RevertToParent
, time
);
392 /**********************************************************************
393 * handle_wm_protocols
395 static void handle_wm_protocols( HWND hwnd
, XClientMessageEvent
*event
)
397 Atom protocol
= (Atom
)event
->data
.l
[0];
399 if (!protocol
) return;
401 if (protocol
== x11drv_atom(WM_DELETE_WINDOW
))
403 /* Ignore the delete window request if the window has been disabled
404 * and we are in managed mode. This is to disallow applications from
405 * being closed by the window manager while in a modal state.
407 if (IsWindowEnabled(hwnd
))
411 if (GetClassLongW(hwnd
, GCL_STYLE
) & CS_NOCLOSE
) return;
412 hSysMenu
= GetSystemMenu(hwnd
, FALSE
);
415 UINT state
= GetMenuState(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
);
416 if (state
== 0xFFFFFFFF || (state
& (MF_DISABLED
| MF_GRAYED
)))
419 if (GetActiveWindow() != hwnd
)
421 LRESULT ma
= SendMessageW( hwnd
, WM_MOUSEACTIVATE
,
422 (WPARAM
)GetAncestor( hwnd
, GA_ROOT
),
423 MAKELONG(HTCLOSE
,WM_LBUTTONDOWN
) );
426 case MA_NOACTIVATEANDEAT
:
427 case MA_ACTIVATEANDEAT
:
433 SetActiveWindow(hwnd
);
436 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma
);
440 PostMessageW( hwnd
, WM_X11DRV_DELETE_WINDOW
, 0, 0 );
443 else if (protocol
== x11drv_atom(WM_TAKE_FOCUS
))
445 Time event_time
= (Time
)event
->data
.l
[1];
446 HWND last_focus
= x11drv_thread_data()->last_focus
;
448 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
449 hwnd
, IsWindowEnabled(hwnd
), IsWindowVisible(hwnd
), GetWindowLongW(hwnd
, GWL_STYLE
),
450 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus
);
452 if (can_activate_window(hwnd
))
454 /* simulate a mouse click on the caption to find out
455 * whether the window wants to be activated */
456 LRESULT ma
= SendMessageW( hwnd
, WM_MOUSEACTIVATE
,
457 (WPARAM
)GetAncestor( hwnd
, GA_ROOT
),
458 MAKELONG(HTCAPTION
,WM_LBUTTONDOWN
) );
459 if (ma
!= MA_NOACTIVATEANDEAT
&& ma
!= MA_NOACTIVATE
)
461 set_focus( hwnd
, event_time
);
465 /* try to find some other window to give the focus to */
467 if (hwnd
) hwnd
= GetAncestor( hwnd
, GA_ROOT
);
468 if (!hwnd
) hwnd
= GetActiveWindow();
469 if (!hwnd
) hwnd
= last_focus
;
470 if (hwnd
&& can_activate_window(hwnd
)) set_focus( hwnd
, event_time
);
472 else if (protocol
== x11drv_atom(_NET_WM_PING
))
474 XClientMessageEvent xev
;
477 TRACE("NET_WM Ping\n");
479 xev
.window
= DefaultRootWindow(xev
.display
);
480 XSendEvent(xev
.display
, xev
.window
, False
, SubstructureRedirectMask
| SubstructureNotifyMask
, (XEvent
*)&xev
);
482 /* this line is semi-stolen from gtk2 */
483 TRACE("NET_WM Pong\n");
488 static const char * const focus_details
[] =
494 "NotifyNonlinearVirtual",
500 /**********************************************************************
503 static void EVENT_FocusIn( HWND hwnd
, XEvent
*xev
)
505 XFocusChangeEvent
*event
= &xev
->xfocus
;
510 TRACE( "win %p xwin %lx detail=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
] );
512 if (event
->detail
== NotifyPointer
) return;
514 if ((xic
= X11DRV_get_ic( hwnd
)))
520 if (use_take_focus
) return; /* ignore FocusIn if we are using take focus */
522 if (!can_activate_window(hwnd
))
524 HWND hwnd
= GetFocus();
525 if (hwnd
) hwnd
= GetAncestor( hwnd
, GA_ROOT
);
526 if (!hwnd
) hwnd
= GetActiveWindow();
527 if (!hwnd
) hwnd
= x11drv_thread_data()->last_focus
;
528 if (hwnd
&& can_activate_window(hwnd
)) set_focus( hwnd
, CurrentTime
);
530 else SetForegroundWindow( hwnd
);
534 /**********************************************************************
537 * Note: only top-level windows get FocusOut events.
539 static void EVENT_FocusOut( HWND hwnd
, XEvent
*xev
)
541 XFocusChangeEvent
*event
= &xev
->xfocus
;
549 TRACE( "win %p xwin %lx detail=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
] );
551 if (event
->detail
== NotifyPointer
) return;
552 if (ximInComposeMode
) return;
554 x11drv_thread_data()->last_focus
= hwnd
;
555 if ((xic
= X11DRV_get_ic( hwnd
)))
558 XUnsetICFocus( xic
);
561 if (hwnd
!= GetForegroundWindow()) return;
562 SendMessageW( hwnd
, WM_CANCELMODE
, 0, 0 );
564 /* don't reset the foreground window, if the window which is
565 getting the focus is a Wine window */
568 XGetInputFocus( thread_display(), &focus_win
, &revert
);
571 if (XFindContext( thread_display(), focus_win
, winContext
, (char **)&hwnd_tmp
) != 0)
578 /* Abey : 6-Oct-99. Check again if the focus out window is the
579 Foreground window, because in most cases the messages sent
580 above must have already changed the foreground window, in which
581 case we don't have to change the foreground window to 0 */
582 if (hwnd
== GetForegroundWindow())
584 TRACE( "lost focus, setting fg to desktop\n" );
585 SetForegroundWindow( GetDesktopWindow() );
591 /***********************************************************************
592 * get_window_wm_state
594 int get_window_wm_state( Display
*display
, struct x11drv_win_data
*data
)
602 int format
, ret
= -1;
603 unsigned long count
, remaining
;
606 if (!XGetWindowProperty( display
, data
->whole_window
, x11drv_atom(WM_STATE
), 0,
607 sizeof(*state
)/sizeof(CARD32
), False
, x11drv_atom(WM_STATE
),
608 &type
, &format
, &count
, &remaining
, (unsigned char **)&state
))
610 if (type
== x11drv_atom(WM_STATE
) && format
&& count
>= sizeof(*state
)/(format
/8))
619 /***********************************************************************
620 * EVENT_PropertyNotify
622 static void EVENT_PropertyNotify( HWND hwnd
, XEvent
*xev
)
624 XPropertyEvent
*event
= &xev
->xproperty
;
625 struct x11drv_win_data
*data
;
628 if (!(data
= X11DRV_get_win_data( hwnd
))) return;
633 if (event
->atom
== x11drv_atom(WM_STATE
))
635 data
->wm_state
= WithdrawnState
;
636 TRACE( "%p/%lx: WM_STATE deleted\n", data
->hwnd
, data
->whole_window
);
640 case PropertyNewValue
:
641 if (event
->atom
== x11drv_atom(WM_STATE
))
643 int new_state
= get_window_wm_state( event
->display
, data
);
644 if (new_state
!= -1 && new_state
!= data
->wm_state
)
646 TRACE( "%p/%lx: new WM_STATE %d\n", data
->hwnd
, data
->whole_window
, new_state
);
647 data
->wm_state
= new_state
;
655 /* event filter to wait for a WM_STATE change notification on a window */
656 static Bool
is_wm_state_notify( Display
*display
, XEvent
*event
, XPointer arg
)
658 return (event
->type
== PropertyNotify
&&
659 event
->xproperty
.window
== (Window
)arg
&&
660 event
->xproperty
.atom
== x11drv_atom(WM_STATE
));
663 /***********************************************************************
664 * wait_for_withdrawn_state
666 void wait_for_withdrawn_state( Display
*display
, struct x11drv_win_data
*data
)
668 DWORD end
= GetTickCount() + 2000;
670 if (!data
->whole_window
|| !data
->managed
) return;
672 while (data
->wm_state
!= WithdrawnState
&&
673 !process_events( display
, is_wm_state_notify
, data
->whole_window
))
676 int timeout
= end
- GetTickCount();
678 TRACE( "waiting for window %p/%lx to become withdrawn\n", data
->hwnd
, data
->whole_window
);
679 pfd
.fd
= ConnectionNumber(display
);
681 if (timeout
<= 0 || poll( &pfd
, 1, timeout
) != 1)
683 FIXME( "window %p/%lx wait timed out\n", data
->hwnd
, data
->whole_window
);
690 static HWND
find_drop_window( HWND hQueryWnd
, LPPOINT lpPt
)
694 if (!IsWindowEnabled(hQueryWnd
)) return 0;
696 GetWindowRect(hQueryWnd
, &tempRect
);
698 if(!PtInRect(&tempRect
, *lpPt
)) return 0;
700 if (!IsIconic( hQueryWnd
))
703 ScreenToClient( hQueryWnd
, &pt
);
704 GetClientRect( hQueryWnd
, &tempRect
);
706 if (PtInRect( &tempRect
, pt
))
708 HWND ret
= ChildWindowFromPointEx( hQueryWnd
, pt
, CWP_SKIPINVISIBLE
|CWP_SKIPDISABLED
);
709 if (ret
&& ret
!= hQueryWnd
)
711 ret
= find_drop_window( ret
, lpPt
);
717 if(!(GetWindowLongA( hQueryWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return 0;
719 ScreenToClient(hQueryWnd
, lpPt
);
724 /**********************************************************************
725 * EVENT_DropFromOffix
727 * don't know if it still works (last Changelog is from 96/11/04)
729 static void EVENT_DropFromOffiX( HWND hWnd
, XClientMessageEvent
*event
)
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
;
741 win
= X11DRV_get_whole_window(hWnd
);
743 XQueryPointer( event
->display
, win
, &w_aux_root
, &w_aux_child
,
744 &x
, &y
, &dummy
, &dummy
, (unsigned int*)&aux_long
);
745 x
+= virtual_screen_rect
.left
;
746 y
+= virtual_screen_rect
.top
;
749 pWnd
= WIN_GetPtr(hWnd
);
751 /* find out drop point and drop window */
752 if( x
< 0 || y
< 0 ||
753 x
> (pWnd
->rectWindow
.right
- pWnd
->rectWindow
.left
) ||
754 y
> (pWnd
->rectWindow
.bottom
- pWnd
->rectWindow
.top
) )
756 bAccept
= pWnd
->dwExStyle
& WS_EX_ACCEPTFILES
;
763 HWND hwndDrop
= find_drop_window( hWnd
, &pt
);
776 WIN_ReleasePtr(pWnd
);
778 if (!bAccept
) return;
781 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
782 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
783 AnyPropertyType
, &atom_aux
, &dummy
,
784 &data_length
, &aux_long
, &p_data
);
787 if( !aux_long
&& p_data
) /* don't bother if > 64K */
789 char *p
= (char *)p_data
;
793 while( *p
) /* calculate buffer size */
795 INT len
= GetShortPathNameA( p
, NULL
, 0 );
796 if (len
) aux_long
+= len
+ 1;
799 if( aux_long
&& aux_long
< 65535 )
804 aux_long
+= sizeof(DROPFILES
) + 1;
805 hDrop
= GlobalAlloc( GMEM_SHARE
, aux_long
);
806 lpDrop
= (DROPFILES
*)GlobalLock( hDrop
);
810 WND
*pDropWnd
= WIN_GetPtr( hScope
);
811 lpDrop
->pFiles
= sizeof(DROPFILES
);
815 ( x
< (pDropWnd
->rectClient
.left
- pDropWnd
->rectWindow
.left
) ||
816 y
< (pDropWnd
->rectClient
.top
- pDropWnd
->rectWindow
.top
) ||
817 x
> (pDropWnd
->rectClient
.right
- pDropWnd
->rectWindow
.left
) ||
818 y
> (pDropWnd
->rectClient
.bottom
- pDropWnd
->rectWindow
.top
) );
819 lpDrop
->fWide
= FALSE
;
820 WIN_ReleasePtr(pDropWnd
);
821 p_drop
= (char *)(lpDrop
+ 1);
825 if (GetShortPathNameA( p
, p_drop
, aux_long
- (p_drop
- (char *)lpDrop
) ))
826 p_drop
+= strlen( p_drop
) + 1;
830 PostMessageA( hWnd
, WM_DROPFILES
, (WPARAM
)hDrop
, 0L );
835 if( p_data
) XFree(p_data
);
839 /**********************************************************************
842 * drop items are separated by \n
843 * each item is prefixed by its mime type
845 * event->data.l[3], event->data.l[4] contains drop x,y position
847 static void EVENT_DropURLs( HWND hWnd
, XClientMessageEvent
*event
)
849 unsigned long data_length
;
850 unsigned long aux_long
, drop_len
= 0;
851 unsigned char *p_data
= NULL
; /* property data */
864 if (!(GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return;
867 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
868 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
869 AnyPropertyType
, &u
.atom_aux
, &u
.i
,
870 &data_length
, &aux_long
, &p_data
);
873 WARN("property too large, truncated!\n");
874 TRACE("urls=%s\n", p_data
);
876 if( !aux_long
&& p_data
) { /* don't bother if > 64K */
877 /* calculate length */
879 next
= strchr(p
, '\n');
882 if (strncmp(p
,"file:",5) == 0 ) {
883 INT len
= GetShortPathNameA( p
+5, NULL
, 0 );
884 if (len
) drop_len
+= len
+ 1;
889 next
= strchr(p
, '\n');
895 if( drop_len
&& drop_len
< 65535 ) {
897 XQueryPointer( event
->display
, root_window
, &u
.w_aux
, &u
.w_aux
,
898 &x
, &y
, &u
.i
, &u
.i
, &u
.u
);
899 x
+= virtual_screen_rect
.left
;
900 y
+= virtual_screen_rect
.top
;
903 drop_len
+= sizeof(DROPFILES
) + 1;
904 hDrop
= GlobalAlloc( GMEM_SHARE
, drop_len
);
905 lpDrop
= (DROPFILES
*) GlobalLock( hDrop
);
908 WND
*pDropWnd
= WIN_GetPtr( hWnd
);
909 lpDrop
->pFiles
= sizeof(DROPFILES
);
913 ( x
< (pDropWnd
->rectClient
.left
- pDropWnd
->rectWindow
.left
) ||
914 y
< (pDropWnd
->rectClient
.top
- pDropWnd
->rectWindow
.top
) ||
915 x
> (pDropWnd
->rectClient
.right
- pDropWnd
->rectWindow
.left
) ||
916 y
> (pDropWnd
->rectClient
.bottom
- pDropWnd
->rectWindow
.top
) );
917 lpDrop
->fWide
= FALSE
;
918 p_drop
= (char*)(lpDrop
+ 1);
919 WIN_ReleasePtr(pDropWnd
);
922 /* create message content */
925 next
= strchr(p
, '\n');
928 if (strncmp(p
,"file:",5) == 0 ) {
929 INT len
= GetShortPathNameA( p
+5, p_drop
, 65535 );
931 TRACE("drop file %s as %s\n", p
+5, p_drop
);
934 WARN("can't convert file %s to dos name\n", p
+5);
937 WARN("unknown mime type %s\n", p
);
942 next
= strchr(p
, '\n');
950 PostMessageA( hWnd
, WM_DROPFILES
, (WPARAM
)hDrop
, 0L );
954 if( p_data
) XFree(p_data
);
959 /**********************************************************************
960 * handle_dnd_protocol
962 static void handle_dnd_protocol( HWND hwnd
, XClientMessageEvent
*event
)
965 int root_x
, root_y
, child_x
, child_y
;
968 /* query window (drag&drop event contains only drag window) */
970 XQueryPointer( event
->display
, root_window
, &root
, &child
,
971 &root_x
, &root_y
, &child_x
, &child_y
, &u
);
972 if (XFindContext( event
->display
, child
, winContext
, (char **)&hwnd
) != 0) hwnd
= 0;
975 if (event
->data
.l
[0] == DndFile
|| event
->data
.l
[0] == DndFiles
)
976 EVENT_DropFromOffiX(hwnd
, event
);
977 else if (event
->data
.l
[0] == DndURL
)
978 EVENT_DropURLs(hwnd
, event
);
982 struct client_message_handler
984 int atom
; /* protocol atom */
985 void (*handler
)(HWND
, XClientMessageEvent
*); /* corresponding handler function */
988 static const struct client_message_handler client_messages
[] =
990 { XATOM_WM_PROTOCOLS
, handle_wm_protocols
},
991 { XATOM_DndProtocol
, handle_dnd_protocol
},
992 { XATOM_XdndEnter
, X11DRV_XDND_EnterEvent
},
993 { XATOM_XdndPosition
, X11DRV_XDND_PositionEvent
},
994 { XATOM_XdndDrop
, X11DRV_XDND_DropEvent
},
995 { XATOM_XdndLeave
, X11DRV_XDND_LeaveEvent
}
999 /**********************************************************************
1000 * EVENT_ClientMessage
1002 static void EVENT_ClientMessage( HWND hwnd
, XEvent
*xev
)
1004 XClientMessageEvent
*event
= &xev
->xclient
;
1009 if (event
->format
!= 32)
1011 WARN( "Don't know how to handle format %d\n", event
->format
);
1015 for (i
= 0; i
< sizeof(client_messages
)/sizeof(client_messages
[0]); i
++)
1017 if (event
->message_type
== X11DRV_Atoms
[client_messages
[i
].atom
- FIRST_XATOM
])
1019 client_messages
[i
].handler( hwnd
, event
);
1023 TRACE( "no handler found for %ld\n", event
->message_type
);
1027 /**********************************************************************
1028 * X11DRV_WindowMessage (X11DRV.@)
1030 LRESULT
X11DRV_WindowMessage( HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
1034 case WM_X11DRV_ACQUIRE_SELECTION
:
1035 return X11DRV_AcquireClipboard( hwnd
);
1036 case WM_X11DRV_DELETE_WINDOW
:
1037 return SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_CLOSE
, 0 );
1038 case WM_X11DRV_SET_WIN_FORMAT
:
1039 return X11DRV_set_win_format( hwnd
, (XID
)wp
);
1040 case WM_X11DRV_RESIZE_DESKTOP
:
1041 X11DRV_resize_desktop( LOWORD(lp
), HIWORD(lp
) );
1044 FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg
, hwnd
, wp
, lp
);
1050 /***********************************************************************
1051 * X11DRV_SendInput (X11DRV.@)
1053 UINT
X11DRV_SendInput( UINT count
, LPINPUT inputs
, int size
)
1057 for (i
= 0; i
< count
; i
++, inputs
++)
1059 switch(inputs
->type
)
1062 X11DRV_send_mouse_input( 0, inputs
->u
.mi
.dwFlags
, inputs
->u
.mi
.dx
, inputs
->u
.mi
.dy
,
1063 inputs
->u
.mi
.mouseData
, inputs
->u
.mi
.time
,
1064 inputs
->u
.mi
.dwExtraInfo
, LLMHF_INJECTED
);
1066 case INPUT_KEYBOARD
:
1067 X11DRV_send_keyboard_input( inputs
->u
.ki
.wVk
, inputs
->u
.ki
.wScan
, inputs
->u
.ki
.dwFlags
,
1068 inputs
->u
.ki
.time
, inputs
->u
.ki
.dwExtraInfo
, LLKHF_INJECTED
);
1070 case INPUT_HARDWARE
:
1071 FIXME( "INPUT_HARDWARE not supported\n" );