Implement A->W call for GetNamedSecurityInfo.
[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     TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
536
537     if (event->detail == NotifyPointer) return;
538     if (ximInComposeMode) return;
539
540     x11drv_thread_data()->last_focus = hwnd;
541     if ((xic = X11DRV_get_ic( hwnd )))
542     {
543         wine_tsx11_lock();
544         XUnsetICFocus( xic );
545         wine_tsx11_unlock();
546     }
547     if (hwnd != GetForegroundWindow()) return;
548     SendMessageA( hwnd, WM_CANCELMODE, 0, 0 );
549
550     /* don't reset the foreground window, if the window which is
551        getting the focus is a Wine window */
552
553     wine_tsx11_lock();
554     XGetInputFocus( thread_display(), &focus_win, &revert );
555     if (focus_win)
556     {
557         if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
558             focus_win = 0;
559     }
560     wine_tsx11_unlock();
561
562     if (!focus_win)
563     {
564         /* Abey : 6-Oct-99. Check again if the focus out window is the
565            Foreground window, because in most cases the messages sent
566            above must have already changed the foreground window, in which
567            case we don't have to change the foreground window to 0 */
568         if (hwnd == GetForegroundWindow())
569         {
570             TRACE( "lost focus, setting fg to 0\n" );
571             SetForegroundWindow( 0 );
572         }
573     }
574 }
575
576
577 /***********************************************************************
578  *           EVENT_SelectionRequest_AddTARGETS
579  *  Utility function for EVENT_SelectionRequest_TARGETS.
580  */
581 static BOOL EVENT_SelectionRequest_AddTARGETS(Atom* targets, unsigned long cTargets, Atom prop)
582 {
583     int i;
584     BOOL bExists;
585
586     /* Scan through what we have so far to avoid duplicates */
587     for (i = 0, bExists = FALSE; i < cTargets; i++)
588     {
589         if (targets[i] == prop)
590         {
591             bExists = TRUE;
592             break;
593         }
594     }
595
596     if (!bExists)
597         targets[cTargets] = prop;
598
599     return !bExists;
600 }
601
602
603 /***********************************************************************
604  *           EVENT_SelectionRequest_TARGETS
605  *  Service a TARGETS selection request event
606  */
607 static Atom EVENT_SelectionRequest_TARGETS( Display *display, Window requestor,
608                                             Atom target, Atom rprop )
609 {
610     Atom* targets;
611     UINT wFormat;
612     UINT alias;
613     ULONG cTargets;
614     LPWINE_CLIPFORMAT lpFormat;
615
616     /*
617      * Count the number of items we wish to expose as selection targets.
618      * We include the TARGETS item, and property aliases
619      */
620     cTargets = X11DRV_CountClipboardFormats() + 1;
621
622     for (wFormat = 0; (wFormat = X11DRV_EnumClipboardFormats(wFormat));)
623     {
624         lpFormat = X11DRV_CLIPBOARD_LookupFormat(wFormat);
625
626         if (lpFormat)
627         {
628             if (!lpFormat->lpDrvExportFunc)
629                 cTargets--;
630
631             if (X11DRV_CLIPBOARD_LookupPropertyAlias(lpFormat->drvData))
632                 cTargets++;
633         }
634         /* else most likely unregistered format such as CF_PRIVATE or CF_GDIOBJ */
635     }
636
637     TRACE_(clipboard)(" found %ld formats\n", cTargets);
638
639     /* Allocate temp buffer */
640     targets = (Atom*)HeapAlloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
641     if(targets == NULL) 
642         return None;
643
644     /* Create TARGETS property list (First item in list is TARGETS itself) */
645     for (targets[0] = x11drv_atom(TARGETS), cTargets = 1, wFormat = 0;
646           (wFormat = X11DRV_EnumClipboardFormats(wFormat));)
647     {
648         lpFormat = X11DRV_CLIPBOARD_LookupFormat(wFormat);
649
650         if (lpFormat)
651         {
652             if (lpFormat->lpDrvExportFunc)
653             {
654                 if (EVENT_SelectionRequest_AddTARGETS(targets, cTargets, lpFormat->drvData))
655                    cTargets++;
656             }
657
658             /* Check if any alias should be listed */
659             alias = X11DRV_CLIPBOARD_LookupPropertyAlias(lpFormat->drvData);
660             if (alias)
661             {
662                 if (EVENT_SelectionRequest_AddTARGETS(targets, cTargets, alias))
663                    cTargets++;
664             }
665         }
666     }
667
668     wine_tsx11_lock();
669
670     if (TRACE_ON(clipboard))
671     {
672         int i;
673         for ( i = 0; i < cTargets; i++)
674         {
675             if (targets[i])
676             {
677                 char *itemFmtName = XGetAtomName(display, targets[i]);
678                 TRACE_(clipboard)("\tAtom# %d:  Property %ld Type %s\n", i, targets[i], itemFmtName);
679                 XFree(itemFmtName);
680             }
681         }
682     }
683
684     /* We may want to consider setting the type to xaTargets instead,
685      * in case some apps expect this instead of XA_ATOM */
686     XChangeProperty(display, requestor, rprop, XA_ATOM, 32,
687                     PropModeReplace, (unsigned char *)targets, cTargets);
688     wine_tsx11_unlock();
689
690     HeapFree(GetProcessHeap(), 0, targets);
691
692     return rprop;
693 }
694
695
696 /***********************************************************************
697  *           EVENT_SelectionRequest_MULTIPLE
698  *  Service a MULTIPLE selection request event
699  *  rprop contains a list of (target,property) atom pairs.
700  *  The first atom names a target and the second names a property.
701  *  The effect is as if we have received a sequence of SelectionRequest events
702  *  (one for each atom pair) except that:
703  *  1. We reply with a SelectionNotify only when all the requested conversions
704  *  have been performed.
705  *  2. If we fail to convert the target named by an atom in the MULTIPLE property,
706  *  we replace the atom in the property by None.
707  */
708 static Atom EVENT_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
709 {
710     Display *display = pevent->display;
711     Atom           rprop;
712     Atom           atype=AnyPropertyType;
713     int            aformat;
714     unsigned long  remain;
715     Atom*          targetPropList=NULL;
716     unsigned long  cTargetPropList = 0;
717
718    /* If the specified property is None the requestor is an obsolete client.
719     * We support these by using the specified target atom as the reply property.
720     */
721     rprop = pevent->property;
722     if( rprop == None )
723         rprop = pevent->target;
724     if (!rprop)
725         goto END;
726
727     /* Read the MULTIPLE property contents. This should contain a list of
728      * (target,property) atom pairs.
729      */
730     wine_tsx11_lock();
731     if(XGetWindowProperty(display, pevent->requestor, rprop,
732                             0, 0x3FFF, False, AnyPropertyType, &atype,&aformat,
733                             &cTargetPropList, &remain,
734                             (unsigned char**)&targetPropList) != Success)
735     {
736         wine_tsx11_unlock();
737         TRACE("\tCouldn't read MULTIPLE property\n");
738     }
739     else
740     {
741        TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
742              XGetAtomName(display, atype), aformat, cTargetPropList, remain);
743        wine_tsx11_unlock();
744
745        /*
746         * Make sure we got what we expect.
747         * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
748         * in a MULTIPLE selection request should be of type ATOM_PAIR.
749         * However some X apps(such as XPaint) are not compliant with this and return
750         * a user defined atom in atype when XGetWindowProperty is called.
751         * The data *is* an atom pair but is not denoted as such.
752         */
753        if(aformat == 32 /* atype == xAtomPair */ )
754        {
755           int i;
756
757           /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
758            * for each (target,property) pair */
759
760           for (i = 0; i < cTargetPropList; i+=2)
761           {
762               XSelectionRequestEvent event;
763
764               if (TRACE_ON(event))
765               {
766                   char *targetName, *propName;
767                   wine_tsx11_lock();
768                   targetName = XGetAtomName(display, targetPropList[i]);
769                   propName = XGetAtomName(display, targetPropList[i+1]);
770                   TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
771                         i/2, targetName, propName);
772                   XFree(targetName);
773                   XFree(propName);
774                   wine_tsx11_unlock();
775               }
776
777               /* We must have a non "None" property to service a MULTIPLE target atom */
778               if ( !targetPropList[i+1] )
779               {
780                   TRACE("\tMULTIPLE(%d): Skipping target with empty property!\n", i);
781                   continue;
782               }
783
784               /* Set up an XSelectionRequestEvent for this (target,property) pair */
785               memcpy( &event, pevent, sizeof(XSelectionRequestEvent) );
786               event.target = targetPropList[i];
787               event.property = targetPropList[i+1];
788
789               /* Fire a SelectionRequest, informing the handler that we are processing
790                * a MULTIPLE selection request event.
791                */
792               EVENT_SelectionRequest( hWnd, &event, TRUE );
793           }
794        }
795
796        /* Free the list of targets/properties */
797        wine_tsx11_lock();
798        XFree(targetPropList);
799        wine_tsx11_unlock();
800     }
801
802 END:
803     return rprop;
804 }
805
806
807 /***********************************************************************
808  *           EVENT_SelectionRequest
809  *  Process an event selection request event.
810  *  The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
811  *  recursively while servicing a "MULTIPLE" selection target.
812  *
813  *  Note: We only receive this event when WINE owns the X selection
814  */
815 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
816 {
817     Display *display = event->display;
818   XSelectionEvent result;
819   Atom            rprop = None;
820   Window          request = event->requestor;
821
822   TRACE_(clipboard)("\n");
823
824   /*
825    * We can only handle the selection request if :
826    * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
827    * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
828    * since this has been already done.
829    */
830   if ( !bIsMultiple )
831   {
832     if (((event->selection != XA_PRIMARY) && (event->selection != x11drv_atom(CLIPBOARD))))
833        goto END;
834   }
835
836   /* If the specified property is None the requestor is an obsolete client.
837    * We support these by using the specified target atom as the reply property.
838    */
839   rprop = event->property;
840   if( rprop == None )
841       rprop = event->target;
842
843   if(event->target == x11drv_atom(TARGETS))  /*  Return a list of all supported targets */
844   {
845       /* TARGETS selection request */
846       rprop = EVENT_SelectionRequest_TARGETS( display, request, event->target, rprop );
847   }
848   else if(event->target == x11drv_atom(MULTIPLE))  /*  rprop contains a list of (target, property) atom pairs */
849   {
850       /* MULTIPLE selection request */
851       rprop = EVENT_SelectionRequest_MULTIPLE( hWnd, event );
852   }
853   else
854   {
855       LPWINE_CLIPFORMAT lpFormat = X11DRV_CLIPBOARD_LookupProperty(event->target);
856
857       if (!lpFormat)
858           lpFormat = X11DRV_CLIPBOARD_LookupAliasProperty(event->target);
859
860       if (lpFormat && lpFormat->lpDrvExportFunc)
861       {
862           LPWINE_CLIPDATA lpData = X11DRV_CLIPBOARD_LookupData(lpFormat->wFormatID);
863
864           if (lpData)
865           {
866               unsigned char* lpClipData;
867               DWORD cBytes;
868               HANDLE hClipData = lpFormat->lpDrvExportFunc(request, event->target,
869                   rprop, lpData, &cBytes);
870
871               if (hClipData && (lpClipData = GlobalLock(hClipData)))
872               {
873                   TRACE_(clipboard)("\tUpdating property %s, %ld bytes\n",
874                       lpFormat->Name, cBytes);
875
876                   wine_tsx11_lock();
877                   XChangeProperty(display, request, rprop, event->target,
878                       8, PropModeReplace, (unsigned char *)lpClipData, cBytes);
879                   wine_tsx11_unlock();
880
881                   GlobalUnlock(hClipData);
882                   GlobalFree(hClipData);
883               }
884           }
885       }
886   }
887
888 END:
889   /* reply to sender
890    * SelectionNotify should be sent only at the end of a MULTIPLE request
891    */
892   if ( !bIsMultiple )
893   {
894     result.type = SelectionNotify;
895     result.display = display;
896     result.requestor = request;
897     result.selection = event->selection;
898     result.property = rprop;
899     result.target = event->target;
900     result.time = event->time;
901     TRACE("Sending SelectionNotify event...\n");
902     wine_tsx11_lock();
903     XSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
904     wine_tsx11_unlock();
905   }
906 }
907
908 /***********************************************************************
909  *           EVENT_SelectionClear
910  */
911 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
912 {
913   if (event->selection == XA_PRIMARY || event->selection == x11drv_atom(CLIPBOARD))
914       X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd );
915 }
916
917 /***********************************************************************
918  *           EVENT_PropertyNotify
919  *   We use this to release resources like Pixmaps when a selection
920  *   client no longer needs them.
921  */
922 static void EVENT_PropertyNotify( XPropertyEvent *event )
923 {
924   /* Check if we have any resources to free */
925   TRACE("Received PropertyNotify event: \n");
926
927   switch(event->state)
928   {
929     case PropertyDelete:
930     {
931       TRACE("\tPropertyDelete for atom %ld on window %ld\n",
932             event->atom, (long)event->window);
933       break;
934     }
935
936     case PropertyNewValue:
937     {
938       TRACE("\tPropertyNewValue for atom %ld on window %ld\n\n",
939             event->atom, (long)event->window);
940       break;
941     }
942
943     default:
944       break;
945   }
946 }
947
948 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
949 {
950     RECT tempRect;
951
952     if (!IsWindowEnabled(hQueryWnd)) return 0;
953     
954     GetWindowRect(hQueryWnd, &tempRect);
955
956     if(!PtInRect(&tempRect, *lpPt)) return 0;
957
958     if (!IsIconic( hQueryWnd ))
959     {
960         GetClientRect( hQueryWnd, &tempRect );
961         MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
962
963         if (PtInRect( &tempRect, *lpPt))
964         {
965             HWND *list = WIN_ListChildren( hQueryWnd );
966             HWND bResult = 0;
967
968             if (list)
969             {
970                 int i;
971                 
972                 for (i = 0; list[i]; i++)
973                 {
974                     if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
975                     {
976                         GetWindowRect( list[i], &tempRect );
977                         if (PtInRect( &tempRect, *lpPt )) break;
978                     }
979                 }
980                 if (list[i])
981                 {
982                     if (IsWindowEnabled( list[i] ))
983                         bResult = find_drop_window( list[i], lpPt );
984                 }
985                 HeapFree( GetProcessHeap(), 0, list );
986             }
987             if(bResult) return bResult;
988         }
989     }
990
991     if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
992     
993     ScreenToClient(hQueryWnd, lpPt);
994
995     return hQueryWnd;
996 }
997
998 /**********************************************************************
999  *           EVENT_DropFromOffix
1000  *
1001  * don't know if it still works (last Changlog is from 96/11/04)
1002  */
1003 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1004 {
1005     unsigned long       data_length;
1006     unsigned long       aux_long;
1007     unsigned char*      p_data = NULL;
1008     union {
1009         Atom    atom_aux;
1010         struct {
1011             int x;
1012             int y;
1013         }       pt_aux;
1014         int     i;
1015     }                   u;
1016     int                 x, y;
1017     BOOL                bAccept;
1018     Window              w_aux_root, w_aux_child;
1019     WND*                pWnd;
1020     HWND                hScope = hWnd;
1021
1022     pWnd = WIN_FindWndPtr(hWnd);
1023
1024     wine_tsx11_lock();
1025     XQueryPointer( event->display, get_whole_window(pWnd), &w_aux_root, &w_aux_child,
1026                    &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
1027                    (unsigned int*)&aux_long);
1028     wine_tsx11_unlock();
1029
1030     /* find out drop point and drop window */
1031     if( x < 0 || y < 0 ||
1032         x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1033         y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1034     {   
1035         bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; 
1036         x = 0;
1037         y = 0; 
1038     }
1039     else
1040     {
1041         POINT   pt = { x, y };
1042         HWND    hwndDrop = find_drop_window( hWnd, &pt );
1043         if (hwndDrop)
1044         {
1045             x = pt.x;
1046             y = pt.y;
1047             hScope = hwndDrop;
1048             bAccept = TRUE;
1049         }
1050         else
1051         {
1052             bAccept = FALSE;
1053         }
1054     }
1055     WIN_ReleaseWndPtr(pWnd);
1056
1057     if (!bAccept) return;
1058
1059     wine_tsx11_lock();
1060     XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1061                         x11drv_atom(DndSelection), 0, 65535, FALSE,
1062                         AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
1063                         &data_length, &aux_long, &p_data);
1064     wine_tsx11_unlock();
1065
1066     if( !aux_long && p_data)  /* don't bother if > 64K */
1067     {
1068         signed char *p = (signed char*) p_data;
1069         char *p_drop;
1070
1071         aux_long = 0;
1072         while( *p )  /* calculate buffer size */
1073         {
1074             p_drop = p;
1075             if((u.i = *p) != -1 )
1076             {
1077                 INT len = GetShortPathNameA( p, NULL, 0 );
1078                 if (len) aux_long += len + 1;
1079                 else *p = -1;
1080             }
1081             p += strlen(p) + 1;
1082         }
1083         if( aux_long && aux_long < 65535 )
1084         {
1085             HDROP                 hDrop;
1086             DROPFILES *lpDrop;
1087
1088             aux_long += sizeof(DROPFILES) + 1;
1089             hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1090             lpDrop = (DROPFILES*)GlobalLock( hDrop );
1091
1092             if( lpDrop )
1093             {
1094                 WND *pDropWnd = WIN_FindWndPtr( hScope );
1095                 lpDrop->pFiles = sizeof(DROPFILES);
1096                 lpDrop->pt.x = x;
1097                 lpDrop->pt.y = y;
1098                 lpDrop->fNC =
1099                     ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left)  ||
1100                       y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top)    ||
1101                       x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1102                       y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1103                 lpDrop->fWide = FALSE;
1104                 WIN_ReleaseWndPtr(pDropWnd);
1105                 p_drop = (char *)(lpDrop + 1);
1106                 p = p_data;
1107                 while(*p)
1108                 {
1109                     if( *p != -1 ) /* use only "good" entries */
1110                     {
1111                         GetShortPathNameA( p, p_drop, 65535 );
1112                         p_drop += strlen( p_drop ) + 1;
1113                     }
1114                     p += strlen(p) + 1;
1115                 }
1116                 *p_drop = '\0';
1117                 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1118             }
1119         }
1120     }
1121     wine_tsx11_lock();
1122     if( p_data ) XFree(p_data);
1123     wine_tsx11_unlock();
1124 }
1125
1126 /**********************************************************************
1127  *           EVENT_DropURLs
1128  *
1129  * drop items are separated by \n
1130  * each item is prefixed by its mime type
1131  *
1132  * event->data.l[3], event->data.l[4] contains drop x,y position
1133  */
1134 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1135 {
1136   unsigned long data_length;
1137   unsigned long aux_long, drop_len = 0;
1138   unsigned char *p_data = NULL; /* property data */
1139   char          *p_drop = NULL;
1140   char          *p, *next;
1141   int           x, y;
1142   DROPFILES *lpDrop;
1143   HDROP hDrop;
1144   union {
1145     Atom        atom_aux;
1146     int         i;
1147     Window      w_aux;
1148   }             u; /* unused */
1149
1150   if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1151
1152   wine_tsx11_lock();
1153   XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1154                       x11drv_atom(DndSelection), 0, 65535, FALSE,
1155                       AnyPropertyType, &u.atom_aux, &u.i,
1156                       &data_length, &aux_long, &p_data);
1157   wine_tsx11_unlock();
1158   if (aux_long)
1159     WARN("property too large, truncated!\n");
1160   TRACE("urls=%s\n", p_data);
1161
1162   if( !aux_long && p_data) {    /* don't bother if > 64K */
1163     /* calculate length */
1164     p = p_data;
1165     next = strchr(p, '\n');
1166     while (p) {
1167       if (next) *next=0;
1168       if (strncmp(p,"file:",5) == 0 ) {
1169         INT len = GetShortPathNameA( p+5, NULL, 0 );
1170         if (len) drop_len += len + 1;
1171       }
1172       if (next) {
1173         *next = '\n';
1174         p = next + 1;
1175         next = strchr(p, '\n');
1176       } else {
1177         p = NULL;
1178       }
1179     }
1180
1181     if( drop_len && drop_len < 65535 ) {
1182       wine_tsx11_lock();
1183       XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1184                      &x, &y, &u.i, &u.i, &u.i);
1185       wine_tsx11_unlock();
1186
1187       drop_len += sizeof(DROPFILES) + 1;
1188       hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1189       lpDrop = (DROPFILES *) GlobalLock( hDrop );
1190
1191       if( lpDrop ) {
1192           WND *pDropWnd = WIN_FindWndPtr( hWnd );
1193           lpDrop->pFiles = sizeof(DROPFILES);
1194           lpDrop->pt.x = (INT)x;
1195           lpDrop->pt.y = (INT)y;
1196           lpDrop->fNC =
1197             ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left)  ||
1198               y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top)    ||
1199               x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1200               y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1201           lpDrop->fWide = FALSE;
1202           p_drop = (char*)(lpDrop + 1);
1203           WIN_ReleaseWndPtr(pDropWnd);
1204       }
1205
1206       /* create message content */
1207       if (p_drop) {
1208         p = p_data;
1209         next = strchr(p, '\n');
1210         while (p) {
1211           if (next) *next=0;
1212           if (strncmp(p,"file:",5) == 0 ) {
1213             INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1214             if (len) {
1215               TRACE("drop file %s as %s\n", p+5, p_drop);
1216               p_drop += len+1;
1217             } else {
1218               WARN("can't convert file %s to dos name \n", p+5);
1219             }
1220           } else {
1221             WARN("unknown mime type %s\n", p);
1222           }
1223           if (next) {
1224             *next = '\n';
1225             p = next + 1;
1226             next = strchr(p, '\n');
1227           } else {
1228             p = NULL;
1229           }
1230           *p_drop = '\0';
1231         }
1232
1233         GlobalUnlock(hDrop);
1234         PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1235       }
1236     }
1237     wine_tsx11_lock();
1238     if( p_data ) XFree(p_data);
1239     wine_tsx11_unlock();
1240   }
1241 }
1242
1243 /**********************************************************************
1244  *           EVENT_ClientMessage
1245  */
1246 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
1247 {
1248   if (event->message_type != None && event->format == 32) {
1249     if (event->message_type == x11drv_atom(WM_PROTOCOLS))
1250         handle_wm_protocols_message( hWnd, event );
1251     else if (event->message_type == x11drv_atom(DndProtocol))
1252     {
1253         /* query window (drag&drop event contains only drag window) */
1254         Window root, child;
1255         int root_x, root_y, child_x, child_y;
1256         unsigned int u;
1257
1258         wine_tsx11_lock();
1259         XQueryPointer( event->display, root_window, &root, &child,
1260                        &root_x, &root_y, &child_x, &child_y, &u);
1261         if (XFindContext( event->display, child, winContext, (char **)&hWnd ) != 0) hWnd = 0;
1262         wine_tsx11_unlock();
1263         if (!hWnd) return;
1264         if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1265             EVENT_DropFromOffiX(hWnd, event);
1266         else if (event->data.l[0] == DndURL)
1267             EVENT_DropURLs(hWnd, event);
1268     }
1269     else if (!X11DRV_XDND_Event(hWnd, event))
1270     {
1271 #if 0
1272       /* enable this if you want to see the message */
1273       unsigned char* p_data = NULL;
1274       union {
1275         unsigned long   l;
1276         int             i;
1277         Atom            atom;
1278       } u; /* unused */
1279       wine_tsx11_lock();
1280       XGetWindowProperty( event->display, DefaultRootWindow(event->display),
1281                             dndSelection, 0, 65535, FALSE,
1282                             AnyPropertyType, &u.atom, &u.i,
1283                             &u.l, &u.l, &p_data);
1284       wine_tsx11_unlock();
1285       TRACE("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1286             event->message_type, event->data.l[0], event->data.l[1],
1287             event->data.l[2], event->data.l[3], event->data.l[4],
1288             p_data);
1289 #endif
1290       TRACE("unrecognized ClientMessage\n" );
1291     }
1292   }
1293 }
1294
1295
1296 /**********************************************************************
1297  *              X11DRV_EVENT_SetInputMethod
1298  */
1299 INPUT_TYPE X11DRV_EVENT_SetInputMethod(INPUT_TYPE type)
1300 {
1301   INPUT_TYPE prev = current_input_type;
1302
1303   /* Flag not used yet */
1304   in_transition = FALSE;
1305   current_input_type = type;
1306
1307   return prev;
1308 }
1309
1310 #ifdef HAVE_LIBXXF86DGA2
1311 /**********************************************************************
1312  *              X11DRV_EVENT_SetDGAStatus
1313  */
1314 void X11DRV_EVENT_SetDGAStatus(HWND hwnd, int event_base)
1315 {
1316   if (event_base < 0) {
1317     DGAUsed = FALSE;
1318     DGAhwnd = 0;
1319   } else {
1320     DGAUsed = TRUE;
1321     DGAhwnd = hwnd;
1322     DGAMotionEventType = event_base + MotionNotify;
1323     DGAButtonPressEventType = event_base + ButtonPress;
1324     DGAButtonReleaseEventType = event_base + ButtonRelease;
1325     DGAKeyPressEventType = event_base + KeyPress;
1326     DGAKeyReleaseEventType = event_base + KeyRelease;
1327   }
1328 }
1329 #endif