4 * Copyright 1993 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #ifdef HAVE_SYS_POLL_H
30 #include <X11/Xatom.h>
31 #include <X11/keysym.h>
33 #include <X11/Xresource.h>
34 #include <X11/Xutil.h>
40 #define NONAMELESSUNION
41 #define NONAMELESSSTRUCT
49 /* avoid conflict with field names in included win32 headers */
51 #include "shlobj.h" /* DROPFILES */
54 #include "wine/server.h"
55 #include "wine/debug.h"
57 WINE_DEFAULT_DEBUG_CHANNEL(event
);
59 extern BOOL ximInComposeMode
;
61 #define DndNotDnd -1 /* OffiX drag&drop */
73 #define DndURL 128 /* KDE drag&drop */
76 static void X11DRV_FocusIn( HWND hwnd
, XEvent
*event
);
77 static void X11DRV_FocusOut( HWND hwnd
, XEvent
*event
);
78 static void X11DRV_Expose( HWND hwnd
, XEvent
*event
);
79 static void X11DRV_MapNotify( HWND hwnd
, XEvent
*event
);
80 static void X11DRV_ConfigureNotify( HWND hwnd
, XEvent
*event
);
81 static void X11DRV_PropertyNotify( HWND hwnd
, XEvent
*event
);
82 static void X11DRV_ClientMessage( HWND hwnd
, XEvent
*event
);
86 int type
; /* event type */
87 x11drv_event_handler handler
; /* corresponding handler function */
90 #define MAX_EVENT_HANDLERS 64
92 static struct event_handler handlers
[MAX_EVENT_HANDLERS
] =
94 /* list must be sorted by event type */
95 { KeyPress
, X11DRV_KeyEvent
},
96 { KeyRelease
, X11DRV_KeyEvent
},
97 { ButtonPress
, X11DRV_ButtonPress
},
98 { ButtonRelease
, X11DRV_ButtonRelease
},
99 { MotionNotify
, X11DRV_MotionNotify
},
100 { EnterNotify
, X11DRV_EnterNotify
},
102 { FocusIn
, X11DRV_FocusIn
},
103 { FocusOut
, X11DRV_FocusOut
},
104 { KeymapNotify
, X11DRV_KeymapNotify
},
105 { Expose
, X11DRV_Expose
},
108 /* VisibilityNotify */
110 { DestroyNotify
, X11DRV_DestroyNotify
},
112 { MapNotify
, X11DRV_MapNotify
},
115 { ConfigureNotify
, X11DRV_ConfigureNotify
},
116 /* ConfigureRequest */
119 /* CirculateNotify */
120 /* CirculateRequest */
121 { PropertyNotify
, X11DRV_PropertyNotify
},
122 { SelectionClear
, X11DRV_SelectionClear
},
123 { SelectionRequest
, X11DRV_SelectionRequest
},
124 /* SelectionNotify */
126 { ClientMessage
, X11DRV_ClientMessage
},
127 { MappingNotify
, X11DRV_MappingNotify
},
130 static int nb_event_handlers
= 18; /* change this if you add handlers above */
133 /* return the name of an X event */
134 static const char *dbgstr_event( int type
)
136 static const char * const event_names
[] =
138 "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
139 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
140 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
141 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
142 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
143 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
144 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
145 "ClientMessage", "MappingNotify"
148 if (type
>= KeyPress
&& type
<= MappingNotify
) return event_names
[type
- KeyPress
];
149 return wine_dbg_sprintf( "Extension event %d", type
);
153 /***********************************************************************
156 * Find the handler for a given event type. Caller must hold the x11 lock.
158 static inline x11drv_event_handler
find_handler( int type
)
160 int min
= 0, max
= nb_event_handlers
- 1;
164 int pos
= (min
+ max
) / 2;
165 if (handlers
[pos
].type
== type
) return handlers
[pos
].handler
;
166 if (handlers
[pos
].type
> type
) max
= pos
- 1;
173 /***********************************************************************
174 * X11DRV_register_event_handler
176 * Register a handler for a given event type.
177 * If already registered, overwrite the previous handler.
179 void X11DRV_register_event_handler( int type
, x11drv_event_handler handler
)
185 max
= nb_event_handlers
- 1;
188 int pos
= (min
+ max
) / 2;
189 if (handlers
[pos
].type
== type
)
191 handlers
[pos
].handler
= handler
;
194 if (handlers
[pos
].type
> type
) max
= pos
- 1;
197 /* insert it between max and min */
198 memmove( &handlers
[min
+1], &handlers
[min
], (nb_event_handlers
- min
) * sizeof(handlers
[0]) );
199 handlers
[min
].type
= type
;
200 handlers
[min
].handler
= handler
;
202 assert( nb_event_handlers
<= MAX_EVENT_HANDLERS
);
205 TRACE("registered handler %p for event %d count %d\n", handler
, type
, nb_event_handlers
);
209 /***********************************************************************
212 static Bool
filter_event( Display
*display
, XEvent
*event
, char *arg
)
214 ULONG_PTR mask
= (ULONG_PTR
)arg
;
216 if ((mask
& QS_ALLINPUT
) == QS_ALLINPUT
) return 1;
224 return (mask
& QS_KEY
) != 0;
227 return (mask
& QS_MOUSEBUTTON
) != 0;
231 return (mask
& QS_MOUSEMOVE
) != 0;
233 return (mask
& QS_PAINT
) != 0;
238 case ConfigureNotify
:
241 return (mask
& QS_POSTMESSAGE
) != 0;
243 return (mask
& QS_SENDMESSAGE
) != 0;
248 enum event_merge_action
250 MERGE_DISCARD
, /* discard the old event */
251 MERGE_HANDLE
, /* handle the old event */
252 MERGE_KEEP
/* keep the old event for future merging */
255 /***********************************************************************
258 * Try to merge 2 consecutive events.
260 static enum event_merge_action
merge_events( XEvent
*prev
, XEvent
*next
)
264 case ConfigureNotify
:
267 case ConfigureNotify
:
268 if (prev
->xany
.window
== next
->xany
.window
)
270 TRACE( "discarding duplicate ConfigureNotify for window %lx\n", prev
->xany
.window
);
271 return MERGE_DISCARD
;
280 if (prev
->xany
.window
== next
->xany
.window
&& next
->type
== MotionNotify
)
282 TRACE( "discarding duplicate MotionNotify for window %lx\n", prev
->xany
.window
);
283 return MERGE_DISCARD
;
291 /***********************************************************************
294 static inline void call_event_handler( Display
*display
, XEvent
*event
)
297 x11drv_event_handler handler
;
299 struct x11drv_thread_data
*thread_data
;
301 if (!(handler
= find_handler( event
->type
)))
303 TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event
->type
), event
->xany
.window
);
304 return; /* no handler, ignore it */
307 if (XFindContext( display
, event
->xany
.window
, winContext
, (char **)&hwnd
) != 0)
308 hwnd
= 0; /* not for a registered window */
309 if (!hwnd
&& event
->xany
.window
== root_window
) hwnd
= GetDesktopWindow();
311 TRACE( "%s for hwnd/window %p/%lx\n",
312 dbgstr_event( event
->type
), hwnd
, event
->xany
.window
);
314 thread_data
= x11drv_thread_data();
315 prev
= thread_data
->current_event
;
316 thread_data
->current_event
= event
;
317 handler( hwnd
, event
);
318 thread_data
->current_event
= prev
;
323 /***********************************************************************
326 static int process_events( Display
*display
, Bool (*filter
)(), ULONG_PTR arg
)
328 XEvent event
, prev_event
;
330 enum event_merge_action action
= MERGE_DISCARD
;
334 while (XCheckIfEvent( display
, &event
, filter
, (char *)arg
))
337 if (XFilterEvent( &event
, None
)) continue; /* filtered, ignore it */
338 if (prev_event
.type
) action
= merge_events( &prev_event
, &event
);
341 case MERGE_DISCARD
: /* discard prev, keep new */
344 case MERGE_HANDLE
: /* handle prev, keep new */
345 call_event_handler( display
, &prev_event
);
348 case MERGE_KEEP
: /* handle new, keep prev for future merging */
349 call_event_handler( display
, &event
);
353 XFlush( gdi_display
);
354 if (prev_event
.type
) call_event_handler( display
, &prev_event
);
356 if (count
) TRACE( "processed %d events\n", count
);
361 /***********************************************************************
362 * MsgWaitForMultipleObjectsEx (X11DRV.@)
364 DWORD
X11DRV_MsgWaitForMultipleObjectsEx( DWORD count
, const HANDLE
*handles
,
365 DWORD timeout
, DWORD mask
, DWORD flags
)
368 struct x11drv_thread_data
*data
= TlsGetValue( thread_data_tls_index
);
372 if (!count
&& !timeout
) return WAIT_TIMEOUT
;
373 return WaitForMultipleObjectsEx( count
, handles
, flags
& MWMO_WAITALL
,
374 timeout
, flags
& MWMO_ALERTABLE
);
377 if (data
->current_event
) mask
= 0; /* don't process nested events */
379 if (process_events( data
->display
, filter_event
, mask
)) ret
= count
- 1;
380 else if (count
|| timeout
)
382 ret
= WaitForMultipleObjectsEx( count
, handles
, flags
& MWMO_WAITALL
,
383 timeout
, flags
& MWMO_ALERTABLE
);
384 if (ret
== count
- 1) process_events( data
->display
, filter_event
, mask
);
386 else ret
= WAIT_TIMEOUT
;
391 /***********************************************************************
392 * EVENT_x11_time_to_win32_time
394 * Make our timer and the X timer line up as best we can
395 * Pass 0 to retrieve the current adjustment value (times -1)
397 DWORD
EVENT_x11_time_to_win32_time(Time time
)
399 static DWORD adjust
= 0;
400 DWORD now
= GetTickCount();
403 if (! adjust
&& time
!= 0)
410 /* If we got an event in the 'future', then our clock is clearly wrong.
411 If we got it more than 10000 ms in the future, then it's most likely
412 that the clock has wrapped. */
415 if (ret
> now
&& ((ret
- now
) < 10000) && time
!= 0)
426 /*******************************************************************
427 * can_activate_window
429 * Check if we can activate the specified window.
431 static inline BOOL
can_activate_window( HWND hwnd
)
433 LONG style
= GetWindowLongW( hwnd
, GWL_STYLE
);
434 if (!(style
& WS_VISIBLE
)) return FALSE
;
435 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return FALSE
;
436 if (hwnd
== GetDesktopWindow()) return FALSE
;
437 return !(style
& WS_DISABLED
);
441 /**********************************************************************
444 static void set_focus( HWND hwnd
, Time time
)
449 TRACE( "setting foreground window to %p\n", hwnd
);
450 SetForegroundWindow( hwnd
);
453 if (focus
) focus
= GetAncestor( focus
, GA_ROOT
);
454 win
= X11DRV_get_whole_window(focus
);
458 TRACE( "setting focus to %p (%lx) time=%ld\n", focus
, win
, time
);
460 XSetInputFocus( thread_display(), win
, RevertToParent
, time
);
466 /**********************************************************************
467 * handle_wm_protocols
469 static void handle_wm_protocols( HWND hwnd
, XClientMessageEvent
*event
)
471 Atom protocol
= (Atom
)event
->data
.l
[0];
473 if (!protocol
) return;
475 if (protocol
== x11drv_atom(WM_DELETE_WINDOW
))
477 /* Ignore the delete window request if the window has been disabled
478 * and we are in managed mode. This is to disallow applications from
479 * being closed by the window manager while in a modal state.
481 if (IsWindowEnabled(hwnd
))
485 if (GetClassLongW(hwnd
, GCL_STYLE
) & CS_NOCLOSE
) return;
486 hSysMenu
= GetSystemMenu(hwnd
, FALSE
);
489 UINT state
= GetMenuState(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
);
490 if (state
== 0xFFFFFFFF || (state
& (MF_DISABLED
| MF_GRAYED
)))
493 if (GetActiveWindow() != hwnd
)
495 LRESULT ma
= SendMessageW( hwnd
, WM_MOUSEACTIVATE
,
496 (WPARAM
)GetAncestor( hwnd
, GA_ROOT
),
497 MAKELONG(HTCLOSE
,WM_LBUTTONDOWN
) );
500 case MA_NOACTIVATEANDEAT
:
501 case MA_ACTIVATEANDEAT
:
507 SetActiveWindow(hwnd
);
510 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma
);
514 PostMessageW( hwnd
, WM_X11DRV_DELETE_WINDOW
, 0, 0 );
517 else if (protocol
== x11drv_atom(WM_TAKE_FOCUS
))
519 Time event_time
= (Time
)event
->data
.l
[1];
520 HWND last_focus
= x11drv_thread_data()->last_focus
;
522 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
523 hwnd
, IsWindowEnabled(hwnd
), IsWindowVisible(hwnd
), GetWindowLongW(hwnd
, GWL_STYLE
),
524 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus
);
526 if (can_activate_window(hwnd
))
528 /* simulate a mouse click on the caption to find out
529 * whether the window wants to be activated */
530 LRESULT ma
= SendMessageW( hwnd
, WM_MOUSEACTIVATE
,
531 (WPARAM
)GetAncestor( hwnd
, GA_ROOT
),
532 MAKELONG(HTCAPTION
,WM_LBUTTONDOWN
) );
533 if (ma
!= MA_NOACTIVATEANDEAT
&& ma
!= MA_NOACTIVATE
)
535 set_focus( hwnd
, event_time
);
539 /* try to find some other window to give the focus to */
541 if (hwnd
) hwnd
= GetAncestor( hwnd
, GA_ROOT
);
542 if (!hwnd
) hwnd
= GetActiveWindow();
543 if (!hwnd
) hwnd
= last_focus
;
544 if (hwnd
&& can_activate_window(hwnd
)) set_focus( hwnd
, event_time
);
546 else if (protocol
== x11drv_atom(_NET_WM_PING
))
548 XClientMessageEvent xev
;
551 TRACE("NET_WM Ping\n");
553 xev
.window
= DefaultRootWindow(xev
.display
);
554 XSendEvent(xev
.display
, xev
.window
, False
, SubstructureRedirectMask
| SubstructureNotifyMask
, (XEvent
*)&xev
);
556 /* this line is semi-stolen from gtk2 */
557 TRACE("NET_WM Pong\n");
562 static const char * const focus_details
[] =
568 "NotifyNonlinearVirtual",
574 /**********************************************************************
577 static void X11DRV_FocusIn( HWND hwnd
, XEvent
*xev
)
579 XFocusChangeEvent
*event
= &xev
->xfocus
;
584 TRACE( "win %p xwin %lx detail=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
] );
586 if (event
->detail
== NotifyPointer
) return;
588 if ((xic
= X11DRV_get_ic( hwnd
)))
594 if (use_take_focus
) return; /* ignore FocusIn if we are using take focus */
596 if (!can_activate_window(hwnd
))
598 HWND hwnd
= GetFocus();
599 if (hwnd
) hwnd
= GetAncestor( hwnd
, GA_ROOT
);
600 if (!hwnd
) hwnd
= GetActiveWindow();
601 if (!hwnd
) hwnd
= x11drv_thread_data()->last_focus
;
602 if (hwnd
&& can_activate_window(hwnd
)) set_focus( hwnd
, CurrentTime
);
604 else SetForegroundWindow( hwnd
);
608 /**********************************************************************
611 * Note: only top-level windows get FocusOut events.
613 static void X11DRV_FocusOut( HWND hwnd
, XEvent
*xev
)
615 XFocusChangeEvent
*event
= &xev
->xfocus
;
623 TRACE( "win %p xwin %lx detail=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
] );
625 if (event
->detail
== NotifyPointer
) return;
626 if (ximInComposeMode
) return;
628 x11drv_thread_data()->last_focus
= hwnd
;
629 if ((xic
= X11DRV_get_ic( hwnd
)))
632 XUnsetICFocus( xic
);
635 if (hwnd
!= GetForegroundWindow()) return;
636 SendMessageW( hwnd
, WM_CANCELMODE
, 0, 0 );
638 /* don't reset the foreground window, if the window which is
639 getting the focus is a Wine window */
642 XGetInputFocus( thread_display(), &focus_win
, &revert
);
645 if (XFindContext( thread_display(), focus_win
, winContext
, (char **)&hwnd_tmp
) != 0)
652 /* Abey : 6-Oct-99. Check again if the focus out window is the
653 Foreground window, because in most cases the messages sent
654 above must have already changed the foreground window, in which
655 case we don't have to change the foreground window to 0 */
656 if (hwnd
== GetForegroundWindow())
658 TRACE( "lost focus, setting fg to desktop\n" );
659 SetForegroundWindow( GetDesktopWindow() );
665 /***********************************************************************
668 static void X11DRV_Expose( HWND hwnd
, XEvent
*xev
)
670 XExposeEvent
*event
= &xev
->xexpose
;
672 struct x11drv_win_data
*data
;
673 int flags
= RDW_INVALIDATE
| RDW_ERASE
;
675 TRACE( "win %p (%lx) %d,%d %dx%d\n",
676 hwnd
, event
->window
, event
->x
, event
->y
, event
->width
, event
->height
);
678 if (!(data
= X11DRV_get_win_data( hwnd
))) return;
680 if (event
->window
== data
->whole_window
)
682 rect
.left
= data
->whole_rect
.left
+ event
->x
;
683 rect
.top
= data
->whole_rect
.top
+ event
->y
;
688 rect
.left
= data
->client_rect
.left
+ event
->x
;
689 rect
.top
= data
->client_rect
.top
+ event
->y
;
691 rect
.right
= rect
.left
+ event
->width
;
692 rect
.bottom
= rect
.top
+ event
->height
;
694 if (event
->window
!= root_window
)
696 SERVER_START_REQ( update_window_zorder
)
699 req
->rect
.left
= rect
.left
;
700 req
->rect
.top
= rect
.top
;
701 req
->rect
.right
= rect
.right
;
702 req
->rect
.bottom
= rect
.bottom
;
703 wine_server_call( req
);
707 /* make position relative to client area instead of parent */
708 OffsetRect( &rect
, -data
->client_rect
.left
, -data
->client_rect
.top
);
709 flags
|= RDW_ALLCHILDREN
;
712 RedrawWindow( hwnd
, &rect
, 0, flags
);
716 /**********************************************************************
719 static void X11DRV_MapNotify( HWND hwnd
, XEvent
*event
)
721 struct x11drv_win_data
*data
;
723 if (!(data
= X11DRV_get_win_data( hwnd
))) return;
724 if (!data
->mapped
) return;
728 HWND hwndFocus
= GetFocus();
729 if (hwndFocus
&& IsChild( hwnd
, hwndFocus
)) X11DRV_SetFocus(hwndFocus
); /* FIXME */
734 /***********************************************************************
735 * X11DRV_ConfigureNotify
737 void X11DRV_ConfigureNotify( HWND hwnd
, XEvent
*xev
)
739 XConfigureEvent
*event
= &xev
->xconfigure
;
740 struct x11drv_win_data
*data
;
743 int cx
, cy
, x
= event
->x
, y
= event
->y
;
746 if (!(data
= X11DRV_get_win_data( hwnd
))) return;
747 if (!data
->mapped
|| data
->iconic
) return;
751 if (!event
->send_event
) /* normal event, need to map coordinates to the root */
755 XTranslateCoordinates( event
->display
, data
->whole_window
, root_window
,
756 0, 0, &x
, &y
, &child
);
761 rect
.right
= x
+ event
->width
;
762 rect
.bottom
= y
+ event
->height
;
763 OffsetRect( &rect
, virtual_screen_rect
.left
, virtual_screen_rect
.top
);
764 TRACE( "win %p new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
765 hwnd
, rect
.left
, rect
.top
, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
,
766 event
->x
, event
->y
, event
->width
, event
->height
);
767 X11DRV_X_to_window_rect( data
, &rect
);
771 cx
= rect
.right
- rect
.left
;
772 cy
= rect
.bottom
- rect
.top
;
773 flags
= SWP_NOACTIVATE
| SWP_NOZORDER
;
775 /* Compare what has changed */
777 GetWindowRect( hwnd
, &rect
);
778 if (rect
.left
== x
&& rect
.top
== y
) flags
|= SWP_NOMOVE
;
780 TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
781 hwnd
, rect
.left
, rect
.top
, x
, y
);
783 if ((rect
.right
- rect
.left
== cx
&& rect
.bottom
- rect
.top
== cy
) ||
784 (IsRectEmpty( &rect
) && event
->width
== 1 && event
->height
== 1))
786 if (flags
& SWP_NOMOVE
) return; /* if nothing changed, don't do anything */
790 TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
791 hwnd
, rect
.right
- rect
.left
, rect
.bottom
- rect
.top
, cx
, cy
);
793 SetWindowPos( hwnd
, 0, x
, y
, cx
, cy
, flags
);
797 /***********************************************************************
798 * get_window_wm_state
800 static int get_window_wm_state( Display
*display
, struct x11drv_win_data
*data
)
808 int format
, ret
= -1;
809 unsigned long count
, remaining
;
812 if (!XGetWindowProperty( display
, data
->whole_window
, x11drv_atom(WM_STATE
), 0,
813 sizeof(*state
)/sizeof(CARD32
), False
, x11drv_atom(WM_STATE
),
814 &type
, &format
, &count
, &remaining
, (unsigned char **)&state
))
816 if (type
== x11drv_atom(WM_STATE
) && get_property_size( format
, count
) >= sizeof(*state
))
825 /***********************************************************************
826 * handle_wm_state_notify
828 * Handle a PropertyNotify for WM_STATE.
830 static void handle_wm_state_notify( struct x11drv_win_data
*data
, XPropertyEvent
*event
,
836 data
->wm_state
= WithdrawnState
;
837 TRACE( "%p/%lx: WM_STATE deleted\n", data
->hwnd
, data
->whole_window
);
839 case PropertyNewValue
:
841 int new_state
= get_window_wm_state( event
->display
, data
);
842 if (new_state
!= -1 && new_state
!= data
->wm_state
)
844 TRACE( "%p/%lx: new WM_STATE %d\n", data
->hwnd
, data
->whole_window
, new_state
);
845 data
->wm_state
= new_state
;
851 if (!update_window
|| !data
->managed
|| !data
->mapped
) return;
853 if (data
->iconic
&& data
->wm_state
== NormalState
) /* restore window */
856 unsigned int width
, height
, border
, depth
;
863 XGetGeometry( event
->display
, data
->whole_window
, &root
, &x
, &y
, &width
, &height
,
865 XTranslateCoordinates( event
->display
, data
->whole_window
, root
, 0, 0, &x
, &y
, &top
);
869 rect
.right
= x
+ width
;
870 rect
.bottom
= y
+ height
;
871 OffsetRect( &rect
, virtual_screen_rect
.left
, virtual_screen_rect
.top
);
872 X11DRV_X_to_window_rect( data
, &rect
);
874 wp
.length
= sizeof(wp
);
875 GetWindowPlacement( data
->hwnd
, &wp
);
877 wp
.showCmd
= SW_RESTORE
;
878 wp
.rcNormalPosition
= rect
;
880 TRACE( "restoring win %p/%lx\n", data
->hwnd
, data
->whole_window
);
881 data
->iconic
= FALSE
;
882 SetWindowPlacement( data
->hwnd
, &wp
);
884 else if (!data
->iconic
&& data
->wm_state
== IconicState
)
886 TRACE( "minimizing win %p/%lx\n", data
->hwnd
, data
->whole_window
);
888 ShowWindow( data
->hwnd
, SW_MINIMIZE
);
893 /***********************************************************************
894 * X11DRV_PropertyNotify
896 static void X11DRV_PropertyNotify( HWND hwnd
, XEvent
*xev
)
898 XPropertyEvent
*event
= &xev
->xproperty
;
899 struct x11drv_win_data
*data
;
902 if (!(data
= X11DRV_get_win_data( hwnd
))) return;
904 if (event
->atom
== x11drv_atom(WM_STATE
)) handle_wm_state_notify( data
, event
, TRUE
);
908 /* event filter to wait for a WM_STATE change notification on a window */
909 static Bool
is_wm_state_notify( Display
*display
, XEvent
*event
, XPointer arg
)
911 if (event
->xany
.window
!= (Window
)arg
) return 0;
912 return (event
->type
== DestroyNotify
||
913 (event
->type
== PropertyNotify
&& event
->xproperty
.atom
== x11drv_atom(WM_STATE
)));
916 /***********************************************************************
917 * wait_for_withdrawn_state
919 void wait_for_withdrawn_state( Display
*display
, struct x11drv_win_data
*data
, BOOL set
)
921 DWORD end
= GetTickCount() + 2000;
923 if (!data
->managed
) return;
925 TRACE( "waiting for window %p/%lx to become %swithdrawn\n",
926 data
->hwnd
, data
->whole_window
, set
? "" : "not " );
928 while (data
->whole_window
&& ((data
->wm_state
== WithdrawnState
) == !set
))
934 while (XCheckIfEvent( display
, &event
, is_wm_state_notify
, (char *)data
->whole_window
))
937 if (XFilterEvent( &event
, None
)) continue; /* filtered, ignore it */
938 if (event
.type
== DestroyNotify
) call_event_handler( display
, &event
);
942 handle_wm_state_notify( data
, &event
.xproperty
, FALSE
);
951 int timeout
= end
- GetTickCount();
953 pfd
.fd
= ConnectionNumber(display
);
955 if (timeout
<= 0 || poll( &pfd
, 1, timeout
) != 1)
957 FIXME( "window %p/%lx wait timed out\n", data
->hwnd
, data
->whole_window
);
962 TRACE( "window %p/%lx state now %d\n", data
->hwnd
, data
->whole_window
, data
->wm_state
);
966 static HWND
find_drop_window( HWND hQueryWnd
, LPPOINT lpPt
)
970 if (!IsWindowEnabled(hQueryWnd
)) return 0;
972 GetWindowRect(hQueryWnd
, &tempRect
);
974 if(!PtInRect(&tempRect
, *lpPt
)) return 0;
976 if (!IsIconic( hQueryWnd
))
979 ScreenToClient( hQueryWnd
, &pt
);
980 GetClientRect( hQueryWnd
, &tempRect
);
982 if (PtInRect( &tempRect
, pt
))
984 HWND ret
= ChildWindowFromPointEx( hQueryWnd
, pt
, CWP_SKIPINVISIBLE
|CWP_SKIPDISABLED
);
985 if (ret
&& ret
!= hQueryWnd
)
987 ret
= find_drop_window( ret
, lpPt
);
993 if(!(GetWindowLongA( hQueryWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return 0;
995 ScreenToClient(hQueryWnd
, lpPt
);
1000 /**********************************************************************
1001 * EVENT_DropFromOffix
1003 * don't know if it still works (last Changelog is from 96/11/04)
1005 static void EVENT_DropFromOffiX( HWND hWnd
, XClientMessageEvent
*event
)
1007 struct x11drv_win_data
*data
;
1008 unsigned long data_length
;
1009 unsigned long aux_long
;
1010 unsigned char* p_data
= NULL
;
1014 Window win
, w_aux_root
, w_aux_child
;
1016 win
= X11DRV_get_whole_window(hWnd
);
1018 XQueryPointer( event
->display
, win
, &w_aux_root
, &w_aux_child
,
1019 &x
, &y
, &dummy
, &dummy
, (unsigned int*)&aux_long
);
1020 x
+= virtual_screen_rect
.left
;
1021 y
+= virtual_screen_rect
.top
;
1022 wine_tsx11_unlock();
1024 if (!(data
= X11DRV_get_win_data( hWnd
))) return;
1026 /* find out drop point and drop window */
1027 if( x
< 0 || y
< 0 ||
1028 x
> (data
->whole_rect
.right
- data
->whole_rect
.left
) ||
1029 y
> (data
->whole_rect
.bottom
- data
->whole_rect
.top
) )
1031 bAccept
= GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
;
1037 POINT pt
= { x
, y
};
1038 HWND hwndDrop
= find_drop_window( hWnd
, &pt
);
1051 if (!bAccept
) return;
1054 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
1055 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
1056 AnyPropertyType
, &atom_aux
, &dummy
,
1057 &data_length
, &aux_long
, &p_data
);
1058 wine_tsx11_unlock();
1060 if( !aux_long
&& p_data
) /* don't bother if > 64K */
1062 char *p
= (char *)p_data
;
1066 while( *p
) /* calculate buffer size */
1068 INT len
= GetShortPathNameA( p
, NULL
, 0 );
1069 if (len
) aux_long
+= len
+ 1;
1072 if( aux_long
&& aux_long
< 65535 )
1077 aux_long
+= sizeof(DROPFILES
) + 1;
1078 hDrop
= GlobalAlloc( GMEM_SHARE
, aux_long
);
1079 lpDrop
= (DROPFILES
*)GlobalLock( hDrop
);
1083 lpDrop
->pFiles
= sizeof(DROPFILES
);
1086 lpDrop
->fNC
= FALSE
;
1087 lpDrop
->fWide
= FALSE
;
1088 p_drop
= (char *)(lpDrop
+ 1);
1092 if (GetShortPathNameA( p
, p_drop
, aux_long
- (p_drop
- (char *)lpDrop
) ))
1093 p_drop
+= strlen( p_drop
) + 1;
1097 PostMessageA( hWnd
, WM_DROPFILES
, (WPARAM
)hDrop
, 0L );
1102 if( p_data
) XFree(p_data
);
1103 wine_tsx11_unlock();
1106 /**********************************************************************
1109 * drop items are separated by \n
1110 * each item is prefixed by its mime type
1112 * event->data.l[3], event->data.l[4] contains drop x,y position
1114 static void EVENT_DropURLs( HWND hWnd
, XClientMessageEvent
*event
)
1116 struct x11drv_win_data
*win_data
;
1117 unsigned long data_length
;
1118 unsigned long aux_long
, drop_len
= 0;
1119 unsigned char *p_data
= NULL
; /* property data */
1120 char *p_drop
= NULL
;
1132 if (!(GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return;
1135 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
1136 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
1137 AnyPropertyType
, &u
.atom_aux
, &u
.i
,
1138 &data_length
, &aux_long
, &p_data
);
1139 wine_tsx11_unlock();
1141 WARN("property too large, truncated!\n");
1142 TRACE("urls=%s\n", p_data
);
1144 if( !aux_long
&& p_data
) { /* don't bother if > 64K */
1145 /* calculate length */
1147 next
= strchr(p
, '\n');
1150 if (strncmp(p
,"file:",5) == 0 ) {
1151 INT len
= GetShortPathNameA( p
+5, NULL
, 0 );
1152 if (len
) drop_len
+= len
+ 1;
1157 next
= strchr(p
, '\n');
1163 if( drop_len
&& drop_len
< 65535 ) {
1165 XQueryPointer( event
->display
, root_window
, &u
.w_aux
, &u
.w_aux
,
1166 &x
, &y
, &u
.i
, &u
.i
, &u
.u
);
1167 x
+= virtual_screen_rect
.left
;
1168 y
+= virtual_screen_rect
.top
;
1169 wine_tsx11_unlock();
1171 drop_len
+= sizeof(DROPFILES
) + 1;
1172 hDrop
= GlobalAlloc( GMEM_SHARE
, drop_len
);
1173 lpDrop
= (DROPFILES
*) GlobalLock( hDrop
);
1175 if( lpDrop
&& (win_data
= X11DRV_get_win_data( hWnd
)))
1177 lpDrop
->pFiles
= sizeof(DROPFILES
);
1181 ( x
< (win_data
->client_rect
.left
- win_data
->whole_rect
.left
) ||
1182 y
< (win_data
->client_rect
.top
- win_data
->whole_rect
.top
) ||
1183 x
> (win_data
->client_rect
.right
- win_data
->whole_rect
.left
) ||
1184 y
> (win_data
->client_rect
.bottom
- win_data
->whole_rect
.top
) );
1185 lpDrop
->fWide
= FALSE
;
1186 p_drop
= (char*)(lpDrop
+ 1);
1189 /* create message content */
1192 next
= strchr(p
, '\n');
1195 if (strncmp(p
,"file:",5) == 0 ) {
1196 INT len
= GetShortPathNameA( p
+5, p_drop
, 65535 );
1198 TRACE("drop file %s as %s\n", p
+5, p_drop
);
1201 WARN("can't convert file %s to dos name\n", p
+5);
1204 WARN("unknown mime type %s\n", p
);
1209 next
= strchr(p
, '\n');
1216 GlobalUnlock(hDrop
);
1217 PostMessageA( hWnd
, WM_DROPFILES
, (WPARAM
)hDrop
, 0L );
1221 if( p_data
) XFree(p_data
);
1222 wine_tsx11_unlock();
1226 /**********************************************************************
1227 * handle_dnd_protocol
1229 static void handle_dnd_protocol( HWND hwnd
, XClientMessageEvent
*event
)
1232 int root_x
, root_y
, child_x
, child_y
;
1235 /* query window (drag&drop event contains only drag window) */
1237 XQueryPointer( event
->display
, root_window
, &root
, &child
,
1238 &root_x
, &root_y
, &child_x
, &child_y
, &u
);
1239 if (XFindContext( event
->display
, child
, winContext
, (char **)&hwnd
) != 0) hwnd
= 0;
1240 wine_tsx11_unlock();
1242 if (event
->data
.l
[0] == DndFile
|| event
->data
.l
[0] == DndFiles
)
1243 EVENT_DropFromOffiX(hwnd
, event
);
1244 else if (event
->data
.l
[0] == DndURL
)
1245 EVENT_DropURLs(hwnd
, event
);
1249 struct client_message_handler
1251 int atom
; /* protocol atom */
1252 void (*handler
)(HWND
, XClientMessageEvent
*); /* corresponding handler function */
1255 static const struct client_message_handler client_messages
[] =
1257 { XATOM_WM_PROTOCOLS
, handle_wm_protocols
},
1258 { XATOM_DndProtocol
, handle_dnd_protocol
},
1259 { XATOM_XdndEnter
, X11DRV_XDND_EnterEvent
},
1260 { XATOM_XdndPosition
, X11DRV_XDND_PositionEvent
},
1261 { XATOM_XdndDrop
, X11DRV_XDND_DropEvent
},
1262 { XATOM_XdndLeave
, X11DRV_XDND_LeaveEvent
}
1266 /**********************************************************************
1267 * X11DRV_ClientMessage
1269 static void X11DRV_ClientMessage( HWND hwnd
, XEvent
*xev
)
1271 XClientMessageEvent
*event
= &xev
->xclient
;
1276 if (event
->format
!= 32)
1278 WARN( "Don't know how to handle format %d\n", event
->format
);
1282 for (i
= 0; i
< sizeof(client_messages
)/sizeof(client_messages
[0]); i
++)
1284 if (event
->message_type
== X11DRV_Atoms
[client_messages
[i
].atom
- FIRST_XATOM
])
1286 client_messages
[i
].handler( hwnd
, event
);
1290 TRACE( "no handler found for %ld\n", event
->message_type
);
1294 /**********************************************************************
1295 * X11DRV_WindowMessage (X11DRV.@)
1297 LRESULT
X11DRV_WindowMessage( HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
1301 case WM_X11DRV_ACQUIRE_SELECTION
:
1302 return X11DRV_AcquireClipboard( hwnd
);
1303 case WM_X11DRV_DELETE_WINDOW
:
1304 return SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_CLOSE
, 0 );
1305 case WM_X11DRV_SET_WIN_FORMAT
:
1306 return X11DRV_set_win_format( hwnd
, (XID
)wp
);
1307 case WM_X11DRV_RESIZE_DESKTOP
:
1308 X11DRV_resize_desktop( LOWORD(lp
), HIWORD(lp
) );
1311 FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg
, hwnd
, wp
, lp
);
1317 /***********************************************************************
1318 * X11DRV_SendInput (X11DRV.@)
1320 UINT
X11DRV_SendInput( UINT count
, LPINPUT inputs
, int size
)
1324 for (i
= 0; i
< count
; i
++, inputs
++)
1326 switch(inputs
->type
)
1329 X11DRV_send_mouse_input( 0, inputs
->u
.mi
.dwFlags
, inputs
->u
.mi
.dx
, inputs
->u
.mi
.dy
,
1330 inputs
->u
.mi
.mouseData
, inputs
->u
.mi
.time
,
1331 inputs
->u
.mi
.dwExtraInfo
, LLMHF_INJECTED
);
1333 case INPUT_KEYBOARD
:
1334 X11DRV_send_keyboard_input( inputs
->u
.ki
.wVk
, inputs
->u
.ki
.wScan
, inputs
->u
.ki
.dwFlags
,
1335 inputs
->u
.ki
.time
, inputs
->u
.ki
.dwExtraInfo
, LLKHF_INJECTED
);
1337 case INPUT_HARDWARE
:
1338 FIXME( "INPUT_HARDWARE not supported\n" );