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>
35 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
36 #include <X11/extensions/XInput2.h>
50 /* avoid conflict with field names in included win32 headers */
52 #include "shlobj.h" /* DROPFILES */
55 #include "wine/server.h"
56 #include "wine/debug.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(event
);
60 extern BOOL ximInComposeMode
;
62 #define DndNotDnd -1 /* OffiX drag&drop */
74 #define DndURL 128 /* KDE drag&drop */
76 #define XEMBED_EMBEDDED_NOTIFY 0
77 #define XEMBED_WINDOW_ACTIVATE 1
78 #define XEMBED_WINDOW_DEACTIVATE 2
79 #define XEMBED_REQUEST_FOCUS 3
80 #define XEMBED_FOCUS_IN 4
81 #define XEMBED_FOCUS_OUT 5
82 #define XEMBED_FOCUS_NEXT 6
83 #define XEMBED_FOCUS_PREV 7
84 #define XEMBED_MODALITY_ON 10
85 #define XEMBED_MODALITY_OFF 11
86 #define XEMBED_REGISTER_ACCELERATOR 12
87 #define XEMBED_UNREGISTER_ACCELERATOR 13
88 #define XEMBED_ACTIVATE_ACCELERATOR 14
90 Bool (*pXGetEventData
)( Display
*display
, XEvent
/*XGenericEventCookie*/ *event
) = NULL
;
91 void (*pXFreeEventData
)( Display
*display
, XEvent
/*XGenericEventCookie*/ *event
) = NULL
;
94 static void X11DRV_FocusIn( HWND hwnd
, XEvent
*event
);
95 static void X11DRV_FocusOut( HWND hwnd
, XEvent
*event
);
96 static void X11DRV_Expose( HWND hwnd
, XEvent
*event
);
97 static void X11DRV_MapNotify( HWND hwnd
, XEvent
*event
);
98 static void X11DRV_UnmapNotify( HWND hwnd
, XEvent
*event
);
99 static void X11DRV_ReparentNotify( HWND hwnd
, XEvent
*event
);
100 static void X11DRV_ConfigureNotify( HWND hwnd
, XEvent
*event
);
101 static void X11DRV_PropertyNotify( HWND hwnd
, XEvent
*event
);
102 static void X11DRV_ClientMessage( HWND hwnd
, XEvent
*event
);
103 static void X11DRV_GravityNotify( HWND hwnd
, XEvent
*event
);
105 #define MAX_EVENT_HANDLERS 128
107 static x11drv_event_handler handlers
[MAX_EVENT_HANDLERS
] =
109 NULL
, /* 0 reserved */
110 NULL
, /* 1 reserved */
111 X11DRV_KeyEvent
, /* 2 KeyPress */
112 X11DRV_KeyEvent
, /* 3 KeyRelease */
113 X11DRV_ButtonPress
, /* 4 ButtonPress */
114 X11DRV_ButtonRelease
, /* 5 ButtonRelease */
115 X11DRV_MotionNotify
, /* 6 MotionNotify */
116 X11DRV_EnterNotify
, /* 7 EnterNotify */
117 NULL
, /* 8 LeaveNotify */
118 X11DRV_FocusIn
, /* 9 FocusIn */
119 X11DRV_FocusOut
, /* 10 FocusOut */
120 X11DRV_KeymapNotify
, /* 11 KeymapNotify */
121 X11DRV_Expose
, /* 12 Expose */
122 NULL
, /* 13 GraphicsExpose */
123 NULL
, /* 14 NoExpose */
124 NULL
, /* 15 VisibilityNotify */
125 NULL
, /* 16 CreateNotify */
126 X11DRV_DestroyNotify
, /* 17 DestroyNotify */
127 X11DRV_UnmapNotify
, /* 18 UnmapNotify */
128 X11DRV_MapNotify
, /* 19 MapNotify */
129 NULL
, /* 20 MapRequest */
130 X11DRV_ReparentNotify
, /* 21 ReparentNotify */
131 X11DRV_ConfigureNotify
, /* 22 ConfigureNotify */
132 NULL
, /* 23 ConfigureRequest */
133 X11DRV_GravityNotify
, /* 24 GravityNotify */
134 NULL
, /* 25 ResizeRequest */
135 NULL
, /* 26 CirculateNotify */
136 NULL
, /* 27 CirculateRequest */
137 X11DRV_PropertyNotify
, /* 28 PropertyNotify */
138 X11DRV_SelectionClear
, /* 29 SelectionClear */
139 X11DRV_SelectionRequest
, /* 30 SelectionRequest */
140 NULL
, /* 31 SelectionNotify */
141 NULL
, /* 32 ColormapNotify */
142 X11DRV_ClientMessage
, /* 33 ClientMessage */
143 X11DRV_MappingNotify
, /* 34 MappingNotify */
144 X11DRV_GenericEvent
/* 35 GenericEvent */
147 static const char * event_names
[MAX_EVENT_HANDLERS
] =
149 NULL
, NULL
, "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
150 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
151 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
152 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
153 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify", "ResizeRequest",
154 "CirculateNotify", "CirculateRequest", "PropertyNotify", "SelectionClear", "SelectionRequest",
155 "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify", "GenericEvent"
158 int xinput2_opcode
= 0;
160 /* return the name of an X event */
161 static const char *dbgstr_event( int type
)
163 if (type
< MAX_EVENT_HANDLERS
&& event_names
[type
]) return event_names
[type
];
164 return wine_dbg_sprintf( "Unknown event %d", type
);
167 static inline void get_event_data( XEvent
*event
)
169 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
170 if (event
->xany
.type
!= GenericEvent
) return;
171 if (!pXGetEventData
|| !pXGetEventData( event
->xany
.display
, event
)) event
->xcookie
.data
= NULL
;
175 static inline void free_event_data( XEvent
*event
)
177 #if defined(GenericEvent) && defined(HAVE_XEVENT_XCOOKIE)
178 if (event
->xany
.type
!= GenericEvent
) return;
179 if (event
->xcookie
.data
) pXFreeEventData( event
->xany
.display
, event
);
183 /***********************************************************************
184 * xembed_request_focus
186 static void xembed_request_focus( Display
*display
, Window window
, DWORD timestamp
)
190 xev
.xclient
.type
= ClientMessage
;
191 xev
.xclient
.window
= window
;
192 xev
.xclient
.message_type
= x11drv_atom(_XEMBED
);
193 xev
.xclient
.serial
= 0;
194 xev
.xclient
.display
= display
;
195 xev
.xclient
.send_event
= True
;
196 xev
.xclient
.format
= 32;
198 xev
.xclient
.data
.l
[0] = timestamp
;
199 xev
.xclient
.data
.l
[1] = XEMBED_REQUEST_FOCUS
;
200 xev
.xclient
.data
.l
[2] = 0;
201 xev
.xclient
.data
.l
[3] = 0;
202 xev
.xclient
.data
.l
[4] = 0;
204 XSendEvent(display
, window
, False
, NoEventMask
, &xev
);
208 /***********************************************************************
209 * X11DRV_register_event_handler
211 * Register a handler for a given event type.
212 * If already registered, overwrite the previous handler.
214 void X11DRV_register_event_handler( int type
, x11drv_event_handler handler
, const char *name
)
216 assert( type
< MAX_EVENT_HANDLERS
);
217 assert( !handlers
[type
] || handlers
[type
] == handler
);
218 handlers
[type
] = handler
;
219 event_names
[type
] = name
;
220 TRACE("registered handler %p for event %d %s\n", handler
, type
, debugstr_a(name
) );
224 /***********************************************************************
227 static Bool
filter_event( Display
*display
, XEvent
*event
, char *arg
)
229 ULONG_PTR mask
= (ULONG_PTR
)arg
;
231 if ((mask
& QS_ALLINPUT
) == QS_ALLINPUT
) return 1;
239 return (mask
& (QS_KEY
|QS_HOTKEY
)) != 0;
242 return (mask
& QS_MOUSEBUTTON
) != 0;
249 return (mask
& QS_MOUSEMOVE
) != 0;
251 return (mask
& QS_PAINT
) != 0;
256 case ConfigureNotify
:
259 return (mask
& QS_POSTMESSAGE
) != 0;
261 return (mask
& QS_SENDMESSAGE
) != 0;
266 enum event_merge_action
268 MERGE_DISCARD
, /* discard the old event */
269 MERGE_HANDLE
, /* handle the old event */
270 MERGE_KEEP
, /* keep the old event for future merging */
271 MERGE_IGNORE
/* ignore the new event, keep the old one */
274 /***********************************************************************
275 * merge_raw_motion_events
277 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
278 static enum event_merge_action
merge_raw_motion_events( XIRawEvent
*prev
, XIRawEvent
*next
)
283 if (!prev
->valuators
.mask_len
) return MERGE_HANDLE
;
284 if (!next
->valuators
.mask_len
) return MERGE_HANDLE
;
286 mask
= prev
->valuators
.mask
[0] | next
->valuators
.mask
[0];
287 if (mask
== next
->valuators
.mask
[0]) /* keep next */
289 for (i
= j
= k
= 0; i
< 8; i
++)
291 if (XIMaskIsSet( prev
->valuators
.mask
, i
))
292 next
->valuators
.values
[j
] += prev
->valuators
.values
[k
++];
293 if (XIMaskIsSet( next
->valuators
.mask
, i
)) j
++;
295 TRACE( "merging duplicate GenericEvent\n" );
296 return MERGE_DISCARD
;
298 if (mask
== prev
->valuators
.mask
[0]) /* keep prev */
300 for (i
= j
= k
= 0; i
< 8; i
++)
302 if (XIMaskIsSet( next
->valuators
.mask
, i
))
303 prev
->valuators
.values
[j
] += next
->valuators
.values
[k
++];
304 if (XIMaskIsSet( prev
->valuators
.mask
, i
)) j
++;
306 TRACE( "merging duplicate GenericEvent\n" );
309 /* can't merge events with disjoint masks */
314 /***********************************************************************
317 * Try to merge 2 consecutive events.
319 static enum event_merge_action
merge_events( XEvent
*prev
, XEvent
*next
)
323 case ConfigureNotify
:
326 case ConfigureNotify
:
327 if (prev
->xany
.window
== next
->xany
.window
)
329 TRACE( "discarding duplicate ConfigureNotify for window %lx\n", prev
->xany
.window
);
330 return MERGE_DISCARD
;
342 if (prev
->xany
.window
== next
->xany
.window
)
344 TRACE( "discarding duplicate MotionNotify for window %lx\n", prev
->xany
.window
);
345 return MERGE_DISCARD
;
348 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
350 if (next
->xcookie
.extension
!= xinput2_opcode
) break;
351 if (next
->xcookie
.evtype
!= XI_RawMotion
) break;
352 if (x11drv_thread_data()->warp_serial
) break;
357 if (prev
->xcookie
.extension
!= xinput2_opcode
) break;
358 if (prev
->xcookie
.evtype
!= XI_RawMotion
) break;
362 if (next
->xcookie
.extension
!= xinput2_opcode
) break;
363 if (next
->xcookie
.evtype
!= XI_RawMotion
) break;
364 if (x11drv_thread_data()->warp_serial
) break;
365 return merge_raw_motion_events( prev
->xcookie
.data
, next
->xcookie
.data
);
374 /***********************************************************************
377 static inline void call_event_handler( Display
*display
, XEvent
*event
)
381 struct x11drv_thread_data
*thread_data
;
383 if (!handlers
[event
->type
])
385 TRACE( "%s for win %lx, ignoring\n", dbgstr_event( event
->type
), event
->xany
.window
);
386 return; /* no handler, ignore it */
389 if (XFindContext( display
, event
->xany
.window
, winContext
, (char **)&hwnd
) != 0)
390 hwnd
= 0; /* not for a registered window */
391 if (!hwnd
&& event
->xany
.window
== root_window
) hwnd
= GetDesktopWindow();
393 TRACE( "%lu %s for hwnd/window %p/%lx\n",
394 event
->xany
.serial
, dbgstr_event( event
->type
), hwnd
, event
->xany
.window
);
395 thread_data
= x11drv_thread_data();
396 prev
= thread_data
->current_event
;
397 thread_data
->current_event
= event
;
398 handlers
[event
->type
]( hwnd
, event
);
399 thread_data
->current_event
= prev
;
403 /***********************************************************************
406 static int process_events( Display
*display
, Bool (*filter
)(Display
*, XEvent
*,XPointer
), ULONG_PTR arg
)
408 XEvent event
, prev_event
;
410 enum event_merge_action action
= MERGE_DISCARD
;
413 while (XCheckIfEvent( display
, &event
, filter
, (char *)arg
))
416 if (XFilterEvent( &event
, None
))
419 * SCIM on linux filters key events strangely. It does not filter the
420 * KeyPress events for these keys however it does filter the
421 * KeyRelease events. This causes wine to become very confused as
422 * to the keyboard state.
424 * We need to let those KeyRelease events be processed so that the
425 * keyboard state is correct.
427 if (event
.type
== KeyRelease
)
430 XKeyEvent
*keyevent
= &event
.xkey
;
432 XLookupString(keyevent
, NULL
, 0, &keysym
, NULL
);
433 if (!(keysym
== XK_Shift_L
||
434 keysym
== XK_Shift_R
||
435 keysym
== XK_Control_L
||
436 keysym
== XK_Control_R
||
437 keysym
== XK_Alt_R
||
438 keysym
== XK_Alt_L
||
439 keysym
== XK_Meta_R
||
440 keysym
== XK_Meta_L
))
441 continue; /* not a key we care about, ignore it */
444 continue; /* filtered, ignore it */
446 get_event_data( &event
);
447 if (prev_event
.type
) action
= merge_events( &prev_event
, &event
);
450 case MERGE_HANDLE
: /* handle prev, keep new */
451 call_event_handler( display
, &prev_event
);
453 case MERGE_DISCARD
: /* discard prev, keep new */
454 free_event_data( &prev_event
);
457 case MERGE_KEEP
: /* handle new, keep prev for future merging */
458 call_event_handler( display
, &event
);
460 case MERGE_IGNORE
: /* ignore new, keep prev for future merging */
461 free_event_data( &event
);
465 if (prev_event
.type
) call_event_handler( display
, &prev_event
);
466 free_event_data( &prev_event
);
467 XFlush( gdi_display
);
468 if (count
) TRACE( "processed %d events\n", count
);
473 /***********************************************************************
474 * MsgWaitForMultipleObjectsEx (X11DRV.@)
476 DWORD CDECL
X11DRV_MsgWaitForMultipleObjectsEx( DWORD count
, const HANDLE
*handles
,
477 DWORD timeout
, DWORD mask
, DWORD flags
)
480 struct x11drv_thread_data
*data
= TlsGetValue( thread_data_tls_index
);
484 if (!count
&& !timeout
) return WAIT_TIMEOUT
;
485 return WaitForMultipleObjectsEx( count
, handles
, flags
& MWMO_WAITALL
,
486 timeout
, flags
& MWMO_ALERTABLE
);
489 if (data
->current_event
) mask
= 0; /* don't process nested events */
491 if (process_events( data
->display
, filter_event
, mask
)) ret
= count
- 1;
492 else if (count
|| timeout
)
494 ret
= WaitForMultipleObjectsEx( count
, handles
, flags
& MWMO_WAITALL
,
495 timeout
, flags
& MWMO_ALERTABLE
);
496 if (ret
== count
- 1) process_events( data
->display
, filter_event
, mask
);
498 else ret
= WAIT_TIMEOUT
;
503 /***********************************************************************
504 * EVENT_x11_time_to_win32_time
506 * Make our timer and the X timer line up as best we can
507 * Pass 0 to retrieve the current adjustment value (times -1)
509 DWORD
EVENT_x11_time_to_win32_time(Time time
)
511 static DWORD adjust
= 0;
512 DWORD now
= GetTickCount();
515 if (! adjust
&& time
!= 0)
522 /* If we got an event in the 'future', then our clock is clearly wrong.
523 If we got it more than 10000 ms in the future, then it's most likely
524 that the clock has wrapped. */
527 if (ret
> now
&& ((ret
- now
) < 10000) && time
!= 0)
538 /*******************************************************************
539 * can_activate_window
541 * Check if we can activate the specified window.
543 static inline BOOL
can_activate_window( HWND hwnd
)
545 LONG style
= GetWindowLongW( hwnd
, GWL_STYLE
);
548 if (!(style
& WS_VISIBLE
)) return FALSE
;
549 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return FALSE
;
550 if (style
& WS_MINIMIZE
) return FALSE
;
551 if (GetWindowLongW( hwnd
, GWL_EXSTYLE
) & WS_EX_NOACTIVATE
) return FALSE
;
552 if (hwnd
== GetDesktopWindow()) return FALSE
;
553 if (GetWindowRect( hwnd
, &rect
) && IsRectEmpty( &rect
)) return FALSE
;
554 return !(style
& WS_DISABLED
);
558 /**********************************************************************
561 * Try to force focus for embedded or non-managed windows.
563 static void set_input_focus( struct x11drv_win_data
*data
)
565 XWindowChanges changes
;
568 if (!data
->whole_window
) return;
570 if (EVENT_x11_time_to_win32_time(0))
571 /* ICCCM says don't use CurrentTime, so try to use last message time if possible */
572 /* FIXME: this is not entirely correct */
573 timestamp
= GetMessageTime() - EVENT_x11_time_to_win32_time(0);
575 timestamp
= CurrentTime
;
577 /* Set X focus and install colormap */
578 changes
.stack_mode
= Above
;
579 XConfigureWindow( data
->display
, data
->whole_window
, CWStackMode
, &changes
);
582 xembed_request_focus( data
->display
, data
->embedder
, timestamp
);
584 XSetInputFocus( data
->display
, data
->whole_window
, RevertToParent
, timestamp
);
588 /**********************************************************************
591 static void set_focus( Display
*display
, HWND hwnd
, Time time
)
595 GUITHREADINFO threadinfo
;
597 TRACE( "setting foreground window to %p\n", hwnd
);
598 SetForegroundWindow( hwnd
);
600 threadinfo
.cbSize
= sizeof(threadinfo
);
601 GetGUIThreadInfo(0, &threadinfo
);
602 focus
= threadinfo
.hwndFocus
;
603 if (!focus
) focus
= threadinfo
.hwndActive
;
604 if (focus
) focus
= GetAncestor( focus
, GA_ROOT
);
605 win
= X11DRV_get_whole_window(focus
);
609 TRACE( "setting focus to %p (%lx) time=%ld\n", focus
, win
, time
);
610 XSetInputFocus( display
, win
, RevertToParent
, time
);
615 /**********************************************************************
616 * handle_manager_message
618 static void handle_manager_message( HWND hwnd
, XClientMessageEvent
*event
)
620 if (hwnd
!= GetDesktopWindow()) return;
621 if (systray_atom
&& event
->data
.l
[1] == systray_atom
)
622 change_systray_owner( event
->display
, event
->data
.l
[2] );
626 /**********************************************************************
627 * handle_wm_protocols
629 static void handle_wm_protocols( HWND hwnd
, XClientMessageEvent
*event
)
631 Atom protocol
= (Atom
)event
->data
.l
[0];
632 Time event_time
= (Time
)event
->data
.l
[1];
634 if (!protocol
) return;
636 if (protocol
== x11drv_atom(WM_DELETE_WINDOW
))
638 update_user_time( event_time
);
640 if (hwnd
== GetDesktopWindow())
642 /* The desktop window does not have a close button that we can
643 * pretend to click. Therefore, we simply send it a close command. */
644 SendMessageW(hwnd
, WM_SYSCOMMAND
, SC_CLOSE
, 0);
648 /* Ignore the delete window request if the window has been disabled
649 * and we are in managed mode. This is to disallow applications from
650 * being closed by the window manager while in a modal state.
652 if (IsWindowEnabled(hwnd
))
656 if (GetClassLongW(hwnd
, GCL_STYLE
) & CS_NOCLOSE
) return;
657 hSysMenu
= GetSystemMenu(hwnd
, FALSE
);
660 UINT state
= GetMenuState(hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
);
661 if (state
== 0xFFFFFFFF || (state
& (MF_DISABLED
| MF_GRAYED
)))
664 if (GetActiveWindow() != hwnd
)
666 LRESULT ma
= SendMessageW( hwnd
, WM_MOUSEACTIVATE
,
667 (WPARAM
)GetAncestor( hwnd
, GA_ROOT
),
668 MAKELPARAM( HTCLOSE
, WM_NCLBUTTONDOWN
) );
671 case MA_NOACTIVATEANDEAT
:
672 case MA_ACTIVATEANDEAT
:
678 SetActiveWindow(hwnd
);
681 WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma
);
686 PostMessageW( hwnd
, WM_SYSCOMMAND
, SC_CLOSE
, 0 );
689 else if (protocol
== x11drv_atom(WM_TAKE_FOCUS
))
691 HWND last_focus
= x11drv_thread_data()->last_focus
;
693 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
694 hwnd
, IsWindowEnabled(hwnd
), IsWindowVisible(hwnd
), GetWindowLongW(hwnd
, GWL_STYLE
),
695 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus
);
697 if (can_activate_window(hwnd
))
699 /* simulate a mouse click on the caption to find out
700 * whether the window wants to be activated */
701 LRESULT ma
= SendMessageW( hwnd
, WM_MOUSEACTIVATE
,
702 (WPARAM
)GetAncestor( hwnd
, GA_ROOT
),
703 MAKELONG(HTCAPTION
,WM_LBUTTONDOWN
) );
704 if (ma
!= MA_NOACTIVATEANDEAT
&& ma
!= MA_NOACTIVATE
)
706 set_focus( event
->display
, hwnd
, event_time
);
710 else if (hwnd
== GetDesktopWindow())
712 hwnd
= GetForegroundWindow();
713 if (!hwnd
) hwnd
= last_focus
;
714 if (!hwnd
) hwnd
= GetDesktopWindow();
715 set_focus( event
->display
, hwnd
, event_time
);
718 /* try to find some other window to give the focus to */
720 if (hwnd
) hwnd
= GetAncestor( hwnd
, GA_ROOT
);
721 if (!hwnd
) hwnd
= GetActiveWindow();
722 if (!hwnd
) hwnd
= last_focus
;
723 if (hwnd
&& can_activate_window(hwnd
)) set_focus( event
->display
, hwnd
, event_time
);
725 else if (protocol
== x11drv_atom(_NET_WM_PING
))
727 XClientMessageEvent xev
;
730 TRACE("NET_WM Ping\n");
731 xev
.window
= DefaultRootWindow(xev
.display
);
732 XSendEvent(xev
.display
, xev
.window
, False
, SubstructureRedirectMask
| SubstructureNotifyMask
, (XEvent
*)&xev
);
737 static const char * const focus_details
[] =
743 "NotifyNonlinearVirtual",
749 /**********************************************************************
752 static void X11DRV_FocusIn( HWND hwnd
, XEvent
*xev
)
754 XFocusChangeEvent
*event
= &xev
->xfocus
;
759 TRACE( "win %p xwin %lx detail=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
] );
761 if (event
->detail
== NotifyPointer
) return;
762 if (hwnd
== GetDesktopWindow()) return;
764 if ((xic
= X11DRV_get_ic( hwnd
))) XSetICFocus( xic
);
767 if (hwnd
== GetForegroundWindow()) clip_fullscreen_window( hwnd
, FALSE
);
771 if (!can_activate_window(hwnd
))
773 HWND hwnd
= GetFocus();
774 if (hwnd
) hwnd
= GetAncestor( hwnd
, GA_ROOT
);
775 if (!hwnd
) hwnd
= GetActiveWindow();
776 if (!hwnd
) hwnd
= x11drv_thread_data()->last_focus
;
777 if (hwnd
&& can_activate_window(hwnd
)) set_focus( event
->display
, hwnd
, CurrentTime
);
779 else SetForegroundWindow( hwnd
);
782 /**********************************************************************
785 static void focus_out( Display
*display
, HWND hwnd
)
792 if (ximInComposeMode
) return;
794 x11drv_thread_data()->last_focus
= hwnd
;
795 if ((xic
= X11DRV_get_ic( hwnd
))) XUnsetICFocus( xic
);
797 if (root_window
!= DefaultRootWindow(display
))
799 if (hwnd
== GetDesktopWindow()) reset_clipping_window();
802 if (hwnd
!= GetForegroundWindow()) return;
803 SendMessageW( hwnd
, WM_CANCELMODE
, 0, 0 );
805 /* don't reset the foreground window, if the window which is
806 getting the focus is a Wine window */
808 XGetInputFocus( display
, &focus_win
, &revert
);
811 if (XFindContext( display
, focus_win
, winContext
, (char **)&hwnd_tmp
) != 0)
817 /* Abey : 6-Oct-99. Check again if the focus out window is the
818 Foreground window, because in most cases the messages sent
819 above must have already changed the foreground window, in which
820 case we don't have to change the foreground window to 0 */
821 if (hwnd
== GetForegroundWindow())
823 TRACE( "lost focus, setting fg to desktop\n" );
824 SetForegroundWindow( GetDesktopWindow() );
829 /**********************************************************************
832 * Note: only top-level windows get FocusOut events.
834 static void X11DRV_FocusOut( HWND hwnd
, XEvent
*xev
)
836 XFocusChangeEvent
*event
= &xev
->xfocus
;
838 TRACE( "win %p xwin %lx detail=%s\n", hwnd
, event
->window
, focus_details
[event
->detail
] );
840 if (event
->detail
== NotifyPointer
)
842 if (!hwnd
&& event
->window
== x11drv_thread_data()->clip_window
) reset_clipping_window();
846 focus_out( event
->display
, hwnd
);
850 /***********************************************************************
853 static void X11DRV_Expose( HWND hwnd
, XEvent
*xev
)
855 XExposeEvent
*event
= &xev
->xexpose
;
858 struct x11drv_win_data
*data
;
859 HRGN surface_region
= 0;
860 UINT flags
= RDW_INVALIDATE
| RDW_ERASE
| RDW_FRAME
| RDW_ALLCHILDREN
;
862 TRACE( "win %p (%lx) %d,%d %dx%d\n",
863 hwnd
, event
->window
, event
->x
, event
->y
, event
->width
, event
->height
);
865 if (event
->window
!= root_window
)
870 else pos
= root_to_virtual_screen( event
->x
, event
->y
);
872 if (!(data
= get_win_data( hwnd
))) return;
876 rect
.right
= pos
.x
+ event
->width
;
877 rect
.bottom
= pos
.y
+ event
->height
;
879 if (event
->window
!= data
->client_window
)
883 surface_region
= expose_surface( data
->surface
, &rect
);
884 if (!surface_region
) flags
= 0;
885 else OffsetRgn( surface_region
, data
->whole_rect
.left
- data
->client_rect
.left
,
886 data
->whole_rect
.top
- data
->client_rect
.top
);
888 if (data
->vis
.visualid
!= default_visual
.visualid
)
889 data
->surface
->funcs
->flush( data
->surface
);
891 OffsetRect( &rect
, data
->whole_rect
.left
- data
->client_rect
.left
,
892 data
->whole_rect
.top
- data
->client_rect
.top
);
895 if (event
->window
!= root_window
)
897 if (GetWindowLongW( data
->hwnd
, GWL_EXSTYLE
) & WS_EX_LAYOUTRTL
)
898 mirror_rect( &data
->client_rect
, &rect
);
900 SERVER_START_REQ( update_window_zorder
)
902 req
->window
= wine_server_user_handle( hwnd
);
903 req
->rect
.left
= rect
.left
;
904 req
->rect
.top
= rect
.top
;
905 req
->rect
.right
= rect
.right
;
906 req
->rect
.bottom
= rect
.bottom
;
907 wine_server_call( req
);
911 else flags
&= ~RDW_ALLCHILDREN
;
913 release_win_data( data
);
915 if (flags
) RedrawWindow( hwnd
, &rect
, surface_region
, flags
);
916 if (surface_region
) DeleteObject( surface_region
);
920 /**********************************************************************
923 static void X11DRV_MapNotify( HWND hwnd
, XEvent
*event
)
925 struct x11drv_win_data
*data
;
927 if (event
->xany
.window
== x11drv_thread_data()->clip_window
)
929 clipping_cursor
= TRUE
;
932 if (!(data
= get_win_data( hwnd
))) return;
934 if (!data
->managed
&& !data
->embedded
&& data
->mapped
)
936 HWND hwndFocus
= GetFocus();
937 if (hwndFocus
&& IsChild( hwnd
, hwndFocus
))
938 set_input_focus( data
);
940 release_win_data( data
);
944 /**********************************************************************
947 static void X11DRV_UnmapNotify( HWND hwnd
, XEvent
*event
)
949 if (event
->xany
.window
== x11drv_thread_data()->clip_window
)
950 clipping_cursor
= FALSE
;
954 /***********************************************************************
957 static void reparent_notify( Display
*display
, HWND hwnd
, Window xparent
, int x
, int y
)
959 HWND parent
, old_parent
;
962 style
= GetWindowLongW( hwnd
, GWL_STYLE
);
963 if (xparent
== root_window
)
965 parent
= GetDesktopWindow();
966 style
= (style
& ~WS_CHILD
) | WS_POPUP
;
970 if (!(parent
= create_foreign_window( display
, xparent
))) return;
971 style
= (style
& ~WS_POPUP
) | WS_CHILD
;
974 ShowWindow( hwnd
, SW_HIDE
);
975 old_parent
= SetParent( hwnd
, parent
);
976 SetWindowLongW( hwnd
, GWL_STYLE
, style
);
977 SetWindowPos( hwnd
, HWND_TOP
, x
, y
, 0, 0,
978 SWP_NOACTIVATE
| SWP_NOSIZE
| SWP_NOCOPYBITS
|
979 ((style
& WS_VISIBLE
) ? SWP_SHOWWINDOW
: 0) );
981 /* make old parent destroy itself if it no longer has children */
982 if (old_parent
!= GetDesktopWindow()) PostMessageW( old_parent
, WM_CLOSE
, 0, 0 );
986 /***********************************************************************
987 * X11DRV_ReparentNotify
989 static void X11DRV_ReparentNotify( HWND hwnd
, XEvent
*xev
)
991 XReparentEvent
*event
= &xev
->xreparent
;
992 struct x11drv_win_data
*data
;
994 if (!(data
= get_win_data( hwnd
))) return;
998 release_win_data( data
);
1002 if (data
->whole_window
)
1004 if (event
->parent
== root_window
)
1006 TRACE( "%p/%lx reparented to root\n", hwnd
, data
->whole_window
);
1008 release_win_data( data
);
1009 SendMessageW( hwnd
, WM_CLOSE
, 0, 0 );
1012 data
->embedder
= event
->parent
;
1015 TRACE( "%p/%lx reparented to %lx\n", hwnd
, data
->whole_window
, event
->parent
);
1016 release_win_data( data
);
1018 reparent_notify( event
->display
, hwnd
, event
->parent
, event
->x
, event
->y
);
1022 /***********************************************************************
1023 * X11DRV_ConfigureNotify
1025 void X11DRV_ConfigureNotify( HWND hwnd
, XEvent
*xev
)
1027 XConfigureEvent
*event
= &xev
->xconfigure
;
1028 struct x11drv_win_data
*data
;
1034 int cx
, cy
, x
= event
->x
, y
= event
->y
;
1038 if (!(data
= get_win_data( hwnd
))) return;
1039 if (!data
->mapped
|| data
->iconic
) goto done
;
1040 if (data
->whole_window
&& !data
->managed
) goto done
;
1041 /* ignore synthetic events on foreign windows */
1042 if (event
->send_event
&& !data
->whole_window
) goto done
;
1043 if (data
->configure_serial
&& (long)(data
->configure_serial
- event
->serial
) > 0)
1045 TRACE( "win %p/%lx event %d,%d,%dx%d ignoring old serial %lu/%lu\n",
1046 hwnd
, data
->whole_window
, event
->x
, event
->y
, event
->width
, event
->height
,
1047 event
->serial
, data
->configure_serial
);
1053 parent
= GetAncestor( hwnd
, GA_PARENT
);
1054 root_coords
= event
->send_event
; /* synthetic events are always in root coords */
1056 if (!root_coords
&& parent
== GetDesktopWindow()) /* normal event, map coordinates to the root */
1059 XTranslateCoordinates( event
->display
, event
->window
, root_window
,
1060 0, 0, &x
, &y
, &child
);
1069 else pos
= root_to_virtual_screen( x
, y
);
1073 rect
.right
= pos
.x
+ event
->width
;
1074 rect
.bottom
= pos
.y
+ event
->height
;
1075 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
1076 hwnd
, data
->whole_window
, rect
.left
, rect
.top
, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
,
1077 event
->x
, event
->y
, event
->width
, event
->height
);
1079 X11DRV_X_to_window_rect( data
, &rect
);
1080 if (root_coords
) MapWindowPoints( 0, parent
, (POINT
*)&rect
, 2 );
1082 /* Compare what has changed */
1086 cx
= rect
.right
- rect
.left
;
1087 cy
= rect
.bottom
- rect
.top
;
1088 flags
= SWP_NOACTIVATE
| SWP_NOZORDER
;
1090 if (!data
->whole_window
) flags
|= SWP_NOCOPYBITS
; /* we can't copy bits of foreign windows */
1092 if (data
->window_rect
.left
== x
&& data
->window_rect
.top
== y
) flags
|= SWP_NOMOVE
;
1094 TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
1095 hwnd
, data
->window_rect
.left
, data
->window_rect
.top
, x
, y
);
1097 if ((data
->window_rect
.right
- data
->window_rect
.left
== cx
&&
1098 data
->window_rect
.bottom
- data
->window_rect
.top
== cy
) ||
1099 IsRectEmpty( &data
->window_rect
))
1100 flags
|= SWP_NOSIZE
;
1102 TRACE( "%p resizing from (%dx%d) to (%dx%d)\n",
1103 hwnd
, data
->window_rect
.right
- data
->window_rect
.left
,
1104 data
->window_rect
.bottom
- data
->window_rect
.top
, cx
, cy
);
1106 style
= GetWindowLongW( data
->hwnd
, GWL_STYLE
);
1107 if ((style
& WS_CAPTION
) == WS_CAPTION
)
1109 read_net_wm_states( event
->display
, data
);
1110 if ((data
->net_wm_state
& (1 << NET_WM_STATE_MAXIMIZED
)))
1112 if (!(style
& WS_MAXIMIZE
))
1114 TRACE( "win %p/%lx is maximized\n", data
->hwnd
, data
->whole_window
);
1115 release_win_data( data
);
1116 SendMessageW( data
->hwnd
, WM_SYSCOMMAND
, SC_MAXIMIZE
, 0 );
1120 else if (style
& WS_MAXIMIZE
)
1122 TRACE( "window %p/%lx is no longer maximized\n", data
->hwnd
, data
->whole_window
);
1123 release_win_data( data
);
1124 SendMessageW( data
->hwnd
, WM_SYSCOMMAND
, SC_RESTORE
, 0 );
1129 if ((flags
& (SWP_NOSIZE
| SWP_NOMOVE
)) != (SWP_NOSIZE
| SWP_NOMOVE
))
1131 release_win_data( data
);
1132 SetWindowPos( hwnd
, 0, x
, y
, cx
, cy
, flags
);
1137 release_win_data( data
);
1141 /**********************************************************************
1142 * X11DRV_GravityNotify
1144 static void X11DRV_GravityNotify( HWND hwnd
, XEvent
*xev
)
1146 XGravityEvent
*event
= &xev
->xgravity
;
1147 struct x11drv_win_data
*data
= get_win_data( hwnd
);
1148 RECT rect
, window_rect
;
1152 if (data
->whole_window
) /* only handle this for foreign windows */
1154 release_win_data( data
);
1158 rect
.left
= event
->x
;
1159 rect
.top
= event
->y
;
1160 rect
.right
= rect
.left
+ data
->whole_rect
.right
- data
->whole_rect
.left
;
1161 rect
.bottom
= rect
.top
+ data
->whole_rect
.bottom
- data
->whole_rect
.top
;
1163 TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d)\n",
1164 hwnd
, data
->whole_window
, rect
.left
, rect
.top
, rect
.right
-rect
.left
, rect
.bottom
-rect
.top
,
1165 event
->x
, event
->y
);
1167 X11DRV_X_to_window_rect( data
, &rect
);
1168 window_rect
= data
->window_rect
;
1169 release_win_data( data
);
1171 if (window_rect
.left
!= rect
.left
|| window_rect
.top
!= rect
.top
)
1172 SetWindowPos( hwnd
, 0, rect
.left
, rect
.top
, 0, 0,
1173 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOCOPYBITS
);
1177 /***********************************************************************
1178 * get_window_wm_state
1180 static int get_window_wm_state( Display
*display
, Window window
)
1188 int format
, ret
= -1;
1189 unsigned long count
, remaining
;
1191 if (!XGetWindowProperty( display
, window
, x11drv_atom(WM_STATE
), 0,
1192 sizeof(*state
)/sizeof(CARD32
), False
, x11drv_atom(WM_STATE
),
1193 &type
, &format
, &count
, &remaining
, (unsigned char **)&state
))
1195 if (type
== x11drv_atom(WM_STATE
) && get_property_size( format
, count
) >= sizeof(*state
))
1203 /***********************************************************************
1204 * handle_wm_state_notify
1206 * Handle a PropertyNotify for WM_STATE.
1208 static void handle_wm_state_notify( HWND hwnd
, XPropertyEvent
*event
, BOOL update_window
)
1210 struct x11drv_win_data
*data
= get_win_data( hwnd
);
1215 switch(event
->state
)
1217 case PropertyDelete
:
1218 TRACE( "%p/%lx: WM_STATE deleted from %d\n", data
->hwnd
, data
->whole_window
, data
->wm_state
);
1219 data
->wm_state
= WithdrawnState
;
1221 case PropertyNewValue
:
1223 int old_state
= data
->wm_state
;
1224 int new_state
= get_window_wm_state( event
->display
, data
->whole_window
);
1225 if (new_state
!= -1 && new_state
!= data
->wm_state
)
1227 TRACE( "%p/%lx: new WM_STATE %d from %d\n",
1228 data
->hwnd
, data
->whole_window
, new_state
, old_state
);
1229 data
->wm_state
= new_state
;
1230 /* ignore the initial state transition out of withdrawn state */
1231 /* metacity does Withdrawn->NormalState->IconicState when mapping an iconic window */
1232 if (!old_state
) goto done
;
1238 if (!update_window
|| !data
->managed
|| !data
->mapped
) goto done
;
1240 style
= GetWindowLongW( data
->hwnd
, GWL_STYLE
);
1242 if (data
->iconic
&& data
->wm_state
== NormalState
) /* restore window */
1244 data
->iconic
= FALSE
;
1245 read_net_wm_states( event
->display
, data
);
1246 if ((style
& WS_CAPTION
) == WS_CAPTION
&& (data
->net_wm_state
& (1 << NET_WM_STATE_MAXIMIZED
)))
1248 if ((style
& WS_MAXIMIZEBOX
) && !(style
& WS_DISABLED
))
1250 TRACE( "restoring to max %p/%lx\n", data
->hwnd
, data
->whole_window
);
1251 release_win_data( data
);
1252 SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_MAXIMIZE
, 0 );
1255 TRACE( "not restoring to max win %p/%lx style %08x\n", data
->hwnd
, data
->whole_window
, style
);
1259 if (style
& (WS_MINIMIZE
| WS_MAXIMIZE
))
1261 TRACE( "restoring win %p/%lx\n", data
->hwnd
, data
->whole_window
);
1262 release_win_data( data
);
1263 SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_RESTORE
, 0 );
1266 TRACE( "not restoring win %p/%lx style %08x\n", data
->hwnd
, data
->whole_window
, style
);
1269 else if (!data
->iconic
&& data
->wm_state
== IconicState
)
1271 data
->iconic
= TRUE
;
1272 if ((style
& WS_MINIMIZEBOX
) && !(style
& WS_DISABLED
))
1274 TRACE( "minimizing win %p/%lx\n", data
->hwnd
, data
->whole_window
);
1275 release_win_data( data
);
1276 SendMessageW( hwnd
, WM_SYSCOMMAND
, SC_MINIMIZE
, 0 );
1279 TRACE( "not minimizing win %p/%lx style %08x\n", data
->hwnd
, data
->whole_window
, style
);
1282 release_win_data( data
);
1286 /***********************************************************************
1287 * X11DRV_PropertyNotify
1289 static void X11DRV_PropertyNotify( HWND hwnd
, XEvent
*xev
)
1291 XPropertyEvent
*event
= &xev
->xproperty
;
1294 if (event
->atom
== x11drv_atom(WM_STATE
)) handle_wm_state_notify( hwnd
, event
, TRUE
);
1298 /* event filter to wait for a WM_STATE change notification on a window */
1299 static Bool
is_wm_state_notify( Display
*display
, XEvent
*event
, XPointer arg
)
1301 if (event
->xany
.window
!= (Window
)arg
) return 0;
1302 return (event
->type
== DestroyNotify
||
1303 (event
->type
== PropertyNotify
&& event
->xproperty
.atom
== x11drv_atom(WM_STATE
)));
1306 /***********************************************************************
1307 * wait_for_withdrawn_state
1309 void wait_for_withdrawn_state( HWND hwnd
, BOOL set
)
1311 Display
*display
= thread_display();
1312 struct x11drv_win_data
*data
;
1313 DWORD end
= GetTickCount() + 2000;
1315 TRACE( "waiting for window %p to become %swithdrawn\n", hwnd
, set
? "" : "not " );
1323 if (!(data
= get_win_data( hwnd
))) break;
1324 if (!data
->managed
|| data
->embedded
|| data
->display
!= display
) break;
1325 if (!(window
= data
->whole_window
)) break;
1326 if (!data
->mapped
== !set
)
1328 TRACE( "window %p/%lx now %smapped\n", hwnd
, window
, data
->mapped
? "" : "un" );
1331 if ((data
->wm_state
== WithdrawnState
) != !set
)
1333 TRACE( "window %p/%lx state now %d\n", hwnd
, window
, data
->wm_state
);
1336 release_win_data( data
);
1338 while (XCheckIfEvent( display
, &event
, is_wm_state_notify
, (char *)window
))
1341 if (XFilterEvent( &event
, None
)) continue; /* filtered, ignore it */
1342 if (event
.type
== DestroyNotify
) call_event_handler( display
, &event
);
1343 else handle_wm_state_notify( hwnd
, &event
.xproperty
, FALSE
);
1349 int timeout
= end
- GetTickCount();
1351 pfd
.fd
= ConnectionNumber(display
);
1352 pfd
.events
= POLLIN
;
1353 if (timeout
<= 0 || poll( &pfd
, 1, timeout
) != 1)
1355 FIXME( "window %p/%lx wait timed out\n", hwnd
, window
);
1360 release_win_data( data
);
1364 /*****************************************************************
1365 * SetFocus (X11DRV.@)
1369 void CDECL
X11DRV_SetFocus( HWND hwnd
)
1371 struct x11drv_win_data
*data
;
1377 if (!(data
= get_win_data( hwnd
))) return;
1378 if (data
->embedded
) break;
1379 parent
= GetAncestor( hwnd
, GA_PARENT
);
1380 if (!parent
|| parent
== GetDesktopWindow()) break;
1381 release_win_data( data
);
1384 if (!data
->managed
|| data
->embedder
) set_input_focus( data
);
1385 release_win_data( data
);
1389 static HWND
find_drop_window( HWND hQueryWnd
, LPPOINT lpPt
)
1393 if (!IsWindowEnabled(hQueryWnd
)) return 0;
1395 GetWindowRect(hQueryWnd
, &tempRect
);
1397 if(!PtInRect(&tempRect
, *lpPt
)) return 0;
1399 if (!IsIconic( hQueryWnd
))
1402 ScreenToClient( hQueryWnd
, &pt
);
1403 GetClientRect( hQueryWnd
, &tempRect
);
1405 if (PtInRect( &tempRect
, pt
))
1407 HWND ret
= ChildWindowFromPointEx( hQueryWnd
, pt
, CWP_SKIPINVISIBLE
|CWP_SKIPDISABLED
);
1408 if (ret
&& ret
!= hQueryWnd
)
1410 ret
= find_drop_window( ret
, lpPt
);
1411 if (ret
) return ret
;
1416 if(!(GetWindowLongA( hQueryWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return 0;
1418 ScreenToClient(hQueryWnd
, lpPt
);
1423 /**********************************************************************
1424 * EVENT_DropFromOffix
1426 * don't know if it still works (last Changelog is from 96/11/04)
1428 static void EVENT_DropFromOffiX( HWND hWnd
, XClientMessageEvent
*event
)
1430 struct x11drv_win_data
*data
;
1432 unsigned long data_length
;
1433 unsigned long aux_long
;
1434 unsigned char* p_data
= NULL
;
1436 int x
, y
, cx
, cy
, dummy
;
1437 Window win
, w_aux_root
, w_aux_child
;
1439 if (!(data
= get_win_data( hWnd
))) return;
1440 cx
= data
->whole_rect
.right
- data
->whole_rect
.left
;
1441 cy
= data
->whole_rect
.bottom
- data
->whole_rect
.top
;
1442 win
= data
->whole_window
;
1443 release_win_data( data
);
1445 XQueryPointer( event
->display
, win
, &w_aux_root
, &w_aux_child
,
1446 &x
, &y
, &dummy
, &dummy
, (unsigned int*)&aux_long
);
1447 pt
= root_to_virtual_screen( x
, y
);
1449 /* find out drop point and drop window */
1450 if (pt
.x
< 0 || pt
.y
< 0 || pt
.x
> cx
|| pt
.y
> cy
)
1452 if (!(GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return;
1457 if (!find_drop_window( hWnd
, &pt
)) return;
1460 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
1461 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
1462 AnyPropertyType
, &atom_aux
, &dummy
,
1463 &data_length
, &aux_long
, &p_data
);
1465 if( !aux_long
&& p_data
) /* don't bother if > 64K */
1467 char *p
= (char *)p_data
;
1471 while( *p
) /* calculate buffer size */
1473 INT len
= GetShortPathNameA( p
, NULL
, 0 );
1474 if (len
) aux_long
+= len
+ 1;
1477 if( aux_long
&& aux_long
< 65535 )
1482 aux_long
+= sizeof(DROPFILES
) + 1;
1483 hDrop
= GlobalAlloc( GMEM_SHARE
, aux_long
);
1484 lpDrop
= GlobalLock( hDrop
);
1488 lpDrop
->pFiles
= sizeof(DROPFILES
);
1490 lpDrop
->fNC
= FALSE
;
1491 lpDrop
->fWide
= FALSE
;
1492 p_drop
= (char *)(lpDrop
+ 1);
1496 if (GetShortPathNameA( p
, p_drop
, aux_long
- (p_drop
- (char *)lpDrop
) ))
1497 p_drop
+= strlen( p_drop
) + 1;
1501 PostMessageA( hWnd
, WM_DROPFILES
, (WPARAM
)hDrop
, 0L );
1505 if( p_data
) XFree(p_data
);
1508 /**********************************************************************
1511 * drop items are separated by \n
1512 * each item is prefixed by its mime type
1514 * event->data.l[3], event->data.l[4] contains drop x,y position
1516 static void EVENT_DropURLs( HWND hWnd
, XClientMessageEvent
*event
)
1518 struct x11drv_win_data
*win_data
;
1519 unsigned long data_length
;
1520 unsigned long aux_long
, drop_len
= 0;
1521 unsigned char *p_data
= NULL
; /* property data */
1522 char *p_drop
= NULL
;
1535 if (!(GetWindowLongW( hWnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
)) return;
1537 XGetWindowProperty( event
->display
, DefaultRootWindow(event
->display
),
1538 x11drv_atom(DndSelection
), 0, 65535, FALSE
,
1539 AnyPropertyType
, &u
.atom_aux
, &u
.i
,
1540 &data_length
, &aux_long
, &p_data
);
1542 WARN("property too large, truncated!\n");
1543 TRACE("urls=%s\n", p_data
);
1545 if( !aux_long
&& p_data
) { /* don't bother if > 64K */
1546 /* calculate length */
1548 next
= strchr(p
, '\n');
1551 if (strncmp(p
,"file:",5) == 0 ) {
1552 INT len
= GetShortPathNameA( p
+5, NULL
, 0 );
1553 if (len
) drop_len
+= len
+ 1;
1558 next
= strchr(p
, '\n');
1564 if( drop_len
&& drop_len
< 65535 ) {
1565 XQueryPointer( event
->display
, root_window
, &u
.w_aux
, &u
.w_aux
,
1566 &x
, &y
, &u
.i
, &u
.i
, &u
.u
);
1567 pos
= root_to_virtual_screen( x
, y
);
1569 drop_len
+= sizeof(DROPFILES
) + 1;
1570 hDrop
= GlobalAlloc( GMEM_SHARE
, drop_len
);
1571 lpDrop
= GlobalLock( hDrop
);
1573 if( lpDrop
&& (win_data
= get_win_data( hWnd
)))
1575 lpDrop
->pFiles
= sizeof(DROPFILES
);
1578 (pos
.x
< (win_data
->client_rect
.left
- win_data
->whole_rect
.left
) ||
1579 pos
.y
< (win_data
->client_rect
.top
- win_data
->whole_rect
.top
) ||
1580 pos
.x
> (win_data
->client_rect
.right
- win_data
->whole_rect
.left
) ||
1581 pos
.y
> (win_data
->client_rect
.bottom
- win_data
->whole_rect
.top
) );
1582 lpDrop
->fWide
= FALSE
;
1583 p_drop
= (char*)(lpDrop
+ 1);
1584 release_win_data( win_data
);
1587 /* create message content */
1590 next
= strchr(p
, '\n');
1593 if (strncmp(p
,"file:",5) == 0 ) {
1594 INT len
= GetShortPathNameA( p
+5, p_drop
, 65535 );
1596 TRACE("drop file %s as %s\n", p
+5, p_drop
);
1599 WARN("can't convert file %s to dos name\n", p
+5);
1602 WARN("unknown mime type %s\n", p
);
1607 next
= strchr(p
, '\n');
1614 GlobalUnlock(hDrop
);
1615 PostMessageA( hWnd
, WM_DROPFILES
, (WPARAM
)hDrop
, 0L );
1618 if( p_data
) XFree(p_data
);
1623 /**********************************************************************
1624 * handle_xembed_protocol
1626 static void handle_xembed_protocol( HWND hwnd
, XClientMessageEvent
*event
)
1628 switch (event
->data
.l
[1])
1630 case XEMBED_EMBEDDED_NOTIFY
:
1632 struct x11drv_win_data
*data
= get_win_data( hwnd
);
1635 TRACE( "win %p/%lx XEMBED_EMBEDDED_NOTIFY owner %lx\n", hwnd
, event
->window
, event
->data
.l
[3] );
1636 data
->embedder
= event
->data
.l
[3];
1638 /* window has been marked as embedded before (e.g. systray) */
1639 if (data
->embedded
|| !data
->embedder
/* broken QX11EmbedContainer implementation */)
1641 release_win_data( data
);
1645 make_window_embedded( data
);
1646 release_win_data( data
);
1647 reparent_notify( event
->display
, hwnd
, event
->data
.l
[3], 0, 0 );
1651 case XEMBED_WINDOW_DEACTIVATE
:
1652 TRACE( "win %p/%lx XEMBED_WINDOW_DEACTIVATE message\n", hwnd
, event
->window
);
1653 focus_out( event
->display
, GetAncestor( hwnd
, GA_ROOT
) );
1656 case XEMBED_FOCUS_OUT
:
1657 TRACE( "win %p/%lx XEMBED_FOCUS_OUT message\n", hwnd
, event
->window
);
1658 focus_out( event
->display
, GetAncestor( hwnd
, GA_ROOT
) );
1661 case XEMBED_MODALITY_ON
:
1662 TRACE( "win %p/%lx XEMBED_MODALITY_ON message\n", hwnd
, event
->window
);
1663 EnableWindow( hwnd
, FALSE
);
1666 case XEMBED_MODALITY_OFF
:
1667 TRACE( "win %p/%lx XEMBED_MODALITY_OFF message\n", hwnd
, event
->window
);
1668 EnableWindow( hwnd
, TRUE
);
1672 TRACE( "win %p/%lx XEMBED message %lu(%lu)\n",
1673 hwnd
, event
->window
, event
->data
.l
[1], event
->data
.l
[2] );
1679 /**********************************************************************
1680 * handle_dnd_protocol
1682 static void handle_dnd_protocol( HWND hwnd
, XClientMessageEvent
*event
)
1685 int root_x
, root_y
, child_x
, child_y
;
1688 /* query window (drag&drop event contains only drag window) */
1689 XQueryPointer( event
->display
, root_window
, &root
, &child
,
1690 &root_x
, &root_y
, &child_x
, &child_y
, &u
);
1691 if (XFindContext( event
->display
, child
, winContext
, (char **)&hwnd
) != 0) hwnd
= 0;
1693 if (event
->data
.l
[0] == DndFile
|| event
->data
.l
[0] == DndFiles
)
1694 EVENT_DropFromOffiX(hwnd
, event
);
1695 else if (event
->data
.l
[0] == DndURL
)
1696 EVENT_DropURLs(hwnd
, event
);
1700 struct client_message_handler
1702 int atom
; /* protocol atom */
1703 void (*handler
)(HWND
, XClientMessageEvent
*); /* corresponding handler function */
1706 static const struct client_message_handler client_messages
[] =
1708 { XATOM_MANAGER
, handle_manager_message
},
1709 { XATOM_WM_PROTOCOLS
, handle_wm_protocols
},
1710 { XATOM__XEMBED
, handle_xembed_protocol
},
1711 { XATOM_DndProtocol
, handle_dnd_protocol
},
1712 { XATOM_XdndEnter
, X11DRV_XDND_EnterEvent
},
1713 { XATOM_XdndPosition
, X11DRV_XDND_PositionEvent
},
1714 { XATOM_XdndDrop
, X11DRV_XDND_DropEvent
},
1715 { XATOM_XdndLeave
, X11DRV_XDND_LeaveEvent
}
1719 /**********************************************************************
1720 * X11DRV_ClientMessage
1722 static void X11DRV_ClientMessage( HWND hwnd
, XEvent
*xev
)
1724 XClientMessageEvent
*event
= &xev
->xclient
;
1729 if (event
->format
!= 32)
1731 WARN( "Don't know how to handle format %d\n", event
->format
);
1735 for (i
= 0; i
< sizeof(client_messages
)/sizeof(client_messages
[0]); i
++)
1737 if (event
->message_type
== X11DRV_Atoms
[client_messages
[i
].atom
- FIRST_XATOM
])
1739 client_messages
[i
].handler( hwnd
, event
);
1743 TRACE( "no handler found for %ld\n", event
->message_type
);