Release 970305
[wine] / windows / event.c
1 /*
2  * X events handling functions
3  * 
4  * Copyright 1993 Alexandre Julliard
5  * 
6  */
7
8 #include <ctype.h>
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <sys/time.h>
14 #include <sys/types.h>
15 #include <errno.h>
16 #include <X11/keysym.h>
17 #include <X11/Xlib.h>
18 #include <X11/Xresource.h>
19 #include <X11/Xutil.h>
20 #include <X11/Xatom.h>
21
22 #include "windows.h"
23 #include "winnt.h"
24 #include "gdi.h"
25 #include "heap.h"
26 #include "queue.h"
27 #include "win.h"
28 #include "class.h"
29 #include "clipboard.h"
30 #include "message.h"
31 #include "module.h"
32 #include "options.h"
33 #include "queue.h"
34 #include "winpos.h"
35 #include "drive.h"
36 #include "shell.h"
37 #include "xmalloc.h"
38 #include "keyboard.h"
39 #include "stddebug.h"
40 #include "debug.h"
41 #include "dde_proc.h"
42
43
44 #define NB_BUTTONS      3     /* Windows can handle 3 buttons */
45
46 #define DndNotDnd       -1    /* OffiX drag&drop */
47 #define DndUnknown      0
48 #define DndRawData      1
49 #define DndFile         2
50 #define DndFiles        3
51 #define DndText         4
52 #define DndDir          5
53 #define DndLink         6
54 #define DndExe          7
55
56 #define DndEND          8
57
58   /* X context to associate a hwnd to an X window */
59 static XContext winContext = 0;
60
61 static INT16  captureHT = HTCLIENT;
62 static HWND32 captureWnd = 0;
63 static BOOL32 InputEnabled = TRUE;
64 static BOOL32 SwappedButtons = FALSE;
65
66 static Atom wmProtocols = None;
67 static Atom wmDeleteWindow = None;
68 static Atom dndProtocol = None;
69 static Atom dndSelection = None;
70
71 static const char * const event_names[] =
72 {
73     "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
74     "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
75     "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
76     "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
77     "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
78     "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
79     "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
80     "ClientMessage", "MappingNotify"
81 };
82
83   /* Event handlers */
84 static void EVENT_Key( XKeyEvent *event );
85 static void EVENT_ButtonPress( XButtonEvent *event );
86 static void EVENT_ButtonRelease( XButtonEvent *event );
87 static void EVENT_MotionNotify( XMotionEvent *event );
88 static void EVENT_FocusIn( HWND32 hwnd, XFocusChangeEvent *event );
89 static void EVENT_FocusOut( HWND32 hwnd, XFocusChangeEvent *event );
90 static void EVENT_Expose( WND *pWnd, XExposeEvent *event );
91 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event );
92 static void EVENT_ConfigureNotify( HWND32 hwnd, XConfigureEvent *event );
93 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event);
94 static void EVENT_SelectionNotify( XSelectionEvent *event);
95 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event);
96 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event );
97 static void EVENT_MapNotify( HWND32 hwnd, XMapEvent *event );
98
99 /* Usable only with OLVWM - compile option perhaps?
100 static void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event );
101 */
102
103 extern void FOCUS_SetXFocus( HWND32 );
104 extern BOOL16 DRAG_QueryUpdate( HWND16, SEGPTR, BOOL32 );
105
106 /***********************************************************************
107  *           EVENT_ProcessEvent
108  *
109  * Process an X event.
110  */
111 void EVENT_ProcessEvent( XEvent *event )
112 {
113     WND *pWnd;
114     
115     if (XFindContext( display, event->xany.window, winContext,
116                       (char **)&pWnd ) != 0)
117         return;  /* Not for a registered window */
118
119     dprintf_event( stddeb, "Got event %s for hwnd %04x\n",
120                    event_names[event->type], pWnd->hwndSelf );
121
122     switch(event->type)
123     {
124     case KeyPress:
125     case KeyRelease:
126         if (InputEnabled)
127             EVENT_Key( (XKeyEvent*)event );
128         break;
129         
130     case ButtonPress:
131         if (InputEnabled)
132             EVENT_ButtonPress( (XButtonEvent*)event );
133         break;
134
135     case ButtonRelease:
136         if (InputEnabled)
137             EVENT_ButtonRelease( (XButtonEvent*)event );
138         break;
139
140     case MotionNotify:
141         /* Wine between two fast machines across the overloaded campus
142            ethernet gets very boged down in MotionEvents. The following
143            simply finds the last motion event in the queue and drops
144            the rest. On a good link events are servered before they build
145            up so this doesn't take place. On a slow link this may cause
146            problems if the event order is important. I'm not yet seen
147            of any problems. Jon 7/6/96.
148          */
149         if (InputEnabled)
150         {
151             while (XCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
152                                           MotionNotify, event));    
153             EVENT_MotionNotify( (XMotionEvent*)event );
154         }
155         break;
156
157     case FocusIn:
158         EVENT_FocusIn( pWnd->hwndSelf, (XFocusChangeEvent*)event );
159         break;
160
161     case FocusOut:
162         EVENT_FocusOut( pWnd->hwndSelf, (XFocusChangeEvent*)event );
163         break;
164
165     case Expose:
166         EVENT_Expose( pWnd, (XExposeEvent *)event );
167         break;
168
169     case GraphicsExpose:
170         EVENT_GraphicsExpose( pWnd, (XGraphicsExposeEvent *)event );
171         break;
172
173     case ConfigureNotify:
174         EVENT_ConfigureNotify( pWnd->hwndSelf, (XConfigureEvent*)event );
175         break;
176
177     case SelectionRequest:
178         EVENT_SelectionRequest( pWnd, (XSelectionRequestEvent *)event );
179         break;
180
181     case SelectionNotify:
182         EVENT_SelectionNotify( (XSelectionEvent *)event );
183         break;
184
185     case SelectionClear:
186         EVENT_SelectionClear( pWnd, (XSelectionClearEvent*) event );
187         break;
188
189     case ClientMessage:
190         EVENT_ClientMessage( pWnd, (XClientMessageEvent *) event );
191         break;
192
193 /*  case EnterNotify:
194  *       EVENT_EnterNotify( pWnd, (XCrossingEvent *) event );
195  *       break;
196  */
197     case NoExpose:
198         break;
199
200     /* We get all these because of StructureNotifyMask. */
201     case UnmapNotify:
202     case CirculateNotify:
203     case CreateNotify:
204     case DestroyNotify:
205     case GravityNotify:
206     case ReparentNotify:
207         break;
208
209     case MapNotify:
210         EVENT_MapNotify( pWnd->hwndSelf, (XMapEvent *)event );
211         break;
212
213     default:    
214         dprintf_event(stddeb, "Unprocessed event %s for hwnd %04x\n",
215                 event_names[event->type], pWnd->hwndSelf );
216         break;
217     }
218 }
219
220
221 /***********************************************************************
222  *           EVENT_RegisterWindow
223  *
224  * Associate an X window to a HWND.
225  */
226 void EVENT_RegisterWindow( WND *pWnd )
227 {
228     if (wmProtocols == None)
229         wmProtocols = XInternAtom( display, "WM_PROTOCOLS", True );
230     if (wmDeleteWindow == None)
231         wmDeleteWindow = XInternAtom( display, "WM_DELETE_WINDOW", True );
232     if( dndProtocol == None )
233         dndProtocol = XInternAtom( display, "DndProtocol" , False );
234     if( dndSelection == None )
235         dndSelection = XInternAtom( display, "DndSelection" , False );
236
237     XSetWMProtocols( display, pWnd->window, &wmDeleteWindow, 1 );
238
239     if (!winContext) winContext = XUniqueContext();
240     XSaveContext( display, pWnd->window, winContext, (char *)pWnd );
241 }
242
243 /***********************************************************************
244  *           EVENT_DestroyWindow
245  */
246 void EVENT_DestroyWindow( WND *pWnd )
247 {
248    XEvent xe;
249
250    XDeleteContext( display, pWnd->window, winContext );
251    XDestroyWindow( display, pWnd->window );
252    while( XCheckWindowEvent(display, pWnd->window, NoEventMask, &xe) );
253 }
254
255 /***********************************************************************
256  *           EVENT_WaitXEvent
257  *
258  * Wait for an X event, optionally sleeping until one arrives.
259  * Return TRUE if an event is pending, FALSE on timeout or error
260  * (for instance lost connection with the server).
261  */
262 BOOL32 EVENT_WaitXEvent( BOOL32 sleep, BOOL32 peek )
263 {
264     XEvent event;
265     LONG maxWait = sleep ? TIMER_GetNextExpiration() : 0;
266
267     /* Wait for an event or a timeout. If maxWait is -1, we have no timeout;
268      * in this case, we fall through directly to the XNextEvent loop.
269      */
270
271     if ((maxWait != -1) && !XPending(display))
272     {
273         fd_set read_set;
274         struct timeval timeout;
275         int fd = ConnectionNumber(display);
276
277         FD_ZERO( &read_set );
278         FD_SET( fd, &read_set );
279
280         timeout.tv_usec = (maxWait % 1000) * 1000;
281         timeout.tv_sec = maxWait / 1000;
282
283 #ifdef CONFIG_IPC
284         sigsetjmp(env_wait_x, 1);
285         stop_wait_op= CONT;
286             
287         if (DDE_GetRemoteMessage()) {
288             while(DDE_GetRemoteMessage())
289                 ;
290             return TRUE;
291         }
292         stop_wait_op = STOP_WAIT_X;
293         /* The code up to the next "stop_wait_op = CONT" must be reentrant */
294         if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1 &&
295             !XPending(display))
296         {
297             stop_wait_op = CONT;
298             TIMER_ExpireTimers();
299             return FALSE;
300         }
301         else stop_wait_op = CONT;
302 #else  /* CONFIG_IPC */
303         if (select( fd+1, &read_set, NULL, NULL, &timeout ) != 1)
304         {
305             /* Timeout or error */
306             TIMER_ExpireTimers();
307             return FALSE;
308         }
309 #endif  /* CONFIG_IPC */
310
311     }
312
313     /* Process the event (and possibly others that occurred in the meantime) */
314
315     do
316     {
317
318 #ifdef CONFIG_IPC
319         if (DDE_GetRemoteMessage())
320         {
321             while(DDE_GetRemoteMessage()) ;
322             return TRUE;
323         }
324 #endif  /* CONFIG_IPC */
325
326         XNextEvent( display, &event );
327
328         if( peek )
329         {
330           WND*          pWnd;
331           MESSAGEQUEUE* pQ;
332
333           if (XFindContext( display, ((XAnyEvent *)&event)->window, winContext,
334                             (char **)&pWnd ) || (event.type == NoExpose))
335               continue;
336
337           /* Check only for those events which can be processed
338            * internally. */
339
340           if( event.type == MotionNotify ||
341               event.type == ButtonPress || event.type == ButtonRelease ||
342               event.type == KeyPress || event.type == KeyRelease ||
343               event.type == SelectionRequest || event.type == SelectionClear )
344           {
345                EVENT_ProcessEvent( &event );
346                continue;
347           }
348
349           if( pWnd )
350             if( (pQ = (MESSAGEQUEUE*)GlobalLock16(pWnd->hmemTaskQ)) )
351             {
352               pQ->flags |= QUEUE_FLAG_XEVENT;
353               PostEvent(pQ->hTask);
354               XPutBackEvent(display, &event);
355               break;
356             }
357         }
358         else
359           EVENT_ProcessEvent( &event );
360     }
361     while (XPending( display ));
362     return TRUE;
363 }
364
365
366 /***********************************************************************
367  *           EVENT_Synchronize
368  *
369  * Synchronize with the X server. Should not be used too often.
370  */
371 void EVENT_Synchronize()
372 {
373     XEvent event;
374
375     XSync( display, False );
376     while (XPending( display ))
377     {
378         XNextEvent( display, &event );
379         EVENT_ProcessEvent( &event );
380     }    
381 }
382
383
384 /***********************************************************************
385  *           EVENT_XStateToKeyState
386  *
387  * Translate a X event state (Button1Mask, ShiftMask, etc...) to
388  * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
389  */
390 static WORD EVENT_XStateToKeyState( int state )
391 {
392     int kstate = 0;
393     
394     if (state & Button1Mask) kstate |= MK_LBUTTON;
395     if (state & Button2Mask) kstate |= MK_MBUTTON;
396     if (state & Button3Mask) kstate |= MK_RBUTTON;
397     if (state & ShiftMask)   kstate |= MK_SHIFT;
398     if (state & ControlMask) kstate |= MK_CONTROL;
399     return kstate;
400 }
401
402
403 /***********************************************************************
404  *           EVENT_Expose
405  */
406 static void EVENT_Expose( WND *pWnd, XExposeEvent *event )
407 {
408     RECT32 rect;
409
410     /* Make position relative to client area instead of window */
411     rect.left   = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
412     rect.top    = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
413     rect.right  = rect.left + event->width;
414     rect.bottom = rect.top + event->height;
415
416     PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
417                         RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
418                         (event->count ? 0 : RDW_ERASENOW), 0 );
419 }
420
421
422 /***********************************************************************
423  *           EVENT_GraphicsExpose
424  *
425  * This is needed when scrolling area is partially obscured
426  * by non-Wine X window.
427  */
428 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event )
429 {
430     RECT32 rect;
431
432     /* Make position relative to client area instead of window */
433     rect.left   = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
434     rect.top    = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
435     rect.right  = rect.left + event->width;
436     rect.bottom = rect.top + event->height;
437
438     PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
439                         RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
440                         (event->count ? 0 : RDW_ERASENOW), 0 );
441 }
442
443
444 /***********************************************************************
445  *           EVENT_Key
446  *
447  * Handle a X key event
448  */
449 static void EVENT_Key( XKeyEvent *event )
450 {
451     KEYBOARD_HandleEvent( event );
452 }
453
454
455 /***********************************************************************
456  *           EVENT_MotionNotify
457  */
458 static void EVENT_MotionNotify( XMotionEvent *event )
459 {
460     hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ), 0L,
461                     event->x_root - desktopX, event->y_root - desktopY,
462                     event->time - MSG_WineStartTicks, 0 );
463 }
464
465
466 /***********************************************************************
467  *           EVENT_DummyMotionNotify
468  *
469  * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
470  */
471 void EVENT_DummyMotionNotify(void)
472 {
473     Window root, child;
474     int rootX, rootY, childX, childY;
475     unsigned int state;
476
477     if (XQueryPointer( display, rootWindow, &root, &child,
478                        &rootX, &rootY, &childX, &childY, &state ))
479     {
480         hardware_event(WM_MOUSEMOVE, EVENT_XStateToKeyState( state ), 0L,
481                        rootX - desktopX, rootY - desktopY, GetTickCount(), 0 );
482     }
483 }
484
485
486 /***********************************************************************
487  *           EVENT_ButtonPress
488  */
489 static void EVENT_ButtonPress( XButtonEvent *event )
490 {
491     static WORD messages[NB_BUTTONS] = 
492         { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
493     int buttonNum = event->button - 1;
494
495     if (buttonNum >= NB_BUTTONS) return;
496     if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
497     MouseButtonsStates[buttonNum] = 0x8000;
498     AsyncMouseButtonsStates[buttonNum] = 0x8000;
499     hardware_event( messages[buttonNum],
500                     EVENT_XStateToKeyState( event->state ), 0L,
501                     event->x_root - desktopX, event->y_root - desktopY,
502                     event->time - MSG_WineStartTicks, 0 );
503 }
504
505
506 /***********************************************************************
507  *           EVENT_ButtonRelease
508  */
509 static void EVENT_ButtonRelease( XButtonEvent *event )
510 {
511     static const WORD messages[NB_BUTTONS] = 
512         { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
513     int buttonNum = event->button - 1;
514
515     if (buttonNum >= NB_BUTTONS) return;    
516     if (SwappedButtons) buttonNum = NB_BUTTONS - 1 - buttonNum;
517     MouseButtonsStates[buttonNum] = FALSE;
518     hardware_event( messages[buttonNum],
519                     EVENT_XStateToKeyState( event->state ), 0L,
520                     event->x_root - desktopX, event->y_root - desktopY,
521                     event->time - MSG_WineStartTicks, 0 );
522 }
523
524
525 /**********************************************************************
526  *              EVENT_FocusIn
527  */
528 static void EVENT_FocusIn( HWND32 hwnd, XFocusChangeEvent *event )
529 {
530     if (event->detail == NotifyPointer) return;
531     if (hwnd != GetActiveWindow32()) WINPOS_ChangeActiveWindow( hwnd, FALSE );
532     if ((hwnd != GetFocus32()) && !IsChild32( hwnd, GetFocus32()))
533         SetFocus32( hwnd );
534 }
535
536
537 /**********************************************************************
538  *              EVENT_FocusOut
539  *
540  * Note: only top-level override-redirect windows get FocusOut events.
541  */
542 static void EVENT_FocusOut( HWND32 hwnd, XFocusChangeEvent *event )
543 {
544     if (event->detail == NotifyPointer) return;
545     if (hwnd == GetActiveWindow32()) WINPOS_ChangeActiveWindow( 0, FALSE );
546     if ((hwnd == GetFocus32()) || IsChild32( hwnd, GetFocus32()))
547         SetFocus32( 0 );
548 }
549
550 /**********************************************************************
551  *              EVENT_CheckFocus
552  */
553 BOOL32 EVENT_CheckFocus(void)
554 {
555     WND*   pWnd;
556     Window xW;
557     int    state;
558
559     XGetInputFocus(display, &xW, &state);
560     if( xW == None ||
561         XFindContext(display, xW, winContext, (char **)&pWnd) ) 
562         return FALSE;
563     return TRUE;
564 }
565
566 /**********************************************************************
567  *              EVENT_ConfigureNotify
568  *
569  * The ConfigureNotify event is only selected on the desktop window
570  * and on top-level windows when the -managed flag is used.
571  */
572 static void EVENT_ConfigureNotify( HWND32 hwnd, XConfigureEvent *event )
573 {
574     /* FIXME: with -desktop xxx we get this event _before_ desktop 
575      * window structure is created. WIN_GetDesktop() check is a hack.
576      */
577
578     if ( !WIN_GetDesktop() || hwnd == GetDesktopWindow32())
579     {
580         desktopX = event->x;
581         desktopY = event->y;
582     }
583     else
584     {
585         WND *wndPtr;
586         WINDOWPOS16 *winpos;
587         RECT16 newWindowRect, newClientRect;
588         HRGN32 hrgnOldPos, hrgnNewPos;
589
590         if (!(wndPtr = WIN_FindWndPtr( hwnd )) ||
591             !(wndPtr->flags & WIN_MANAGED) )
592             return;
593         
594         if (!(winpos = SEGPTR_NEW(WINDOWPOS16))) return;
595
596         /* Fill WINDOWPOS struct */
597         winpos->flags = SWP_NOACTIVATE | SWP_NOZORDER;
598         winpos->hwnd = hwnd;
599         winpos->x = event->x;
600         winpos->y = event->y;
601         winpos->cx = event->width;
602         winpos->cy = event->height;
603
604         /* Check for unchanged attributes */
605         if(winpos->x == wndPtr->rectWindow.left &&
606            winpos->y == wndPtr->rectWindow.top)
607             winpos->flags |= SWP_NOMOVE;
608         if(winpos->cx == wndPtr->rectWindow.right - wndPtr->rectWindow.left &&
609            winpos->cy == wndPtr->rectWindow.bottom - wndPtr->rectWindow.top)
610             winpos->flags |= SWP_NOSIZE;
611
612         /* Send WM_WINDOWPOSCHANGING */
613         SendMessage16(hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)SEGPTR_GET(winpos));
614
615         /* Calculate new position and size */
616         newWindowRect.left = event->x;
617         newWindowRect.right = event->x + event->width;
618         newWindowRect.top = event->y;
619         newWindowRect.bottom = event->y + event->height;
620
621         WINPOS_SendNCCalcSize( winpos->hwnd, TRUE, &newWindowRect,
622                                &wndPtr->rectWindow, &wndPtr->rectClient,
623                                SEGPTR_GET(winpos), &newClientRect );
624
625         hrgnOldPos = CreateRectRgnIndirect16( &wndPtr->rectWindow );
626         hrgnNewPos = CreateRectRgnIndirect16( &newWindowRect );
627         CombineRgn32( hrgnOldPos, hrgnOldPos, hrgnNewPos, RGN_DIFF );
628  
629         /* Set new size and position */
630         wndPtr->rectWindow = newWindowRect;
631         wndPtr->rectClient = newClientRect;
632         SendMessage16( hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)SEGPTR_GET(winpos));
633         SEGPTR_FREE(winpos);
634
635         /* full window drag leaves unrepainted garbage without this */
636         PAINT_RedrawWindow( 0, NULL, hrgnOldPos, RDW_INVALIDATE |
637                             RDW_ALLCHILDREN | RDW_ERASE | RDW_ERASENOW,
638                             RDW_C_USEHRGN );
639         DeleteObject32(hrgnOldPos);
640         DeleteObject32(hrgnNewPos);
641     }
642 }
643
644
645 /***********************************************************************
646  *           EVENT_SelectionRequest
647  */
648 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event )
649 {
650     XSelectionEvent result;
651     Atom            rprop = None;
652     Window          request = event->requestor;
653
654     if(event->target == XA_STRING)
655     {
656         HANDLE16 hText;
657         LPSTR  text;
658         int    size,i,j;
659
660         rprop = event->property;
661
662         if(rprop == None) rprop = event->target;
663
664         if(event->selection!=XA_PRIMARY) rprop = None;
665         else if(!CLIPBOARD_IsPresent(CF_OEMTEXT)) rprop = None;
666         else
667         {
668             /* open to make sure that clipboard is available */
669
670             BOOL32 couldOpen = OpenClipboard32( pWnd->hwndSelf );
671             char* lpstr = 0;
672
673             hText = GetClipboardData16(CF_TEXT);
674             text = GlobalLock16(hText);
675             size = GlobalSize16(hText);
676
677             /* remove carriage returns */
678
679             lpstr = (char*)xmalloc(size--);
680             for(i=0,j=0; i < size && text[i]; i++ )
681             {
682                if( text[i] == '\r' && 
683                   (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
684                lpstr[j++] = text[i];
685             }
686             lpstr[j]='\0';
687
688             XChangeProperty(display, request, rprop, 
689                             XA_STRING, 8, PropModeReplace, 
690                             lpstr, j);
691             free(lpstr);
692
693             /* close only if we opened before */
694
695             if(couldOpen) CloseClipboard32();
696         }
697     }
698
699     if(rprop==None) 
700        dprintf_event(stddeb,"Request for %s ignored\n", XGetAtomName(display,event->target));
701
702     result.type=SelectionNotify;
703     result.display=display;
704     result.requestor=request;
705     result.selection=event->selection;
706     result.property=rprop;
707     result.target=event->target;
708     result.time=event->time;
709     XSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
710 }
711
712
713 /***********************************************************************
714  *           EVENT_SelectionNotify
715  */
716 static void EVENT_SelectionNotify( XSelectionEvent *event )
717 {
718     if (event->selection != XA_PRIMARY) return;
719
720     if (event->target != XA_STRING) CLIPBOARD_ReadSelection( 0, None );
721     else CLIPBOARD_ReadSelection( event->requestor, event->property );
722
723     dprintf_clipboard(stddeb,"\tSelectionNotify done!\n");
724 }
725
726
727 /***********************************************************************
728  *           EVENT_SelectionClear
729  */
730 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event )
731 {
732     if (event->selection != XA_PRIMARY) return;
733     CLIPBOARD_ReleaseSelection( event->window, pWnd->hwndSelf ); 
734 }
735
736
737 /**********************************************************************
738  *           EVENT_ClientMessage
739  */
740 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event )
741 {
742     if (event->message_type != None && event->format == 32)
743     {
744        if ((event->message_type == wmProtocols) && 
745            (((Atom) event->data.l[0]) == wmDeleteWindow))
746           SendMessage16( pWnd->hwndSelf, WM_SYSCOMMAND, SC_CLOSE, 0 );
747        else if ( event->message_type == dndProtocol &&
748                 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
749        {
750           unsigned long         data_length;
751           unsigned long         aux_long;
752           unsigned char*        p_data = NULL;
753           union {
754                    Atom         atom_aux;
755                    POINT32      pt_aux;
756                    int          i;
757                 }               u;
758           int                   x, y;
759           BOOL16                bAccept;
760           HGLOBAL16             hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
761           LPDRAGINFO            lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
762           SEGPTR                spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
763           Window                w_aux_root, w_aux_child;
764           WND*                  pDropWnd;
765           
766           if( !lpDragInfo || !spDragInfo ) return;
767
768           XQueryPointer( display, pWnd->window, &w_aux_root, &w_aux_child, 
769                  &x, &y, &u.pt_aux.x, &u.pt_aux.y, (unsigned int*)&aux_long);
770
771           lpDragInfo->hScope = pWnd->hwndSelf;
772           lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
773
774           /* find out drop point and drop window */
775           if( x < 0 || y < 0 ||
776               x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
777               y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
778           {   bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
779           else
780           {
781               bAccept = DRAG_QueryUpdate( pWnd->hwndSelf, spDragInfo, TRUE );
782               x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
783           }
784           pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
785           GlobalFree16( hDragInfo );
786
787           if( bAccept )
788           {
789               XGetWindowProperty( display, DefaultRootWindow(display),
790                               dndSelection, 0, 65535, FALSE,
791                               AnyPropertyType, &u.atom_aux, &u.pt_aux.y,
792                              &data_length, &aux_long, &p_data);
793
794               if( !aux_long && p_data)  /* don't bother if > 64K */
795               {
796                 char *p = (char*) p_data;
797                 char *p_drop;
798
799                 aux_long = 0; 
800                 while( *p )     /* calculate buffer size */
801                 {
802                   p_drop = p;
803                   if((u.i = *p) != -1 ) 
804                       u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
805                   if( u.i == -1 ) *p = -1;      /* mark as "bad" */
806                   else
807                   {
808                       INT32 len = GetShortPathName32A( p, NULL, 0 );
809                       if (len) aux_long += len + 1;
810                       else *p = -1;
811                   }
812                   p += strlen(p) + 1;
813                 }
814                 if( aux_long && aux_long < 65535 )
815                 {
816                   HDROP16                 hDrop;
817                   LPDROPFILESTRUCT        lpDrop;
818
819                   aux_long += sizeof(DROPFILESTRUCT) + 1; 
820                   hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
821                   lpDrop = (LPDROPFILESTRUCT) GlobalLock16( hDrop );
822
823                   if( lpDrop )
824                   {
825                     lpDrop->wSize = sizeof(DROPFILESTRUCT);
826                     lpDrop->ptMousePos.x = (INT16)x;
827                     lpDrop->ptMousePos.y = (INT16)y;
828                     lpDrop->fInNonClientArea = (BOOL16) 
829                         ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left)  ||
830                           y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top)    ||
831                           x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
832                           y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
833                     p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT);
834                     p = p_data;
835                     while(*p)
836                     {
837                       if( *p != -1 )    /* use only "good" entries */
838                       {
839                           GetShortPathName32A( p, p_drop, 65535 );
840                           p_drop += strlen( p_drop ) + 1;
841                       }
842                       p += strlen(p) + 1;
843                     }
844                     *p_drop = '\0';
845                     PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
846                                    (WPARAM16)hDrop, 0L );
847                   }
848                 }
849               }
850               if( p_data ) XFree(p_data);  
851
852           } /* WS_EX_ACCEPTFILES */
853        } /* dndProtocol */
854        else
855           dprintf_event( stddeb, "unrecognized ClientMessage\n" );
856     }
857 }
858
859 /**********************************************************************
860  *           EVENT_EnterNotify
861  *
862  * Install colormap when Wine window is focused in
863  * self-managed mode with private colormap
864  */
865 /*
866   void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
867   {
868    if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
869      (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
870       XInstallColormap( display, COLOR_GetColormap() );
871   }
872  */ 
873
874 /**********************************************************************
875  *              EVENT_MapNotify
876  */
877 void EVENT_MapNotify( HWND32 hWnd, XMapEvent *event )
878 {
879     HWND32 hwndFocus = GetFocus32();
880
881     if (hwndFocus && IsChild32( hWnd, hwndFocus ))
882       FOCUS_SetXFocus( (HWND32)hwndFocus );
883
884     return;
885 }
886
887 /**********************************************************************
888  *              EVENT_Capture
889  * 
890  * We need this to be able to generate double click messages
891  * when menu code captures mouse in the window without CS_DBLCLK style.
892  */
893 HWND32 EVENT_Capture(HWND32 hwnd, INT16 ht)
894 {
895     Window win;
896     HWND32 capturePrev = captureWnd;
897
898     if (!hwnd)
899     {
900         XUngrabPointer(display, CurrentTime );
901         captureWnd = NULL; captureHT = 0; 
902     }
903     else if ((win = WIN_GetXWindow( hwnd )))
904     {
905         WND* wndPtr = WIN_FindWndPtr( hwnd );
906
907         if ( wndPtr && 
908              (XGrabPointer(display, win, False, 
909                            ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
910                            GrabModeAsync, GrabModeAsync,
911                            None, None, CurrentTime ) == GrabSuccess) )
912         {
913             dprintf_win(stddeb, "SetCapture(0x%04x)\n", hwnd );
914             captureWnd   = hwnd;
915             captureHT    = ht;
916         }
917     }
918
919     if( capturePrev && capturePrev != captureWnd )
920     {
921         WND* wndPtr = WIN_FindWndPtr( capturePrev );
922         if( wndPtr && (wndPtr->flags & WIN_ISWIN32) )
923             SendMessage32A( capturePrev, WM_CAPTURECHANGED, 0L, hwnd);
924     }
925     return capturePrev;
926 }
927
928 /**********************************************************************
929  *              EVENT_GetCaptureInfo
930  */
931 INT16 EVENT_GetCaptureInfo()
932 {
933     return captureHT;
934 }
935
936 /**********************************************************************
937  *              SetCapture16   (USER.18)
938  */
939 HWND16 SetCapture16( HWND16 hwnd )
940 {
941     return (HWND16)EVENT_Capture( hwnd, HTCLIENT );
942 }
943
944
945 /**********************************************************************
946  *              SetCapture32   (USER32.463)
947  */
948 HWND32 SetCapture32( HWND32 hwnd )
949 {
950     return EVENT_Capture( hwnd, HTCLIENT );
951 }
952
953
954 /**********************************************************************
955  *              ReleaseCapture   (USER.19) (USER32.438)
956  */
957 void ReleaseCapture(void)
958 {
959     dprintf_win(stddeb, "ReleaseCapture() [%04x]\n", captureWnd );
960     if( captureWnd ) EVENT_Capture( 0, 0 );
961 }
962
963
964 /**********************************************************************
965  *              GetCapture16   (USER.236)
966  */
967 HWND16 GetCapture16(void)
968 {
969     return captureWnd;
970 }
971
972
973 /**********************************************************************
974  *              GetCapture32   (USER32.207)
975  */
976 HWND32 GetCapture32(void)
977 {
978     return captureWnd;
979 }
980
981
982 /***********************************************************************
983  *           GetMouseEventProc   (USER.337)
984  */
985 FARPROC16 GetMouseEventProc(void)
986 {
987     HMODULE16 hmodule = GetModuleHandle16("USER");
988     return MODULE_GetEntryPoint( hmodule,
989                                  MODULE_GetOrdinal( hmodule, "Mouse_Event" ) );
990 }
991
992
993 /***********************************************************************
994  *           Mouse_Event   (USER.299)
995  */
996 void Mouse_Event( CONTEXT *context )
997 {
998     /* Register values:
999      * AX = mouse event
1000      * BX = horizontal displacement if AX & ME_MOVE
1001      * CX = vertical displacement if AX & ME_MOVE
1002      * DX = button state (?)
1003      * SI = mouse event flags (?)
1004      */
1005     Window root, child;
1006     int rootX, rootY, childX, childY;
1007     unsigned int state;
1008
1009     if (AX_reg(context) & ME_MOVE)
1010     {
1011         /* We have to actually move the cursor */
1012         XWarpPointer( display, rootWindow, None, 0, 0, 0, 0,
1013                       (short)BX_reg(context), (short)CX_reg(context) );
1014         return;
1015     }
1016     if (!XQueryPointer( display, rootWindow, &root, &child,
1017                         &rootX, &rootY, &childX, &childY, &state )) return;
1018     if (AX_reg(context) & ME_LDOWN)
1019         hardware_event( WM_LBUTTONDOWN, EVENT_XStateToKeyState( state ), 0L,
1020                         rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
1021     if (AX_reg(context) & ME_LUP)
1022         hardware_event( WM_LBUTTONUP, EVENT_XStateToKeyState( state ), 0L,
1023                         rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
1024     if (AX_reg(context) & ME_RDOWN)
1025         hardware_event( WM_RBUTTONDOWN, EVENT_XStateToKeyState( state ), 0L,
1026                         rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
1027     if (AX_reg(context) & ME_RUP)
1028         hardware_event( WM_RBUTTONUP, EVENT_XStateToKeyState( state ), 0L,
1029                         rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
1030 }
1031
1032
1033 /**********************************************************************
1034  *                      EnableHardwareInput   (USER.331)
1035  */
1036 BOOL16 EnableHardwareInput(BOOL16 bEnable)
1037 {
1038   BOOL16 bOldState = InputEnabled;
1039   dprintf_event(stdnimp,"EnableHardwareInput(%d);\n", bEnable);
1040   InputEnabled = bEnable;
1041   return bOldState;
1042 }
1043
1044
1045 /***********************************************************************
1046  *           SwapMouseButton16   (USER.186)
1047  */
1048 BOOL16 SwapMouseButton16( BOOL16 fSwap )
1049 {
1050     BOOL16 ret = SwappedButtons;
1051     SwappedButtons = fSwap;
1052     return ret;
1053 }
1054
1055
1056 /***********************************************************************
1057  *           SwapMouseButton32   (USER32.536)
1058  */
1059 BOOL32 SwapMouseButton32( BOOL32 fSwap )
1060 {
1061     BOOL32 ret = SwappedButtons;
1062     SwappedButtons = fSwap;
1063     return ret;
1064 }