GetItemA/W on header controls should handle message even if index is
[wine] / dlls / x11drv / event.c
1 /*
2  * X11 event driver
3  *
4  * Copyright 1993 Alexandre Julliard
5  *           1999 Noel Borthwick
6  *
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.
11  *
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.
16  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #define COM_NO_WINDOWS_H
23 #include "config.h"
24
25 #include <X11/Xatom.h>
26 #include <X11/keysym.h>
27 #include <X11/Xlib.h>
28 #include <X11/Xresource.h>
29 #include <X11/Xutil.h>
30 #ifdef HAVE_LIBXXF86DGA2
31 #include <X11/extensions/xf86dga.h>
32 #endif
33
34 #include <assert.h>
35 #include <stdarg.h>
36 #include <string.h>
37 #include "wine/winuser16.h"
38 #include "windef.h"
39 #include "winbase.h"
40 #include "winuser.h"
41 #include "wingdi.h"
42 #include "shlobj.h"  /* DROPFILES */
43
44 #include "win.h"
45 #include "winpos.h"
46 #include "winreg.h"
47 #include "x11drv.h"
48 #include "shellapi.h"
49 #include "wine/debug.h"
50
51 WINE_DEFAULT_DEBUG_CHANNEL(event);
52 WINE_DECLARE_DEBUG_CHANNEL(clipboard);
53
54 /* X context to associate a hwnd to an X window */
55 extern XContext winContext;
56
57 extern BOOL ximInComposeMode;
58
59 #define DndNotDnd       -1    /* OffiX drag&drop */
60 #define DndUnknown      0
61 #define DndRawData      1
62 #define DndFile         2
63 #define DndFiles        3
64 #define DndText         4
65 #define DndDir          5
66 #define DndLink         6
67 #define DndExe          7
68
69 #define DndEND          8
70
71 #define DndURL          128   /* KDE drag&drop */
72
73 static const char * const event_names[] =
74 {
75   "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
76   "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
77   "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
78   "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
79   "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
80   "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
81   "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
82   "ClientMessage", "MappingNotify"
83 };
84
85
86 static void EVENT_ProcessEvent( XEvent *event );
87
88   /* Event handlers */
89 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event );
90 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event );
91 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple );
92 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event);
93 static void EVENT_PropertyNotify( XPropertyEvent *event );
94 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event );
95
96 extern void X11DRV_ButtonPress( HWND hwnd, XButtonEvent *event );
97 extern void X11DRV_ButtonRelease( HWND hwnd, XButtonEvent *event );
98 extern void X11DRV_MotionNotify( HWND hwnd, XMotionEvent *event );
99 extern void X11DRV_EnterNotify( HWND hwnd, XCrossingEvent *event );
100 extern void X11DRV_KeyEvent( HWND hwnd, XKeyEvent *event );
101 extern void X11DRV_KeymapNotify( HWND hwnd, XKeymapEvent *event );
102 extern void X11DRV_Expose( HWND hwnd, XExposeEvent *event );
103 extern void X11DRV_MapNotify( HWND hwnd, XMapEvent *event );
104 extern void X11DRV_UnmapNotify( HWND hwnd, XUnmapEvent *event );
105 extern void X11DRV_ConfigureNotify( HWND hwnd, XConfigureEvent *event );
106 extern void X11DRV_MappingNotify( XMappingEvent *event );
107
108 #ifdef HAVE_LIBXXF86DGA2
109 static int DGAMotionEventType;
110 static int DGAButtonPressEventType;
111 static int DGAButtonReleaseEventType;
112 static int DGAKeyPressEventType;
113 static int DGAKeyReleaseEventType;
114
115 static BOOL DGAUsed = FALSE;
116 static HWND DGAhwnd = 0;
117
118 extern void X11DRV_DGAMotionEvent( HWND hwnd, XDGAMotionEvent *event );
119 extern void X11DRV_DGAButtonPressEvent( HWND hwnd, XDGAButtonEvent *event );
120 extern void X11DRV_DGAButtonReleaseEvent( HWND hwnd, XDGAButtonEvent *event );
121 #endif
122
123 /* Static used for the current input method */
124 static INPUT_TYPE current_input_type = X11DRV_INPUT_ABSOLUTE;
125 static BOOL in_transition = FALSE; /* This is not used as for today */
126
127
128 /***********************************************************************
129  *           process_events
130  */
131 static int process_events( struct x11drv_thread_data *data )
132 {
133     XEvent event;
134     int count = 0;
135
136     wine_tsx11_lock();
137     while ( XPending( data->display ) )
138     {
139         Bool ignore;
140
141         XNextEvent( data->display, &event );
142         ignore = XFilterEvent( &event, None );
143         wine_tsx11_unlock();
144         if (!ignore) EVENT_ProcessEvent( &event );
145         count++;
146         wine_tsx11_lock();
147     }
148     wine_tsx11_unlock();
149     return count;
150 }
151
152
153 /***********************************************************************
154  *           MsgWaitForMultipleObjectsEx   (X11DRV.@)
155  */
156 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
157                                           DWORD timeout, DWORD mask, DWORD flags )
158 {
159     HANDLE new_handles[MAXIMUM_WAIT_OBJECTS+1];  /* FIXME! */
160     DWORD i, ret;
161     struct x11drv_thread_data *data = NtCurrentTeb()->driver_data;
162
163     if (!data || data->process_event_count)
164         return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
165                                          timeout, flags & MWMO_ALERTABLE );
166
167     /* check whether only server queue handle was passed in */
168     if (count < 2) flags &= ~MWMO_WAITALL;
169
170     for (i = 0; i < count; i++) new_handles[i] = handles[i];
171     new_handles[count] = data->display_fd;
172
173     wine_tsx11_lock();
174     XFlush( gdi_display );
175     XFlush( data->display );
176     wine_tsx11_unlock();
177
178     data->process_event_count++;
179     if (process_events( data )) ret = count;
180     else
181     {
182         ret = WaitForMultipleObjectsEx( count+1, new_handles, flags & MWMO_WAITALL,
183                                         timeout, flags & MWMO_ALERTABLE );
184         if (ret == count) process_events( data );
185     }
186     data->process_event_count--;
187     return ret;
188 }
189
190
191 /***********************************************************************
192  *           EVENT_ProcessEvent
193  *
194  * Process an X event.
195  */
196 static void EVENT_ProcessEvent( XEvent *event )
197 {
198   HWND hWnd;
199   Display *display = event->xany.display;
200
201   TRACE( "called.\n" );
202
203   switch (event->type)
204   {
205     case SelectionNotify: /* all of these should be caught by XCheckTypedWindowEvent() */
206          FIXME("Got SelectionNotify - must not happen!\n");
207          /* fall through */
208
209       /* We get all these because of StructureNotifyMask.
210          This check is placed here to avoid getting error messages below,
211          as X might send some of these even for windows that have already
212          been deleted ... */
213     case CirculateNotify:
214     case CreateNotify:
215     case DestroyNotify:
216     case GravityNotify:
217     case ReparentNotify:
218       return;
219   }
220
221 #ifdef HAVE_LIBXXF86DGA2
222   if (DGAUsed) {
223     if (event->type == DGAMotionEventType) {
224       TRACE("DGAMotionEvent received.\n");
225       X11DRV_DGAMotionEvent( DGAhwnd, (XDGAMotionEvent *)event );
226       return;
227     }
228     if (event->type == DGAButtonPressEventType) {
229       TRACE("DGAButtonPressEvent received.\n");
230       X11DRV_DGAButtonPressEvent( DGAhwnd, (XDGAButtonEvent *)event );
231       return;
232     }
233     if (event->type == DGAButtonReleaseEventType) {
234       TRACE("DGAButtonReleaseEvent received.\n");
235       X11DRV_DGAButtonReleaseEvent( DGAhwnd, (XDGAButtonEvent *)event );
236       return;
237     }
238     if ((event->type == DGAKeyPressEventType) ||
239         (event->type == DGAKeyReleaseEventType)) {
240       /* Fill a XKeyEvent to send to EVENT_Key */
241       XKeyEvent ke;
242       XDGAKeyEvent *evt = (XDGAKeyEvent *) event;
243
244       TRACE("DGAKeyPress/ReleaseEvent received.\n");
245
246       if (evt->type == DGAKeyReleaseEventType)
247         ke.type = KeyRelease;
248       else
249         ke.type = KeyPress;
250       ke.serial = evt->serial;
251       ke.send_event = FALSE;
252       ke.display = evt->display;
253       ke.window = 0;
254       ke.root = 0;
255       ke.subwindow = 0;
256       ke.time = evt->time;
257       ke.x = -1;
258       ke.y = -1;
259       ke.x_root = -1;
260       ke.y_root = -1;
261       ke.state = evt->state;
262       ke.keycode = evt->keycode;
263       ke.same_screen = TRUE;
264       X11DRV_KeyEvent( 0, &ke );
265       return;
266     }
267   }
268 #endif
269
270   wine_tsx11_lock();
271   if (XFindContext( display, event->xany.window, winContext, (char **)&hWnd ) != 0)
272       hWnd = 0;  /* Not for a registered window */
273   wine_tsx11_unlock();
274   if (!hWnd && event->xany.window == root_window) hWnd = GetDesktopWindow();
275
276   if (!hWnd && event->type != PropertyNotify &&
277       event->type != MappingNotify && event->type != KeymapNotify)
278       WARN( "Got event %s for unknown Window %08lx\n",
279             event_names[event->type], event->xany.window );
280   else if (event->type <= MappingNotify)
281       TRACE("Got event %s for hwnd/window %p/%lx, GetFocus()=%p\n",
282             event_names[event->type], hWnd, event->xany.window, GetFocus() );
283   else
284       TRACE("Got extension event for hwnd/window %p/%lx, GetFocus()=%p\n",
285             hWnd, event->xany.window, GetFocus() );
286
287   if (X11DRV_ProcessTabletEvent(hWnd, event))
288   {
289         TRACE("Return: filtered by tablet\n");
290         return;
291   }
292
293   switch(event->type)
294     {
295     case KeyPress:
296     case KeyRelease:
297       /* FIXME: should generate a motion event if event point is different from current pos */
298       X11DRV_KeyEvent( hWnd, (XKeyEvent*)event );
299       break;
300
301     case ButtonPress:
302       X11DRV_ButtonPress( hWnd, (XButtonEvent*)event );
303       break;
304
305     case ButtonRelease:
306       X11DRV_ButtonRelease( hWnd, (XButtonEvent*)event );
307       break;
308
309     case MotionNotify:
310       X11DRV_MotionNotify( hWnd, (XMotionEvent*)event );
311       break;
312
313     case EnterNotify:
314       X11DRV_EnterNotify( hWnd, (XCrossingEvent*)event );
315       break;
316
317     case FocusIn:
318       EVENT_FocusIn( hWnd, (XFocusChangeEvent*)event );
319       break;
320
321     case FocusOut:
322       EVENT_FocusOut( hWnd, (XFocusChangeEvent*)event );
323       break;
324
325     case Expose:
326       X11DRV_Expose( hWnd, &event->xexpose );
327       break;
328
329     case ConfigureNotify:
330       if (!hWnd) return;
331       X11DRV_ConfigureNotify( hWnd, &event->xconfigure );
332       break;
333
334     case SelectionRequest:
335       if (!hWnd) return;
336       EVENT_SelectionRequest( hWnd, (XSelectionRequestEvent *)event, FALSE );
337       break;
338
339     case SelectionClear:
340       if (!hWnd) return;
341       EVENT_SelectionClear( hWnd, (XSelectionClearEvent*) event );
342       break;
343
344     case PropertyNotify:
345       EVENT_PropertyNotify( (XPropertyEvent *)event );
346       break;
347
348     case ClientMessage:
349       if (!hWnd) return;
350       EVENT_ClientMessage( hWnd, (XClientMessageEvent *) event );
351       break;
352
353     case NoExpose:
354       break;
355
356     case MapNotify:
357       X11DRV_MapNotify( hWnd, (XMapEvent *)event );
358       break;
359
360     case UnmapNotify:
361       X11DRV_UnmapNotify( hWnd, (XUnmapEvent *)event );
362       break;
363
364     case KeymapNotify:
365       X11DRV_KeymapNotify( hWnd, (XKeymapEvent *)event );
366       break;
367
368     case MappingNotify:
369       X11DRV_MappingNotify( (XMappingEvent *) event );
370       break;
371
372     default:
373       WARN("Unprocessed event %s for hwnd %p\n", event_names[event->type], hWnd );
374       break;
375     }
376     TRACE( "returns.\n" );
377 }
378
379
380 /*******************************************************************
381  *         can_activate_window
382  *
383  * Check if we can activate the specified window.
384  */
385 inline static BOOL can_activate_window( HWND hwnd )
386 {
387     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
388     if (!(style & WS_VISIBLE)) return FALSE;
389     if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
390     return !(style & WS_DISABLED);
391 }
392
393
394 /**********************************************************************
395  *              set_focus
396  */
397 static void set_focus( HWND hwnd, Time time )
398 {
399     HWND focus;
400     Window win;
401
402     TRACE( "setting foreground window to %p\n", hwnd );
403     SetForegroundWindow( hwnd );
404
405     focus = GetFocus();
406     if (focus) focus = GetAncestor( focus, GA_ROOT );
407     win = X11DRV_get_whole_window(focus);
408
409     if (win)
410     {
411         TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
412         wine_tsx11_lock();
413         XSetInputFocus( thread_display(), win, RevertToParent, time );
414         wine_tsx11_unlock();
415     }
416 }
417
418
419 /**********************************************************************
420  *              handle_wm_protocols_message
421  */
422 static void handle_wm_protocols_message( HWND hwnd, XClientMessageEvent *event )
423 {
424     Atom protocol = (Atom)event->data.l[0];
425
426     if (!protocol) return;
427
428     if (protocol == x11drv_atom(WM_DELETE_WINDOW))
429     {
430         /* Ignore the delete window request if the window has been disabled
431          * and we are in managed mode. This is to disallow applications from
432          * being closed by the window manager while in a modal state.
433          */
434         if (IsWindowEnabled(hwnd)) PostMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
435     }
436     else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
437     {
438         Time event_time = (Time)event->data.l[1];
439         HWND last_focus = x11drv_thread_data()->last_focus;
440
441         TRACE( "got take focus msg for %p, enabled=%d, focus=%p, active=%p, fg=%p, last=%p\n",
442                hwnd, IsWindowEnabled(hwnd), GetFocus(), GetActiveWindow(),
443                GetForegroundWindow(), last_focus );
444
445         if (can_activate_window(hwnd))
446         {
447             /* simulate a mouse click on the caption to find out
448              * whether the window wants to be activated */
449             LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
450                                        (WPARAM)GetAncestor( hwnd, GA_ROOT ),
451                                        MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
452             if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE) set_focus( hwnd, event_time );
453             else TRACE( "not setting focus to %p (%lx), ma=%ld\n", hwnd, event->window, ma );
454         }
455         else
456         {
457             hwnd = GetFocus();
458             if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
459             if (!hwnd) hwnd = GetActiveWindow();
460             if (!hwnd) hwnd = last_focus;
461             if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, event_time );
462         }
463     }
464     else if (protocol == x11drv_atom(_NET_WM_PING))
465     {
466       XClientMessageEvent xev;
467       xev = *event;
468       
469       TRACE("NET_WM Ping\n");
470       xev.window = DefaultRootWindow(xev.display);
471       XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
472       /* this line is semi-stolen from gtk2 */
473       TRACE("NET_WM Pong\n");
474     }
475 }
476
477
478 static const char * const focus_details[] =
479 {
480     "NotifyAncestor",
481     "NotifyVirtual",
482     "NotifyInferior",
483     "NotifyNonlinear",
484     "NotifyNonlinearVirtual",
485     "NotifyPointer",
486     "NotifyPointerRoot",
487     "NotifyDetailNone"
488 };
489
490 /**********************************************************************
491  *              EVENT_FocusIn
492  */
493 static void EVENT_FocusIn( HWND hwnd, XFocusChangeEvent *event )
494 {
495     XIC xic;
496
497     if (!hwnd) return;
498
499     TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
500
501     if (event->detail == NotifyPointer) return;
502
503     if ((xic = X11DRV_get_ic( hwnd )))
504     {
505         wine_tsx11_lock();
506         XSetICFocus( xic );
507         wine_tsx11_unlock();
508     }
509     if (use_take_focus) return;  /* ignore FocusIn if we are using take focus */
510
511     if (!can_activate_window(hwnd))
512     {
513         HWND hwnd = GetFocus();
514         if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
515         if (!hwnd) hwnd = GetActiveWindow();
516         if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
517         if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
518     }
519     else SetForegroundWindow( hwnd );
520 }
521
522
523 /**********************************************************************
524  *              EVENT_FocusOut
525  *
526  * Note: only top-level windows get FocusOut events.
527  */
528 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event )
529 {
530     HWND hwnd_tmp;
531     Window focus_win;
532     int revert;
533     XIC xic;
534
535     if (!hwnd) return;
536
537     TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
538
539     if (event->detail == NotifyPointer) return;
540     if (ximInComposeMode) return;
541
542     x11drv_thread_data()->last_focus = hwnd;
543     if ((xic = X11DRV_get_ic( hwnd )))
544     {
545         wine_tsx11_lock();
546         XUnsetICFocus( xic );
547         wine_tsx11_unlock();
548     }
549     if (hwnd != GetForegroundWindow()) return;
550     SendMessageA( hwnd, WM_CANCELMODE, 0, 0 );
551
552     /* don't reset the foreground window, if the window which is
553        getting the focus is a Wine window */
554
555     wine_tsx11_lock();
556     XGetInputFocus( thread_display(), &focus_win, &revert );
557     if (focus_win)
558     {
559         if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
560             focus_win = 0;
561     }
562     wine_tsx11_unlock();
563
564     if (!focus_win)
565     {
566         /* Abey : 6-Oct-99. Check again if the focus out window is the
567            Foreground window, because in most cases the messages sent
568            above must have already changed the foreground window, in which
569            case we don't have to change the foreground window to 0 */
570         if (hwnd == GetForegroundWindow())
571         {
572             TRACE( "lost focus, setting fg to 0\n" );
573             SetForegroundWindow( 0 );
574         }
575     }
576 }
577
578
579 /***********************************************************************
580  *           EVENT_SelectionRequest_AddTARGETS
581  *  Utility function for EVENT_SelectionRequest_TARGETS.
582  */
583 static BOOL EVENT_SelectionRequest_AddTARGETS(Atom* targets, unsigned long cTargets, Atom prop)
584 {
585     unsigned int i;
586     BOOL bExists;
587
588     /* Scan through what we have so far to avoid duplicates */
589     for (i = 0, bExists = FALSE; i < cTargets; i++)
590     {
591         if (targets[i] == prop)
592         {
593             bExists = TRUE;
594             break;
595         }
596     }
597
598     if (!bExists)
599         targets[cTargets] = prop;
600
601     return !bExists;
602 }
603
604
605 /***********************************************************************
606  *           EVENT_SelectionRequest_TARGETS
607  *  Service a TARGETS selection request event
608  */
609 static Atom EVENT_SelectionRequest_TARGETS( Display *display, Window requestor,
610                                             Atom target, Atom rprop )
611 {
612     Atom* targets;
613     UINT wFormat;
614     UINT alias;
615     ULONG cTargets;
616     LPWINE_CLIPFORMAT lpFormat;
617
618     /*
619      * Count the number of items we wish to expose as selection targets.
620      * We include the TARGETS item, and property aliases
621      */
622     cTargets = X11DRV_CountClipboardFormats() + 1;
623
624     for (wFormat = 0; (wFormat = X11DRV_EnumClipboardFormats(wFormat));)
625     {
626         lpFormat = X11DRV_CLIPBOARD_LookupFormat(wFormat);
627
628         if (lpFormat)
629         {
630             if (!lpFormat->lpDrvExportFunc)
631                 cTargets--;
632
633             if (X11DRV_CLIPBOARD_LookupPropertyAlias(lpFormat->drvData))
634                 cTargets++;
635         }
636         /* else most likely unregistered format such as CF_PRIVATE or CF_GDIOBJ */
637     }
638
639     TRACE_(clipboard)(" found %ld formats\n", cTargets);
640
641     /* Allocate temp buffer */
642     targets = (Atom*)HeapAlloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
643     if(targets == NULL) 
644         return None;
645
646     /* Create TARGETS property list (First item in list is TARGETS itself) */
647     for (targets[0] = x11drv_atom(TARGETS), cTargets = 1, wFormat = 0;
648           (wFormat = X11DRV_EnumClipboardFormats(wFormat));)
649     {
650         lpFormat = X11DRV_CLIPBOARD_LookupFormat(wFormat);
651
652         if (lpFormat)
653         {
654             if (lpFormat->lpDrvExportFunc)
655             {
656                 if (EVENT_SelectionRequest_AddTARGETS(targets, cTargets, lpFormat->drvData))
657                    cTargets++;
658             }
659
660             /* Check if any alias should be listed */
661             alias = X11DRV_CLIPBOARD_LookupPropertyAlias(lpFormat->drvData);
662             if (alias)
663             {
664                 if (EVENT_SelectionRequest_AddTARGETS(targets, cTargets, alias))
665                    cTargets++;
666             }
667         }
668     }
669
670     wine_tsx11_lock();
671
672     if (TRACE_ON(clipboard))
673     {
674         unsigned int i;
675         for ( i = 0; i < cTargets; i++)
676         {
677             if (targets[i])
678             {
679                 char *itemFmtName = XGetAtomName(display, targets[i]);
680                 TRACE_(clipboard)("\tAtom# %d:  Property %ld Type %s\n", i, targets[i], itemFmtName);
681                 XFree(itemFmtName);
682             }
683         }
684     }
685
686     /* We may want to consider setting the type to xaTargets instead,
687      * in case some apps expect this instead of XA_ATOM */
688     XChangeProperty(display, requestor, rprop, XA_ATOM, 32,
689                     PropModeReplace, (unsigned char *)targets, cTargets);
690     wine_tsx11_unlock();
691
692     HeapFree(GetProcessHeap(), 0, targets);
693
694     return rprop;
695 }
696
697
698 /***********************************************************************
699  *           EVENT_SelectionRequest_MULTIPLE
700  *  Service a MULTIPLE selection request event
701  *  rprop contains a list of (target,property) atom pairs.
702  *  The first atom names a target and the second names a property.
703  *  The effect is as if we have received a sequence of SelectionRequest events
704  *  (one for each atom pair) except that:
705  *  1. We reply with a SelectionNotify only when all the requested conversions
706  *  have been performed.
707  *  2. If we fail to convert the target named by an atom in the MULTIPLE property,
708  *  we replace the atom in the property by None.
709  */
710 static Atom EVENT_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
711 {
712     Display *display = pevent->display;
713     Atom           rprop;
714     Atom           atype=AnyPropertyType;
715     int            aformat;
716     unsigned long  remain;
717     Atom*          targetPropList=NULL;
718     unsigned long  cTargetPropList = 0;
719
720    /* If the specified property is None the requestor is an obsolete client.
721     * We support these by using the specified target atom as the reply property.
722     */
723     rprop = pevent->property;
724     if( rprop == None )
725         rprop = pevent->target;
726     if (!rprop)
727         goto END;
728
729     /* Read the MULTIPLE property contents. This should contain a list of
730      * (target,property) atom pairs.
731      */
732     wine_tsx11_lock();
733     if(XGetWindowProperty(display, pevent->requestor, rprop,
734                             0, 0x3FFF, False, AnyPropertyType, &atype,&aformat,
735                             &cTargetPropList, &remain,
736                             (unsigned char**)&targetPropList) != Success)
737     {
738         wine_tsx11_unlock();
739         TRACE("\tCouldn't read MULTIPLE property\n");
740     }
741     else
742     {
743        TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
744              XGetAtomName(display, atype), aformat, cTargetPropList, remain);
745        wine_tsx11_unlock();
746
747        /*
748         * Make sure we got what we expect.
749         * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
750         * in a MULTIPLE selection request should be of type ATOM_PAIR.
751         * However some X apps(such as XPaint) are not compliant with this and return
752         * a user defined atom in atype when XGetWindowProperty is called.
753         * The data *is* an atom pair but is not denoted as such.
754         */
755        if(aformat == 32 /* atype == xAtomPair */ )
756        {
757           unsigned int i;
758
759           /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
760            * for each (target,property) pair */
761
762           for (i = 0; i < cTargetPropList; i+=2)
763           {
764               XSelectionRequestEvent event;
765
766               if (TRACE_ON(event))
767               {
768                   char *targetName, *propName;
769                   wine_tsx11_lock();
770                   targetName = XGetAtomName(display, targetPropList[i]);
771                   propName = XGetAtomName(display, targetPropList[i+1]);
772                   TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
773                         i/2, targetName, propName);
774                   XFree(targetName);
775                   XFree(propName);
776                   wine_tsx11_unlock();
777               }
778
779               /* We must have a non "None" property to service a MULTIPLE target atom */
780               if ( !targetPropList[i+1] )
781               {
782                   TRACE("\tMULTIPLE(%d): Skipping target with empty property!\n", i);
783                   continue;
784               }
785
786               /* Set up an XSelectionRequestEvent for this (target,property) pair */
787               memcpy( &event, pevent, sizeof(XSelectionRequestEvent) );
788               event.target = targetPropList[i];
789               event.property = targetPropList[i+1];
790
791               /* Fire a SelectionRequest, informing the handler that we are processing
792                * a MULTIPLE selection request event.
793                */
794               EVENT_SelectionRequest( hWnd, &event, TRUE );
795           }
796        }
797
798        /* Free the list of targets/properties */
799        wine_tsx11_lock();
800        XFree(targetPropList);
801        wine_tsx11_unlock();
802     }
803
804 END:
805     return rprop;
806 }
807
808
809 /***********************************************************************
810  *           EVENT_SelectionRequest
811  *  Process an event selection request event.
812  *  The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
813  *  recursively while servicing a "MULTIPLE" selection target.
814  *
815  *  Note: We only receive this event when WINE owns the X selection
816  */
817 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
818 {
819     Display *display = event->display;
820   XSelectionEvent result;
821   Atom            rprop = None;
822   Window          request = event->requestor;
823
824   TRACE_(clipboard)("\n");
825
826   /*
827    * We can only handle the selection request if :
828    * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
829    * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
830    * since this has been already done.
831    */
832   if ( !bIsMultiple )
833   {
834     if (((event->selection != XA_PRIMARY) && (event->selection != x11drv_atom(CLIPBOARD))))
835        goto END;
836   }
837
838   /* If the specified property is None the requestor is an obsolete client.
839    * We support these by using the specified target atom as the reply property.
840    */
841   rprop = event->property;
842   if( rprop == None )
843       rprop = event->target;
844
845   if(event->target == x11drv_atom(TARGETS))  /*  Return a list of all supported targets */
846   {
847       /* TARGETS selection request */
848       rprop = EVENT_SelectionRequest_TARGETS( display, request, event->target, rprop );
849   }
850   else if(event->target == x11drv_atom(MULTIPLE))  /*  rprop contains a list of (target, property) atom pairs */
851   {
852       /* MULTIPLE selection request */
853       rprop = EVENT_SelectionRequest_MULTIPLE( hWnd, event );
854   }
855   else
856   {
857       LPWINE_CLIPFORMAT lpFormat = X11DRV_CLIPBOARD_LookupProperty(event->target);
858
859       if (!lpFormat)
860           lpFormat = X11DRV_CLIPBOARD_LookupAliasProperty(event->target);
861
862       if (lpFormat && lpFormat->lpDrvExportFunc)
863       {
864           LPWINE_CLIPDATA lpData = X11DRV_CLIPBOARD_LookupData(lpFormat->wFormatID);
865
866           if (lpData)
867           {
868               unsigned char* lpClipData;
869               DWORD cBytes;
870               HANDLE hClipData = lpFormat->lpDrvExportFunc(request, event->target,
871                   rprop, lpData, &cBytes);
872
873               if (hClipData && (lpClipData = GlobalLock(hClipData)))
874               {
875                   TRACE_(clipboard)("\tUpdating property %s, %ld bytes\n",
876                       lpFormat->Name, cBytes);
877
878                   wine_tsx11_lock();
879                   XChangeProperty(display, request, rprop, event->target,
880                       8, PropModeReplace, (unsigned char *)lpClipData, cBytes);
881                   wine_tsx11_unlock();
882
883                   GlobalUnlock(hClipData);
884                   GlobalFree(hClipData);
885               }
886           }
887       }
888   }
889
890 END:
891   /* reply to sender
892    * SelectionNotify should be sent only at the end of a MULTIPLE request
893    */
894   if ( !bIsMultiple )
895   {
896     result.type = SelectionNotify;
897     result.display = display;
898     result.requestor = request;
899     result.selection = event->selection;
900     result.property = rprop;
901     result.target = event->target;
902     result.time = event->time;
903     TRACE("Sending SelectionNotify event...\n");
904     wine_tsx11_lock();
905     XSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
906     wine_tsx11_unlock();
907   }
908 }
909
910 /***********************************************************************
911  *           EVENT_SelectionClear
912  */
913 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
914 {
915   if (event->selection == XA_PRIMARY || event->selection == x11drv_atom(CLIPBOARD))
916       X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd, event->time );
917 }
918
919 /***********************************************************************
920  *           EVENT_PropertyNotify
921  *   We use this to release resources like Pixmaps when a selection
922  *   client no longer needs them.
923  */
924 static void EVENT_PropertyNotify( XPropertyEvent *event )
925 {
926   /* Check if we have any resources to free */
927   TRACE("Received PropertyNotify event: \n");
928
929   switch(event->state)
930   {
931     case PropertyDelete:
932     {
933       TRACE("\tPropertyDelete for atom %ld on window %ld\n",
934             event->atom, (long)event->window);
935       break;
936     }
937
938     case PropertyNewValue:
939     {
940       TRACE("\tPropertyNewValue for atom %ld on window %ld\n\n",
941             event->atom, (long)event->window);
942       break;
943     }
944
945     default:
946       break;
947   }
948 }
949
950 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
951 {
952     RECT tempRect;
953
954     if (!IsWindowEnabled(hQueryWnd)) return 0;
955     
956     GetWindowRect(hQueryWnd, &tempRect);
957
958     if(!PtInRect(&tempRect, *lpPt)) return 0;
959
960     if (!IsIconic( hQueryWnd ))
961     {
962         GetClientRect( hQueryWnd, &tempRect );
963         MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
964
965         if (PtInRect( &tempRect, *lpPt))
966         {
967             HWND *list = WIN_ListChildren( hQueryWnd );
968             HWND bResult = 0;
969
970             if (list)
971             {
972                 int i;
973                 
974                 for (i = 0; list[i]; i++)
975                 {
976                     if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
977                     {
978                         GetWindowRect( list[i], &tempRect );
979                         if (PtInRect( &tempRect, *lpPt )) break;
980                     }
981                 }
982                 if (list[i])
983                 {
984                     if (IsWindowEnabled( list[i] ))
985                         bResult = find_drop_window( list[i], lpPt );
986                 }
987                 HeapFree( GetProcessHeap(), 0, list );
988             }
989             if(bResult) return bResult;
990         }
991     }
992
993     if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
994     
995     ScreenToClient(hQueryWnd, lpPt);
996
997     return hQueryWnd;
998 }
999
1000 /**********************************************************************
1001  *           EVENT_DropFromOffix
1002  *
1003  * don't know if it still works (last Changlog is from 96/11/04)
1004  */
1005 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1006 {
1007     unsigned long       data_length;
1008     unsigned long       aux_long;
1009     unsigned char*      p_data = NULL;
1010     union {
1011         Atom    atom_aux;
1012         struct {
1013             int x;
1014             int y;
1015         }       pt_aux;
1016         int     i;
1017     }                   u;
1018     int                 x, y;
1019     BOOL                bAccept;
1020     Window              w_aux_root, w_aux_child;
1021     WND*                pWnd;
1022     HWND                hScope = hWnd;
1023
1024     pWnd = WIN_FindWndPtr(hWnd);
1025
1026     wine_tsx11_lock();
1027     XQueryPointer( event->display, get_whole_window(pWnd), &w_aux_root, &w_aux_child,
1028                    &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
1029                    (unsigned int*)&aux_long);
1030     wine_tsx11_unlock();
1031
1032     /* find out drop point and drop window */
1033     if( x < 0 || y < 0 ||
1034         x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1035         y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1036     {   
1037         bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; 
1038         x = 0;
1039         y = 0; 
1040     }
1041     else
1042     {
1043         POINT   pt = { x, y };
1044         HWND    hwndDrop = find_drop_window( hWnd, &pt );
1045         if (hwndDrop)
1046         {
1047             x = pt.x;
1048             y = pt.y;
1049             hScope = hwndDrop;
1050             bAccept = TRUE;
1051         }
1052         else
1053         {
1054             bAccept = FALSE;
1055         }
1056     }
1057     WIN_ReleaseWndPtr(pWnd);
1058
1059     if (!bAccept) return;
1060
1061     wine_tsx11_lock();
1062     XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1063                         x11drv_atom(DndSelection), 0, 65535, FALSE,
1064                         AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
1065                         &data_length, &aux_long, &p_data);
1066     wine_tsx11_unlock();
1067
1068     if( !aux_long && p_data)  /* don't bother if > 64K */
1069     {
1070         signed char *p = (signed char*) p_data;
1071         char *p_drop;
1072
1073         aux_long = 0;
1074         while( *p )  /* calculate buffer size */
1075         {
1076             p_drop = p;
1077             if((u.i = *p) != -1 )
1078             {
1079                 INT len = GetShortPathNameA( p, NULL, 0 );
1080                 if (len) aux_long += len + 1;
1081                 else *p = -1;
1082             }
1083             p += strlen(p) + 1;
1084         }
1085         if( aux_long && aux_long < 65535 )
1086         {
1087             HDROP                 hDrop;
1088             DROPFILES *lpDrop;
1089
1090             aux_long += sizeof(DROPFILES) + 1;
1091             hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1092             lpDrop = (DROPFILES*)GlobalLock( hDrop );
1093
1094             if( lpDrop )
1095             {
1096                 WND *pDropWnd = WIN_FindWndPtr( hScope );
1097                 lpDrop->pFiles = sizeof(DROPFILES);
1098                 lpDrop->pt.x = x;
1099                 lpDrop->pt.y = y;
1100                 lpDrop->fNC =
1101                     ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left)  ||
1102                       y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top)    ||
1103                       x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1104                       y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1105                 lpDrop->fWide = FALSE;
1106                 WIN_ReleaseWndPtr(pDropWnd);
1107                 p_drop = (char *)(lpDrop + 1);
1108                 p = p_data;
1109                 while(*p)
1110                 {
1111                     if( *p != -1 ) /* use only "good" entries */
1112                     {
1113                         GetShortPathNameA( p, p_drop, 65535 );
1114                         p_drop += strlen( p_drop ) + 1;
1115                     }
1116                     p += strlen(p) + 1;
1117                 }
1118                 *p_drop = '\0';
1119                 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1120             }
1121         }
1122     }
1123     wine_tsx11_lock();
1124     if( p_data ) XFree(p_data);
1125     wine_tsx11_unlock();
1126 }
1127
1128 /**********************************************************************
1129  *           EVENT_DropURLs
1130  *
1131  * drop items are separated by \n
1132  * each item is prefixed by its mime type
1133  *
1134  * event->data.l[3], event->data.l[4] contains drop x,y position
1135  */
1136 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1137 {
1138   unsigned long data_length;
1139   unsigned long aux_long, drop_len = 0;
1140   unsigned char *p_data = NULL; /* property data */
1141   char          *p_drop = NULL;
1142   char          *p, *next;
1143   int           x, y;
1144   DROPFILES *lpDrop;
1145   HDROP hDrop;
1146   union {
1147     Atom        atom_aux;
1148     int         i;
1149     Window      w_aux;
1150   }             u; /* unused */
1151
1152   if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1153
1154   wine_tsx11_lock();
1155   XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1156                       x11drv_atom(DndSelection), 0, 65535, FALSE,
1157                       AnyPropertyType, &u.atom_aux, &u.i,
1158                       &data_length, &aux_long, &p_data);
1159   wine_tsx11_unlock();
1160   if (aux_long)
1161     WARN("property too large, truncated!\n");
1162   TRACE("urls=%s\n", p_data);
1163
1164   if( !aux_long && p_data) {    /* don't bother if > 64K */
1165     /* calculate length */
1166     p = p_data;
1167     next = strchr(p, '\n');
1168     while (p) {
1169       if (next) *next=0;
1170       if (strncmp(p,"file:",5) == 0 ) {
1171         INT len = GetShortPathNameA( p+5, NULL, 0 );
1172         if (len) drop_len += len + 1;
1173       }
1174       if (next) {
1175         *next = '\n';
1176         p = next + 1;
1177         next = strchr(p, '\n');
1178       } else {
1179         p = NULL;
1180       }
1181     }
1182
1183     if( drop_len && drop_len < 65535 ) {
1184       wine_tsx11_lock();
1185       XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1186                      &x, &y, &u.i, &u.i, &u.i);
1187       wine_tsx11_unlock();
1188
1189       drop_len += sizeof(DROPFILES) + 1;
1190       hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1191       lpDrop = (DROPFILES *) GlobalLock( hDrop );
1192
1193       if( lpDrop ) {
1194           WND *pDropWnd = WIN_FindWndPtr( hWnd );
1195           lpDrop->pFiles = sizeof(DROPFILES);
1196           lpDrop->pt.x = (INT)x;
1197           lpDrop->pt.y = (INT)y;
1198           lpDrop->fNC =
1199             ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left)  ||
1200               y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top)    ||
1201               x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1202               y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1203           lpDrop->fWide = FALSE;
1204           p_drop = (char*)(lpDrop + 1);
1205           WIN_ReleaseWndPtr(pDropWnd);
1206       }
1207
1208       /* create message content */
1209       if (p_drop) {
1210         p = p_data;
1211         next = strchr(p, '\n');
1212         while (p) {
1213           if (next) *next=0;
1214           if (strncmp(p,"file:",5) == 0 ) {
1215             INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1216             if (len) {
1217               TRACE("drop file %s as %s\n", p+5, p_drop);
1218               p_drop += len+1;
1219             } else {
1220               WARN("can't convert file %s to dos name \n", p+5);
1221             }
1222           } else {
1223             WARN("unknown mime type %s\n", p);
1224           }
1225           if (next) {
1226             *next = '\n';
1227             p = next + 1;
1228             next = strchr(p, '\n');
1229           } else {
1230             p = NULL;
1231           }
1232           *p_drop = '\0';
1233         }
1234
1235         GlobalUnlock(hDrop);
1236         PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1237       }
1238     }
1239     wine_tsx11_lock();
1240     if( p_data ) XFree(p_data);
1241     wine_tsx11_unlock();
1242   }
1243 }
1244
1245 /**********************************************************************
1246  *           EVENT_ClientMessage
1247  */
1248 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
1249 {
1250   if (event->message_type != None && event->format == 32) {
1251     if (event->message_type == x11drv_atom(WM_PROTOCOLS))
1252         handle_wm_protocols_message( hWnd, event );
1253     else if (event->message_type == x11drv_atom(DndProtocol))
1254     {
1255         /* query window (drag&drop event contains only drag window) */
1256         Window root, child;
1257         int root_x, root_y, child_x, child_y;
1258         unsigned int u;
1259
1260         wine_tsx11_lock();
1261         XQueryPointer( event->display, root_window, &root, &child,
1262                        &root_x, &root_y, &child_x, &child_y, &u);
1263         if (XFindContext( event->display, child, winContext, (char **)&hWnd ) != 0) hWnd = 0;
1264         wine_tsx11_unlock();
1265         if (!hWnd) return;
1266         if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1267             EVENT_DropFromOffiX(hWnd, event);
1268         else if (event->data.l[0] == DndURL)
1269             EVENT_DropURLs(hWnd, event);
1270     }
1271     else if (!X11DRV_XDND_Event(hWnd, event))
1272     {
1273 #if 0
1274       /* enable this if you want to see the message */
1275       unsigned char* p_data = NULL;
1276       union {
1277         unsigned long   l;
1278         int             i;
1279         Atom            atom;
1280       } u; /* unused */
1281       wine_tsx11_lock();
1282       XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1283                             dndSelection, 0, 65535, FALSE,
1284                             AnyPropertyType, &u.atom, &u.i,
1285                             &u.l, &u.l, &p_data);
1286       wine_tsx11_unlock();
1287       TRACE("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1288             event->message_type, event->data.l[0], event->data.l[1],
1289             event->data.l[2], event->data.l[3], event->data.l[4],
1290             p_data);
1291 #endif
1292       TRACE("unrecognized ClientMessage\n" );
1293     }
1294   }
1295 }
1296
1297
1298 /**********************************************************************
1299  *              X11DRV_EVENT_SetInputMethod
1300  */
1301 INPUT_TYPE X11DRV_EVENT_SetInputMethod(INPUT_TYPE type)
1302 {
1303   INPUT_TYPE prev = current_input_type;
1304
1305   /* Flag not used yet */
1306   in_transition = FALSE;
1307   current_input_type = type;
1308
1309   return prev;
1310 }
1311
1312 #ifdef HAVE_LIBXXF86DGA2
1313 /**********************************************************************
1314  *              X11DRV_EVENT_SetDGAStatus
1315  */
1316 void X11DRV_EVENT_SetDGAStatus(HWND hwnd, int event_base)
1317 {
1318   if (event_base < 0) {
1319     DGAUsed = FALSE;
1320     DGAhwnd = 0;
1321   } else {
1322     DGAUsed = TRUE;
1323     DGAhwnd = hwnd;
1324     DGAMotionEventType = event_base + MotionNotify;
1325     DGAButtonPressEventType = event_base + ButtonPress;
1326     DGAButtonReleaseEventType = event_base + ButtonRelease;
1327     DGAKeyPressEventType = event_base + KeyPress;
1328     DGAKeyReleaseEventType = event_base + KeyRelease;
1329   }
1330 }
1331 #endif