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
))
340 * SCIM on linux filters key events strangely. It does not filter the
341 * KeyPress events for these keys however it does filter the
342 * KeyRelease events. This causes wine to become very confused as
343 * to the keyboard state.
345 * We need to let those KeyRelease events be processed so that the
346 * keyboard state is correct.
348 if (event
.type
== KeyRelease
)
351 XKeyEvent
*keyevent
= &event
.xkey
;
353 XLookupString(keyevent
, NULL
, 0, &keysym
, NULL
);
354 if (!(keysym
== XK_Shift_L
||
355 keysym
== XK_Shift_R
||
356 keysym
== XK_Control_L
||
357 keysym
== XK_Control_R
||
358 keysym
== XK_Alt_R
||
359 keysym
== XK_Alt_L
||
360 keysym
== XK_Meta_R
||
361 keysym
== XK_Meta_L
))
362 continue; /* not a key we care about, ignore it */
365 continue; /* filtered, ignore it */
367 if (prev_event
.type
) action
= merge_events( &prev_event
, &event
);
370 case MERGE_DISCARD
: /* discard prev, keep new */
373 case MERGE_HANDLE
: /* handle prev, keep new */
374 call_event_handler( display
, &prev_event
);
377 case MERGE_KEEP
: /* handle new, keep prev for future merging */
378 call_event_handler( display
, &event
);
382 XFlush( gdi_display
);
383 if (prev_event
.type
) call_event_handler( display
, &prev_event
);
385 if (count
) TRACE( "processed %d events\n", count
);
390 /***********************************************************************
391 * MsgWaitForMultipleObjectsEx (X11DRV.@)
393 DWORD CDECL
X11DRV_MsgWaitForMultipleObjectsEx( DWORD count
, const HANDLE
*handles
,
394 DWORD timeout
, DWORD mask
, DWORD flags
)
397 struct x11drv_thread_data
*data
= TlsGetValue( thread_data_tls_index
);
401 if (!count
&& !timeout
) return WAIT_TIMEOUT
;
402 return WaitForMultipleObjectsEx( count
, handles
, flags
& MWMO_WAITALL
,
403 timeout
, flags
& MWMO_ALERTABLE
);
406 if (data
->current_event
) mask
= 0; /* don't process nested events */
408 if (process_events( data
->display
, filter_event
, mask
)) ret
= count
- 1;
409 else if (count
|| timeout
)
411 ret
= WaitForMultipleObjectsEx( count
, handles
, flags
& MWMO_WAITALL
,
412 timeout
, flags
& MWMO_ALERTABLE
);
413 if (ret
== count
- 1) process_events( data
->display
, filter_event
, mask
);
415 else ret
= WAIT_TIMEOUT
;
420 /***********************************************************************
421 * EVENT_x11_time_to_win32_time
423 * Make our timer and the X timer line up as best we can
424 * Pass 0 to retrieve the current adjustment value (times -1)
426 DWORD
EVENT_x11_time_to_win32_time(Time time
)
428 static DWORD adjust
= 0;
429 DWORD now
= GetTickCount();
432 if (! adjust
&& time
!= 0)
439 /* If we got an event in the 'future', then our clock is clearly wrong.
440 If we got it more than 10000 ms in the future, then it's most likely
441 that the clock has wrapped. */
444 if (ret
> now
&& ((ret
- now
) < 10000) && time
!= 0)
455 /*******************************************************************
456 * can_activate_window
458 * Check if we can activate the specified window.
460 static inline BOOL
can_activate_window( HWND hwnd
)
462 LONG style
= GetWindowLongW( hwnd
, GWL_STYLE
);
463 if (!(style
& WS_VISIBLE
)) return FALSE
;
464 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return FALSE
;
465 if (hwnd
== GetDesktopWindow()) return FALSE
;
466 return !(style
& WS_DISABLED
);
470 /**********************************************************************
473 static void set_focus( Display
*display
, HWND hwnd
, Time time
)
478 TRACE( "setting foreground window to %p\n", hwnd
);
479 SetForegroundWindow( hwnd
);
482 if (focus
) focus
= GetAncestor( focus
, GA_ROOT
);
483 win
= X11DRV_get_whole_window(focus
);
487 TRACE( "setting focus to %p (%lx) time=%ld\n", focus
, win
, time
);
489 XSetInputFocus( display
, win
, RevertToParent
, time
);
495 /**********************************************************************
496 * handle_wm_protocols
498 static void handle_wm_protocols( HWND hwnd
, XClientMessageEvent
*event
)
500 Atom protocol
= (Atom
)event
->data
.l
[0];
502 if (!protocol
) return;
504 if (protocol
== x11drv_atom(WM_DELETE_WINDOW
))
506 /* Ignore the delete window request if the window has been disabled
507 * and we are in managed mode. This is to disallow applications from
508 * being closed by the window manager while in a modal state.
510 if (IsWindowEnabled(hwnd
))
514 if (GetClassLongW(hwnd
, GCL_STYLE
) & CS_NOCLOSE
) return;
515 hSysMenu
= GetSystemMenu(hwnd
, FALSE
);
518 UINT state
= GetMenuState(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
);
519 if (state
== 0xFFFFFFFF || (state
& (MF_DISABLED
| MF_GRAYED
)))
522 if (GetActiveWindow() != hwnd
)
524 LRESULT ma
= SendMessageW( hwnd
, WM_MOUSEACTIVATE
,
525 (WPARAM
)GetAncestor( hwnd
, GA_ROOT
),
526 MAKELONG(HTCLOSE
,WM_LBUTTONDOWN
) );
529 case MA_NOACTIVATEANDEAT
:
530 case MA_ACTIVATEANDEAT
:
536 SetActiveWindow(hwnd
);
539 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma
);
543 PostMessageW( hwnd
, WM_X11DRV_DELETE_WINDOW
, 0, 0 );
546 else if (protocol
== x11drv_atom(WM_TAKE_FOCUS
))
548 Time event_time
= (Time
)event
->data
.l
[1];
549 HWND last_focus
= x11drv_thread_data()->last_focus
;
551 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
552 hwnd
, IsWindowEnabled(hwnd
), IsWindowVisible(hwnd
), GetWindowLongW(hwnd
, GWL_STYLE
),
553 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus
);
555 if (can_activate_window(hwnd
))
557 /* simulate a mouse click on the caption to find out
558 * whether the window wants to be activated */
559 LRESULT ma
= SendMessageW( hwnd
, WM_MOUSEACTIVATE
,
560 (WPARAM
)GetAncestor( hwnd
, GA_ROOT
),
561 MAKELONG(HTCAPTION
,WM_LBUTTONDOWN
) );
562 if (ma
!= MA_NOACTIVATEANDEAT
&& ma
!= MA_NOACTIVATE
)
564 set_focus( event
->display
, hwnd
, event_time
);
568 /* try to find some other window to give the focus to */
570 if (hwnd
) hwnd
= GetAncestor( hwnd
, GA_ROOT
);
571 if (!hwnd
) hwnd
= GetActiveWindow();
572 if (!hwnd
) hwnd
= last_focus
;
573 if (hwnd
&& can_activate_window(hwnd
)) set_focus( event
->display
, hwnd
, event_time
);
575 else if (protocol
== x11drv_atom(_NET_WM_PING
))
577 XClientMessageEvent xev
;
580 TRACE("NET_WM Ping\n");
582 xev
.window
= DefaultRootWindow(xev
.display
);
583 XSendEvent(xev
.display
, xev
.window
, False
, SubstructureRedirectMask
| SubstructureNotifyMask
, (XEvent
*)&xev
);
585 /* this line is semi-stolen from gtk2 */
586 TRACE("NET_WM Pong\n");
591 static const char * const focus_details
[] =
597 "NotifyNonlinearVirtual",
603 /**********************************************************************
606 static void X11DRV_FocusIn( HWND hwnd
, XEvent
*xev
)
608 XFocusChangeEvent
*event
= &xev
->xfocus
;
613 TRACE( "win %p xwin %lx detail=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
] );
615 if (event
->detail
== NotifyPointer
) return;
617 if ((xic
= X11DRV_get_ic( hwnd
)))
623 if (use_take_focus
) return; /* ignore FocusIn if we are using take focus */
625 if (!can_activate_window(hwnd
))
627 HWND hwnd
= GetFocus();
628 if (hwnd
) hwnd
= GetAncestor( hwnd
, GA_ROOT
);
629 if (!hwnd
) hwnd
= GetActiveWindow();
630 if (!hwnd
) hwnd
= x11drv_thread_data()->last_focus
;
631 if (hwnd
&& can_activate_window(hwnd
)) set_focus( event
->display
, hwnd
, CurrentTime
);
633 else SetForegroundWindow( hwnd
);
637 /**********************************************************************
640 * Note: only top-level windows get FocusOut events.
642 static void X11DRV_FocusOut( HWND hwnd
, XEvent
*xev
)
644 XFocusChangeEvent
*event
= &xev
->xfocus
;
652 TRACE( "win %p xwin %lx detail=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
] );
654 if (event
->detail
== NotifyPointer
) return;
655 if (ximInComposeMode
) return;
657 x11drv_thread_data()->last_focus
= hwnd
;
658 if ((xic
= X11DRV_get_ic( hwnd
)))
661 XUnsetICFocus( xic
);
664 if (hwnd
!= GetForegroundWindow()) return;
665 SendMessageW( hwnd
, WM_CANCELMODE
, 0, 0 );
667 /* don't reset the foreground window, if the window which is
668 getting the focus is a Wine window */
671 XGetInputFocus( event
->display
, &focus_win
, &revert
);
674 if (XFindContext( event
->display
, focus_win
, winContext
, (char **)&hwnd_tmp
) != 0)
681 /* Abey : 6-Oct-99. Check again if the focus out window is the
682 Foreground window, because in most cases the messages sent
683 above must have already changed the foreground window, in which
684 case we don't have to change the foreground window to 0 */
685 if (hwnd
== GetForegroundWindow())
687 TRACE( "lost focus, setting fg to desktop\n" );
688 SetForegroundWindow( GetDesktopWindow() );
694 /***********************************************************************
697 static void X11DRV_Expose( HWND hwnd
, XEvent
*xev
)
699 XExposeEvent
*event
= &xev
->xexpose
;
701 struct x11drv_win_data
*data
;
702 int flags
= RDW_INVALIDATE
| RDW_ERASE
;
704 TRACE( "win %p (%lx) %d,%d %dx%d\n",
705 hwnd
, event
->window
, event
->x
, event
->y
, event
->width
, event
->height
);
707 if (!(data
= X11DRV_get_win_data( hwnd
))) return;
709 if (event
->window
== data
->whole_window
)
711 rect
.left
= data
->whole_rect
.left
+ event
->x
;
712 rect
.top
= data
->whole_rect
.top
+ event
->y
;
717 rect
.left
= data
->client_rect
.left
+ event
->x
;
718 rect
.top
= data
->client_rect
.top
+ event
->y
;
720 rect
.right
= rect
.left
+ event
->width
;
721 rect
.bottom
= rect
.top
+ event
->height
;
723 if (event
->window
!= root_window
)
725 SERVER_START_REQ( update_window_zorder
)
727 req
->window
= wine_server_user_handle( hwnd
);
728 req
->rect
.left
= rect
.left
;
729 req
->rect
.top
= rect
.top
;
730 req
->rect
.right
= rect
.right
;
731 req
->rect
.bottom
= rect
.bottom
;
732 wine_server_call( req
);
736 /* make position relative to client area instead of parent */
737 OffsetRect( &rect
, -data
->client_rect
.left
, -data
->client_rect
.top
);
738 flags
|= RDW_ALLCHILDREN
;
741 RedrawWindow( hwnd
, &rect
, 0, flags
);
745 /**********************************************************************
748 static void X11DRV_MapNotify( HWND hwnd
, XEvent
*event
)
750 struct x11drv_win_data
*data
;
752 if (!(data
= X11DRV_get_win_data( hwnd
))) return;
753 if (!data
->mapped
) return;
757 HWND hwndFocus
= GetFocus();
758 if (hwndFocus
&& IsChild( hwnd
, hwndFocus
)) X11DRV_SetFocus(hwndFocus
); /* FIXME */
763 /***********************************************************************
764 * is_net_wm_state_maximized
766 static BOOL
is_net_wm_state_maximized( Display
*display
, struct x11drv_win_data
*data
)
770 unsigned long i
, count
, remaining
;
773 if (!XGetWindowProperty( display
, data
->whole_window
, x11drv_atom(_NET_WM_STATE
), 0,
774 65536/sizeof(CARD32
), False
, XA_ATOM
, &type
, &format
, &count
,
775 &remaining
, (unsigned char **)&state
))
777 if (type
== XA_ATOM
&& format
== 32)
779 for (i
= 0; i
< count
; i
++)
781 if (state
[i
] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_VERT
) ||
782 state
[i
] == x11drv_atom(_NET_WM_STATE_MAXIMIZED_HORZ
))
793 /***********************************************************************
794 * X11DRV_ConfigureNotify
796 void X11DRV_ConfigureNotify( HWND hwnd
, XEvent
*xev
)
798 XConfigureEvent
*event
= &xev
->xconfigure
;
799 struct x11drv_win_data
*data
;
802 int cx
, cy
, x
= event
->x
, y
= event
->y
;
805 if (!(data
= X11DRV_get_win_data( hwnd
))) return;
806 if (!data
->mapped
|| data
->iconic
|| !data
->managed
) return;
810 if (!event
->send_event
) /* normal event, need to map coordinates to the root */
814 XTranslateCoordinates( event
->display
, data
->whole_window
, root_window
,
815 0, 0, &x
, &y
, &child
);
820 rect
.right
= x
+ event
->width
;
821 rect
.bottom
= y
+ event
->height
;
822 OffsetRect( &rect
, virtual_screen_rect
.left
, virtual_screen_rect
.top
);
823 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
824 hwnd
, data
->whole_window
, rect
.left
, rect
.top
, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
,
825 event
->x
, event
->y
, event
->width
, event
->height
);
826 X11DRV_X_to_window_rect( data
, &rect
);
828 if (is_net_wm_state_maximized( event
->display
, data
))
830 if (!IsZoomed( data
->hwnd
))
832 TRACE( "win %p/%lx is maximized\n", data
->hwnd
, data
->whole_window
);
833 SendMessageW( data
->hwnd
, WM_SYSCOMMAND
, SC_MAXIMIZE
, 0 );
839 if (IsZoomed( data
->hwnd
))
841 TRACE( "window %p/%lx is no longer maximized\n", data
->hwnd
, data
->whole_window
);
842 SendMessageW( data
->hwnd
, WM_SYSCOMMAND
, SC_RESTORE
, 0 );
847 /* Compare what has changed */
851 cx
= rect
.right
- rect
.left
;
852 cy
= rect
.bottom
- rect
.top
;
853 flags
= SWP_NOACTIVATE
| SWP_NOZORDER
;
855 if (data
->window_rect
.left
== x
&& data
->window_rect
.top
== y
) flags
|= SWP_NOMOVE
;
857 TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
858 hwnd
, data
->window_rect
.left
, data
->window_rect
.top
, x
, y
);
860 if ((data
->window_rect
.right
- data
->window_rect
.left
== cx
&&
861 data
->window_rect
.bottom
- data
->window_rect
.top
== cy
) ||
862 (IsRectEmpty( &data
->window_rect
) && event
->width
== 1 && event
->height
== 1))
864 if (flags
& SWP_NOMOVE
) return; /* if nothing changed, don't do anything */
868 TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
869 hwnd
, data
->window_rect
.right
- data
->window_rect
.left
,
870 data
->window_rect
.bottom
- data
->window_rect
.top
, cx
, cy
);
872 SetWindowPos( hwnd
, 0, x
, y
, cx
, cy
, flags
);
876 /***********************************************************************
877 * get_window_wm_state
879 static int get_window_wm_state( Display
*display
, struct x11drv_win_data
*data
)
887 int format
, ret
= -1;
888 unsigned long count
, remaining
;
891 if (!XGetWindowProperty( display
, data
->whole_window
, x11drv_atom(WM_STATE
), 0,
892 sizeof(*state
)/sizeof(CARD32
), False
, x11drv_atom(WM_STATE
),
893 &type
, &format
, &count
, &remaining
, (unsigned char **)&state
))
895 if (type
== x11drv_atom(WM_STATE
) && get_property_size( format
, count
) >= sizeof(*state
))
904 /***********************************************************************
905 * handle_wm_state_notify
907 * Handle a PropertyNotify for WM_STATE.
909 static void handle_wm_state_notify( struct x11drv_win_data
*data
, XPropertyEvent
*event
,
915 TRACE( "%p/%lx: WM_STATE deleted from %d\n", data
->hwnd
, data
->whole_window
, data
->wm_state
);
916 data
->wm_state
= WithdrawnState
;
918 case PropertyNewValue
:
920 int old_state
= data
->wm_state
;
921 int new_state
= get_window_wm_state( event
->display
, data
);
922 if (new_state
!= -1 && new_state
!= data
->wm_state
)
924 TRACE( "%p/%lx: new WM_STATE %d from %d\n",
925 data
->hwnd
, data
->whole_window
, new_state
, old_state
);
926 data
->wm_state
= new_state
;
927 /* ignore the initial state transition out of withdrawn state */
928 /* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */
929 if (!old_state
) return;
935 if (!update_window
|| !data
->managed
|| !data
->mapped
) return;
937 if (data
->iconic
&& data
->wm_state
== NormalState
) /* restore window */
939 data
->iconic
= FALSE
;
940 if (is_net_wm_state_maximized( event
->display
, data
))
942 TRACE( "restoring to max %p/%lx\n", data
->hwnd
, data
->whole_window
);
943 SendMessageW( data
->hwnd
, WM_SYSCOMMAND
, SC_MAXIMIZE
, 0 );
947 TRACE( "restoring win %p/%lx\n", data
->hwnd
, data
->whole_window
);
948 SendMessageW( data
->hwnd
, WM_SYSCOMMAND
, SC_RESTORE
, 0 );
951 else if (!data
->iconic
&& data
->wm_state
== IconicState
)
953 TRACE( "minimizing win %p/%lx\n", data
->hwnd
, data
->whole_window
);
955 SendMessageW( data
->hwnd
, WM_SYSCOMMAND
, SC_MINIMIZE
, 0 );
960 /***********************************************************************
961 * X11DRV_PropertyNotify
963 static void X11DRV_PropertyNotify( HWND hwnd
, XEvent
*xev
)
965 XPropertyEvent
*event
= &xev
->xproperty
;
966 struct x11drv_win_data
*data
;
969 if (!(data
= X11DRV_get_win_data( hwnd
))) return;
971 if (event
->atom
== x11drv_atom(WM_STATE
)) handle_wm_state_notify( data
, event
, TRUE
);
975 /* event filter to wait for a WM_STATE change notification on a window */
976 static Bool
is_wm_state_notify( Display
*display
, XEvent
*event
, XPointer arg
)
978 if (event
->xany
.window
!= (Window
)arg
) return 0;
979 return (event
->type
== DestroyNotify
||
980 (event
->type
== PropertyNotify
&& event
->xproperty
.atom
== x11drv_atom(WM_STATE
)));
983 /***********************************************************************
984 * wait_for_withdrawn_state
986 void wait_for_withdrawn_state( Display
*display
, struct x11drv_win_data
*data
, BOOL set
)
988 DWORD end
= GetTickCount() + 2000;
990 if (!data
->managed
) return;
992 TRACE( "waiting for window %p/%lx to become %swithdrawn\n",
993 data
->hwnd
, data
->whole_window
, set
? "" : "not " );
995 while (data
->whole_window
&& ((data
->wm_state
== WithdrawnState
) == !set
))
1001 while (XCheckIfEvent( display
, &event
, is_wm_state_notify
, (char *)data
->whole_window
))
1004 if (XFilterEvent( &event
, None
)) continue; /* filtered, ignore it */
1005 if (event
.type
== DestroyNotify
) call_event_handler( display
, &event
);
1008 wine_tsx11_unlock();
1009 handle_wm_state_notify( data
, &event
.xproperty
, FALSE
);
1013 wine_tsx11_unlock();
1018 int timeout
= end
- GetTickCount();
1020 pfd
.fd
= ConnectionNumber(display
);
1021 pfd
.events
= POLLIN
;
1022 if (timeout
<= 0 || poll( &pfd
, 1, timeout
) != 1)
1024 FIXME( "window %p/%lx wait timed out\n", data
->hwnd
, data
->whole_window
);
1029 TRACE( "window %p/%lx state now %d\n", data
->hwnd
, data
->whole_window
, data
->wm_state
);
1033 static HWND
find_drop_window( HWND hQueryWnd
, LPPOINT lpPt
)
1037 if (!IsWindowEnabled(hQueryWnd
)) return 0;
1039 GetWindowRect(hQueryWnd
, &tempRect
);
1041 if(!PtInRect(&tempRect
, *lpPt
)) return 0;
1043 if (!IsIconic( hQueryWnd
))
1046 ScreenToClient( hQueryWnd
, &pt
);
1047 GetClientRect( hQueryWnd
, &tempRect
);
1049 if (PtInRect( &tempRect
, pt
))
1051 HWND ret
= ChildWindowFromPointEx( hQueryWnd
, pt
, CWP_SKIPINVISIBLE
|CWP_SKIPDISABLED
);
1052 if (ret
&& ret
!= hQueryWnd
)
1054 ret
= find_drop_window( ret
, lpPt
);
1055 if (ret
) return ret
;
1060 if(!(GetWindowLongA( hQueryWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return 0;
1062 ScreenToClient(hQueryWnd
, lpPt
);
1067 /**********************************************************************
1068 * EVENT_DropFromOffix
1070 * don't know if it still works (last Changelog is from 96/11/04)
1072 static void EVENT_DropFromOffiX( HWND hWnd
, XClientMessageEvent
*event
)
1074 struct x11drv_win_data
*data
;
1075 unsigned long data_length
;
1076 unsigned long aux_long
;
1077 unsigned char* p_data
= NULL
;
1081 Window win
, w_aux_root
, w_aux_child
;
1083 win
= X11DRV_get_whole_window(hWnd
);
1085 XQueryPointer( event
->display
, win
, &w_aux_root
, &w_aux_child
,
1086 &x
, &y
, &dummy
, &dummy
, (unsigned int*)&aux_long
);
1087 x
+= virtual_screen_rect
.left
;
1088 y
+= virtual_screen_rect
.top
;
1089 wine_tsx11_unlock();
1091 if (!(data
= X11DRV_get_win_data( hWnd
))) return;
1093 /* find out drop point and drop window */
1094 if( x
< 0 || y
< 0 ||
1095 x
> (data
->whole_rect
.right
- data
->whole_rect
.left
) ||
1096 y
> (data
->whole_rect
.bottom
- data
->whole_rect
.top
) )
1098 bAccept
= GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
;
1104 POINT pt
= { x
, y
};
1105 HWND hwndDrop
= find_drop_window( hWnd
, &pt
);
1118 if (!bAccept
) return;
1121 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
1122 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
1123 AnyPropertyType
, &atom_aux
, &dummy
,
1124 &data_length
, &aux_long
, &p_data
);
1125 wine_tsx11_unlock();
1127 if( !aux_long
&& p_data
) /* don't bother if > 64K */
1129 char *p
= (char *)p_data
;
1133 while( *p
) /* calculate buffer size */
1135 INT len
= GetShortPathNameA( p
, NULL
, 0 );
1136 if (len
) aux_long
+= len
+ 1;
1139 if( aux_long
&& aux_long
< 65535 )
1144 aux_long
+= sizeof(DROPFILES
) + 1;
1145 hDrop
= GlobalAlloc( GMEM_SHARE
, aux_long
);
1146 lpDrop
= GlobalLock( hDrop
);
1150 lpDrop
->pFiles
= sizeof(DROPFILES
);
1153 lpDrop
->fNC
= FALSE
;
1154 lpDrop
->fWide
= FALSE
;
1155 p_drop
= (char *)(lpDrop
+ 1);
1159 if (GetShortPathNameA( p
, p_drop
, aux_long
- (p_drop
- (char *)lpDrop
) ))
1160 p_drop
+= strlen( p_drop
) + 1;
1164 PostMessageA( hWnd
, WM_DROPFILES
, (WPARAM
)hDrop
, 0L );
1169 if( p_data
) XFree(p_data
);
1170 wine_tsx11_unlock();
1173 /**********************************************************************
1176 * drop items are separated by \n
1177 * each item is prefixed by its mime type
1179 * event->data.l[3], event->data.l[4] contains drop x,y position
1181 static void EVENT_DropURLs( HWND hWnd
, XClientMessageEvent
*event
)
1183 struct x11drv_win_data
*win_data
;
1184 unsigned long data_length
;
1185 unsigned long aux_long
, drop_len
= 0;
1186 unsigned char *p_data
= NULL
; /* property data */
1187 char *p_drop
= NULL
;
1199 if (!(GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return;
1202 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
1203 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
1204 AnyPropertyType
, &u
.atom_aux
, &u
.i
,
1205 &data_length
, &aux_long
, &p_data
);
1206 wine_tsx11_unlock();
1208 WARN("property too large, truncated!\n");
1209 TRACE("urls=%s\n", p_data
);
1211 if( !aux_long
&& p_data
) { /* don't bother if > 64K */
1212 /* calculate length */
1214 next
= strchr(p
, '\n');
1217 if (strncmp(p
,"file:",5) == 0 ) {
1218 INT len
= GetShortPathNameA( p
+5, NULL
, 0 );
1219 if (len
) drop_len
+= len
+ 1;
1224 next
= strchr(p
, '\n');
1230 if( drop_len
&& drop_len
< 65535 ) {
1232 XQueryPointer( event
->display
, root_window
, &u
.w_aux
, &u
.w_aux
,
1233 &x
, &y
, &u
.i
, &u
.i
, &u
.u
);
1234 x
+= virtual_screen_rect
.left
;
1235 y
+= virtual_screen_rect
.top
;
1236 wine_tsx11_unlock();
1238 drop_len
+= sizeof(DROPFILES
) + 1;
1239 hDrop
= GlobalAlloc( GMEM_SHARE
, drop_len
);
1240 lpDrop
= GlobalLock( hDrop
);
1242 if( lpDrop
&& (win_data
= X11DRV_get_win_data( hWnd
)))
1244 lpDrop
->pFiles
= sizeof(DROPFILES
);
1248 ( x
< (win_data
->client_rect
.left
- win_data
->whole_rect
.left
) ||
1249 y
< (win_data
->client_rect
.top
- win_data
->whole_rect
.top
) ||
1250 x
> (win_data
->client_rect
.right
- win_data
->whole_rect
.left
) ||
1251 y
> (win_data
->client_rect
.bottom
- win_data
->whole_rect
.top
) );
1252 lpDrop
->fWide
= FALSE
;
1253 p_drop
= (char*)(lpDrop
+ 1);
1256 /* create message content */
1259 next
= strchr(p
, '\n');
1262 if (strncmp(p
,"file:",5) == 0 ) {
1263 INT len
= GetShortPathNameA( p
+5, p_drop
, 65535 );
1265 TRACE("drop file %s as %s\n", p
+5, p_drop
);
1268 WARN("can't convert file %s to dos name\n", p
+5);
1271 WARN("unknown mime type %s\n", p
);
1276 next
= strchr(p
, '\n');
1283 GlobalUnlock(hDrop
);
1284 PostMessageA( hWnd
, WM_DROPFILES
, (WPARAM
)hDrop
, 0L );
1288 if( p_data
) XFree(p_data
);
1289 wine_tsx11_unlock();
1293 /**********************************************************************
1294 * handle_dnd_protocol
1296 static void handle_dnd_protocol( HWND hwnd
, XClientMessageEvent
*event
)
1299 int root_x
, root_y
, child_x
, child_y
;
1302 /* query window (drag&drop event contains only drag window) */
1304 XQueryPointer( event
->display
, root_window
, &root
, &child
,
1305 &root_x
, &root_y
, &child_x
, &child_y
, &u
);
1306 if (XFindContext( event
->display
, child
, winContext
, (char **)&hwnd
) != 0) hwnd
= 0;
1307 wine_tsx11_unlock();
1309 if (event
->data
.l
[0] == DndFile
|| event
->data
.l
[0] == DndFiles
)
1310 EVENT_DropFromOffiX(hwnd
, event
);
1311 else if (event
->data
.l
[0] == DndURL
)
1312 EVENT_DropURLs(hwnd
, event
);
1316 struct client_message_handler
1318 int atom
; /* protocol atom */
1319 void (*handler
)(HWND
, XClientMessageEvent
*); /* corresponding handler function */
1322 static const struct client_message_handler client_messages
[] =
1324 { XATOM_WM_PROTOCOLS
, handle_wm_protocols
},
1325 { XATOM_DndProtocol
, handle_dnd_protocol
},
1326 { XATOM_XdndEnter
, X11DRV_XDND_EnterEvent
},
1327 { XATOM_XdndPosition
, X11DRV_XDND_PositionEvent
},
1328 { XATOM_XdndDrop
, X11DRV_XDND_DropEvent
},
1329 { XATOM_XdndLeave
, X11DRV_XDND_LeaveEvent
}
1333 /**********************************************************************
1334 * X11DRV_ClientMessage
1336 static void X11DRV_ClientMessage( HWND hwnd
, XEvent
*xev
)
1338 XClientMessageEvent
*event
= &xev
->xclient
;
1343 if (event
->format
!= 32)
1345 WARN( "Don't know how to handle format %d\n", event
->format
);
1349 for (i
= 0; i
< sizeof(client_messages
)/sizeof(client_messages
[0]); i
++)
1351 if (event
->message_type
== X11DRV_Atoms
[client_messages
[i
].atom
- FIRST_XATOM
])
1353 client_messages
[i
].handler( hwnd
, event
);
1357 TRACE( "no handler found for %ld\n", event
->message_type
);
1361 /***********************************************************************
1362 * X11DRV_SendInput (X11DRV.@)
1364 UINT CDECL
X11DRV_SendInput( UINT count
, LPINPUT inputs
, int size
)
1368 for (i
= 0; i
< count
; i
++, inputs
++)
1370 switch(inputs
->type
)
1373 X11DRV_send_mouse_input( 0, inputs
->u
.mi
.dwFlags
, inputs
->u
.mi
.dx
, inputs
->u
.mi
.dy
,
1374 inputs
->u
.mi
.mouseData
, inputs
->u
.mi
.time
,
1375 inputs
->u
.mi
.dwExtraInfo
, LLMHF_INJECTED
);
1377 case INPUT_KEYBOARD
:
1378 X11DRV_send_keyboard_input( inputs
->u
.ki
.wVk
, inputs
->u
.ki
.wScan
, inputs
->u
.ki
.dwFlags
,
1379 inputs
->u
.ki
.time
, inputs
->u
.ki
.dwExtraInfo
, LLKHF_INJECTED
);
1381 case INPUT_HARDWARE
:
1382 FIXME( "INPUT_HARDWARE not supported\n" );