Added more support for buddy windows in the updown control.
[wine/testsucceed.git] / windows / x11drv / event.c
bloba1e8161081654e96ea21b47e6ab36d90768cf6ae
1 /*
2 * X11 event driver
4 * Copyright 1993 Alexandre Julliard
5 */
7 #include "config.h"
9 #ifndef X_DISPLAY_MISSING
11 #include <X11/Xatom.h>
12 #include <X11/keysym.h>
13 #include "ts_xlib.h"
14 #include "ts_xresource.h"
15 #include "ts_xutil.h"
17 #include <assert.h>
18 #include <string.h>
19 #include "callback.h"
20 #include "clipboard.h"
21 #include "dce.h"
22 #include "debugtools.h"
23 #include "drive.h"
24 #include "heap.h"
25 #include "keyboard.h"
26 #include "message.h"
27 #include "mouse.h"
28 #include "options.h"
29 #include "queue.h"
30 #include "shell.h"
31 #include "winpos.h"
32 #include "services.h"
33 #include "file.h"
34 #include "windef.h"
35 #include "x11drv.h"
37 DECLARE_DEBUG_CHANNEL(event)
38 DECLARE_DEBUG_CHANNEL(win)
40 /* X context to associate a hwnd to an X window */
41 extern XContext winContext;
43 extern Atom wmProtocols;
44 extern Atom wmDeleteWindow;
45 extern Atom dndProtocol;
46 extern Atom dndSelection;
48 extern void X11DRV_KEYBOARD_UpdateState(void);
49 extern void X11DRV_KEYBOARD_HandleEvent(WND *pWnd, XKeyEvent *event);
51 #define NB_BUTTONS 3 /* Windows can handle 3 buttons */
53 #define DndNotDnd -1 /* OffiX drag&drop */
54 #define DndUnknown 0
55 #define DndRawData 1
56 #define DndFile 2
57 #define DndFiles 3
58 #define DndText 4
59 #define DndDir 5
60 #define DndLink 6
61 #define DndExe 7
63 #define DndEND 8
65 #define DndURL 128 /* KDE drag&drop */
67 /* The last X window which had the focus */
68 static Window glastXFocusWin = 0;
70 static const char * const event_names[] =
72 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
73 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
74 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
75 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
76 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
77 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
78 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
79 "ClientMessage", "MappingNotify"
82 static void CALLBACK EVENT_Flush( ULONG_PTR arg );
83 static void CALLBACK EVENT_ProcessAllEvents( ULONG_PTR arg );
84 static void EVENT_ProcessEvent( XEvent *event );
86 /* Event handlers */
87 static void EVENT_Key( HWND hWnd, XKeyEvent *event );
88 static void EVENT_ButtonPress( HWND hWnd, XButtonEvent *event );
89 static void EVENT_ButtonRelease( HWND hWnd, XButtonEvent *event );
90 static void EVENT_MotionNotify( HWND hWnd, XMotionEvent *event );
91 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event );
92 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event );
93 static void EVENT_Expose( HWND hWnd, XExposeEvent *event );
94 static void EVENT_GraphicsExpose( HWND hWnd, XGraphicsExposeEvent *event );
95 static void EVENT_ConfigureNotify( HWND hWnd, XConfigureEvent *event );
96 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event);
97 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event);
98 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event );
99 static void EVENT_MapNotify( HWND pWnd, XMapEvent *event );
100 static void EVENT_UnmapNotify( HWND pWnd, XUnmapEvent *event );
102 /* Usable only with OLVWM - compile option perhaps?
103 static void EVENT_EnterNotify( HWND hWnd, XCrossingEvent *event );
106 static void EVENT_GetGeometry( Window win, int *px, int *py,
107 unsigned int *pwidth, unsigned int *pheight );
110 static BOOL bUserRepaintDisabled = TRUE;
113 /***********************************************************************
114 * EVENT_Init
116 BOOL X11DRV_EVENT_Init(void)
118 /* Install the X event processing callback */
119 SERVICE_AddObject( FILE_DupUnixHandle( ConnectionNumber(display),
120 GENERIC_READ | SYNCHRONIZE ),
121 EVENT_ProcessAllEvents, 0 );
123 /* Install the XFlush timer callback */
124 if ( Options.synchronous )
125 TSXSynchronize( display, True );
126 else
127 SERVICE_AddTimer( 200000L, EVENT_Flush, 0 );
129 return TRUE;
132 /***********************************************************************
133 * EVENT_Flush
135 static void CALLBACK EVENT_Flush( ULONG_PTR arg )
137 TSXFlush( display );
140 /***********************************************************************
141 * EVENT_ProcessAllEvents
143 static void CALLBACK EVENT_ProcessAllEvents( ULONG_PTR arg )
145 XEvent event;
147 TRACE_(event)( "called.\n" );
149 EnterCriticalSection( &X11DRV_CritSection );
150 while ( XPending( display ) )
152 XNextEvent( display, &event );
154 LeaveCriticalSection( &X11DRV_CritSection );
155 EVENT_ProcessEvent( &event );
156 EnterCriticalSection( &X11DRV_CritSection );
158 LeaveCriticalSection( &X11DRV_CritSection );
161 /***********************************************************************
162 * EVENT_Synchronize
164 * Synchronize with the X server. Should not be used too often.
166 void X11DRV_EVENT_Synchronize( void )
168 TSXSync( display, False );
169 EVENT_ProcessAllEvents( 0 );
172 /***********************************************************************
173 * EVENT_UserRepaintDisable
175 void X11DRV_EVENT_UserRepaintDisable( BOOL bDisabled )
177 bUserRepaintDisabled = bDisabled;
180 /***********************************************************************
181 * EVENT_ProcessEvent
183 * Process an X event.
185 static void EVENT_ProcessEvent( XEvent *event )
187 HWND hWnd;
189 TRACE_(event)( "called.\n" );
191 switch (event->type)
193 case SelectionNotify: /* all of these should be caught by XCheckTypedWindowEvent() */
194 FIXME_(event)("Got SelectionNotify - must not happen!\n");
195 /* fall through */
197 /* We get all these because of StructureNotifyMask.
198 This check is placed here to avoid getting error messages below,
199 as X might send some of these even for windows that have already
200 been deleted ... */
201 case CirculateNotify:
202 case CreateNotify:
203 case DestroyNotify:
204 case GravityNotify:
205 case ReparentNotify:
206 return;
209 if ( TSXFindContext( display, event->xany.window, winContext,
210 (char **)&hWnd ) != 0) {
211 if ( event->type == ClientMessage) {
212 /* query window (drag&drop event contains only drag window) */
213 Window root, child;
214 int root_x, root_y, child_x, child_y;
215 unsigned u;
216 TSXQueryPointer( display, X11DRV_GetXRootWindow(), &root, &child,
217 &root_x, &root_y, &child_x, &child_y, &u);
218 if (TSXFindContext( display, child, winContext, (char **)&hWnd ) != 0)
219 return;
220 } else {
221 hWnd = 0; /* Not for a registered window */
225 if ( !hWnd && event->xany.window != X11DRV_GetXRootWindow() )
226 ERR_(event)("Got event %s for unknown Window %08lx\n",
227 event_names[event->type], event->xany.window );
228 else
229 TRACE_(event)("Got event %s for hwnd %04x\n",
230 event_names[event->type], hWnd );
233 switch(event->type)
235 case KeyPress:
236 case KeyRelease:
237 EVENT_Key( hWnd, (XKeyEvent*)event );
238 break;
240 case ButtonPress:
241 EVENT_ButtonPress( hWnd, (XButtonEvent*)event );
242 break;
244 case ButtonRelease:
245 EVENT_ButtonRelease( hWnd, (XButtonEvent*)event );
246 break;
248 case MotionNotify:
249 /* Wine between two fast machines across the overloaded campus
250 ethernet gets very boged down in MotionEvents. The following
251 simply finds the last motion event in the queue and drops
252 the rest. On a good link events are servered before they build
253 up so this doesn't take place. On a slow link this may cause
254 problems if the event order is important. I'm not yet seen
255 of any problems. Jon 7/6/96.
257 while (TSXCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
258 MotionNotify, event));
259 EVENT_MotionNotify( hWnd, (XMotionEvent*)event );
260 break;
262 case FocusIn:
264 WND *pWndLastFocus = 0;
265 XWindowAttributes win_attr;
266 BOOL bIsDisabled;
267 XFocusChangeEvent *xfocChange = (XFocusChangeEvent*)event;
269 if (!hWnd || bUserRepaintDisabled) return;
271 bIsDisabled = GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED;
273 /* If the window has been disabled and we are in managed mode,
274 * revert the X focus back to the last focus window. This is to disallow
275 * the window manager from switching focus away while the app is
276 * in a modal state.
278 if ( Options.managed && bIsDisabled && glastXFocusWin)
280 /* Change focus only if saved focus window is registered and viewable */
281 if ( TSXFindContext( xfocChange->display, glastXFocusWin, winContext,
282 (char **)&pWndLastFocus ) == 0 )
284 if ( TSXGetWindowAttributes( display, glastXFocusWin, &win_attr ) &&
285 (win_attr.map_state == IsViewable) )
287 TSXSetInputFocus( xfocChange->display, glastXFocusWin, RevertToParent, CurrentTime );
288 EVENT_Synchronize();
289 break;
294 EVENT_FocusIn( hWnd, xfocChange );
295 break;
298 case FocusOut:
300 /* Save the last window which had the focus */
301 XFocusChangeEvent *xfocChange = (XFocusChangeEvent*)event;
302 glastXFocusWin = xfocChange->window;
303 if (!hWnd || bUserRepaintDisabled) return;
304 EVENT_FocusOut( hWnd, (XFocusChangeEvent*)event );
305 break;
308 case Expose:
309 if (bUserRepaintDisabled) return;
310 EVENT_Expose( hWnd, (XExposeEvent *)event );
311 break;
313 case GraphicsExpose:
314 if (bUserRepaintDisabled) return;
315 EVENT_GraphicsExpose( hWnd, (XGraphicsExposeEvent *)event );
316 break;
318 case ConfigureNotify:
319 if (!hWnd || bUserRepaintDisabled) return;
320 EVENT_ConfigureNotify( hWnd, (XConfigureEvent*)event );
321 break;
323 case SelectionRequest:
324 if (!hWnd || bUserRepaintDisabled) return;
325 EVENT_SelectionRequest( hWnd, (XSelectionRequestEvent *)event );
326 break;
328 case SelectionClear:
329 if (!hWnd || bUserRepaintDisabled) return;
330 EVENT_SelectionClear( hWnd, (XSelectionClearEvent*) event );
331 break;
333 case ClientMessage:
334 if (!hWnd || bUserRepaintDisabled) return;
335 EVENT_ClientMessage( hWnd, (XClientMessageEvent *) event );
336 break;
338 #if 0
339 case EnterNotify:
340 EVENT_EnterNotify( hWnd, (XCrossingEvent *) event );
341 break;
342 #endif
344 case NoExpose:
345 break;
347 case MapNotify:
348 if (!hWnd || bUserRepaintDisabled) return;
349 EVENT_MapNotify( hWnd, (XMapEvent *)event );
350 break;
352 case UnmapNotify:
353 if (!hWnd || bUserRepaintDisabled) return;
354 EVENT_UnmapNotify( hWnd, (XUnmapEvent *)event );
355 break;
357 default:
358 WARN_(event)("Unprocessed event %s for hwnd %04x\n",
359 event_names[event->type], hWnd );
360 break;
364 /***********************************************************************
365 * EVENT_QueryZOrder
367 * Synchronize internal z-order with the window manager's.
369 static BOOL __check_query_condition( WND** pWndA, WND** pWndB )
371 /* return TRUE if we have at least two managed windows */
373 for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
374 if( (*pWndA)->flags & WIN_MANAGED &&
375 (*pWndA)->dwStyle & WS_VISIBLE ) break;
376 if( *pWndA )
377 for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
378 if( (*pWndB)->flags & WIN_MANAGED &&
379 (*pWndB)->dwStyle & WS_VISIBLE ) break;
380 return ((*pWndB) != NULL);
383 static Window __get_common_ancestor( Window A, Window B,
384 Window** children, unsigned* total )
386 /* find the real root window */
388 Window root, *childrenB;
389 unsigned totalB;
393 TSXQueryTree( display, A, &root, &A, children, total );
394 TSXQueryTree( display, B, &root, &B, &childrenB, &totalB );
395 if( childrenB ) TSXFree( childrenB );
396 if( *children ) TSXFree( *children ), *children = NULL;
397 } while( A != B && A && B );
399 if( A && B )
401 TSXQueryTree( display, A, &root, &B, children, total );
402 return A;
404 return 0 ;
407 static Window __get_top_decoration( Window w, Window ancestor )
409 Window* children, root, prev = w, parent = w;
410 unsigned total;
414 w = parent;
415 TSXQueryTree( display, w, &root, &parent, &children, &total );
416 if( children ) TSXFree( children );
417 } while( parent && parent != ancestor );
418 TRACE_(event)("\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
419 return ( parent ) ? w : 0 ;
422 static unsigned __td_lookup( Window w, Window* list, unsigned max )
424 unsigned i;
425 for( i = max - 1; i >= 0; i-- ) if( list[i] == w ) break;
426 return i;
429 static HWND EVENT_QueryZOrder( HWND hWndCheck)
431 HWND hwndInsertAfter = HWND_TOP;
432 WND *pWndCheck = WIN_FindWndPtr(hWndCheck);
433 WND *pDesktop = WIN_GetDesktop();
434 WND *pWnd, *pWndZ = WIN_LockWndPtr(pDesktop->child);
435 Window w, parent, *children = NULL;
436 unsigned total, check, pos, best;
438 if( !__check_query_condition(&pWndZ, &pWnd) )
440 WIN_ReleaseWndPtr(pWndCheck);
441 WIN_ReleaseWndPtr(pDesktop->child);
442 WIN_ReleaseDesktop();
443 return hwndInsertAfter;
445 WIN_LockWndPtr(pWndZ);
446 WIN_LockWndPtr(pWnd);
447 WIN_ReleaseWndPtr(pDesktop->child);
448 WIN_ReleaseDesktop();
450 parent = __get_common_ancestor( X11DRV_WND_GetXWindow(pWndZ),
451 X11DRV_WND_GetXWindow(pWnd),
452 &children, &total );
453 if( parent && children )
455 /* w is the ancestor if pWndCheck that is a direct descendant of 'parent' */
457 w = __get_top_decoration( X11DRV_WND_GetXWindow(pWndCheck), parent );
459 if( w != children[total-1] ) /* check if at the top */
461 /* X child at index 0 is at the bottom, at index total-1 is at the top */
462 check = __td_lookup( w, children, total );
463 best = total;
465 for( WIN_UpdateWndPtr(&pWnd,pWndZ); pWnd;WIN_UpdateWndPtr(&pWnd,pWnd->next))
467 /* go through all windows in Wine z-order... */
469 if( pWnd != pWndCheck )
471 if( !(pWnd->flags & WIN_MANAGED) ||
472 !(w = __get_top_decoration( X11DRV_WND_GetXWindow(pWnd), parent )) )
473 continue;
474 pos = __td_lookup( w, children, total );
475 if( pos < best && pos > check )
477 /* find a nearest Wine window precedes
478 * pWndCheck in the real z-order... */
479 best = pos;
480 hwndInsertAfter = pWnd->hwndSelf;
482 if( best - check == 1 ) break;
487 if( children ) TSXFree( children );
488 WIN_ReleaseWndPtr(pWnd);
489 WIN_ReleaseWndPtr(pWndZ);
490 WIN_ReleaseWndPtr(pWndCheck);
491 return hwndInsertAfter;
494 /***********************************************************************
495 * EVENT_XStateToKeyState
497 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
498 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
500 static WORD EVENT_XStateToKeyState( int state )
502 int kstate = 0;
504 if (state & Button1Mask) kstate |= MK_LBUTTON;
505 if (state & Button2Mask) kstate |= MK_MBUTTON;
506 if (state & Button3Mask) kstate |= MK_RBUTTON;
507 if (state & ShiftMask) kstate |= MK_SHIFT;
508 if (state & ControlMask) kstate |= MK_CONTROL;
509 return kstate;
512 /***********************************************************************
513 * X11DRV_EVENT_QueryPointer
515 BOOL X11DRV_EVENT_QueryPointer(DWORD *posX, DWORD *posY, DWORD *state)
517 Window root, child;
518 int rootX, rootY, winX, winY;
519 unsigned int xstate;
521 if (!TSXQueryPointer( display, X11DRV_GetXRootWindow(), &root, &child,
522 &rootX, &rootY, &winX, &winY, &xstate ))
523 return FALSE;
525 if(posX)
526 *posX = (DWORD)winX;
527 if(posY)
528 *posY = (DWORD)winY;
529 if(state)
530 *state = EVENT_XStateToKeyState( xstate );
532 return TRUE;
535 /***********************************************************************
536 * EVENT_Expose
538 static void EVENT_Expose( HWND hWnd, XExposeEvent *event )
540 RECT rect;
542 WND *pWnd = WIN_FindWndPtr(hWnd);
543 /* Make position relative to client area instead of window */
544 rect.left = event->x - (pWnd? (pWnd->rectClient.left - pWnd->rectWindow.left) : 0);
545 rect.top = event->y - (pWnd? (pWnd->rectClient.top - pWnd->rectWindow.top) : 0);
546 rect.right = rect.left + event->width;
547 rect.bottom = rect.top + event->height;
548 WIN_ReleaseWndPtr(pWnd);
550 Callout.RedrawWindow( hWnd, &rect, 0,
551 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
552 (event->count ? 0 : RDW_ERASENOW) );
556 /***********************************************************************
557 * EVENT_GraphicsExpose
559 * This is needed when scrolling area is partially obscured
560 * by non-Wine X window.
562 static void EVENT_GraphicsExpose( HWND hWnd, XGraphicsExposeEvent *event )
564 RECT rect;
565 WND *pWnd = WIN_FindWndPtr(hWnd);
567 /* Make position relative to client area instead of window */
568 rect.left = event->x - (pWnd? (pWnd->rectClient.left - pWnd->rectWindow.left) : 0);
569 rect.top = event->y - (pWnd? (pWnd->rectClient.top - pWnd->rectWindow.top) : 0);
570 rect.right = rect.left + event->width;
571 rect.bottom = rect.top + event->height;
573 WIN_ReleaseWndPtr(pWnd);
575 Callout.RedrawWindow( hWnd, &rect, 0,
576 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
577 (event->count ? 0 : RDW_ERASENOW) );
581 /***********************************************************************
582 * EVENT_Key
584 * Handle a X key event
586 static void EVENT_Key( HWND hWnd, XKeyEvent *event )
588 WND *pWnd = WIN_FindWndPtr(hWnd);
589 X11DRV_KEYBOARD_HandleEvent( pWnd, event );
590 WIN_ReleaseWndPtr(pWnd);
595 /***********************************************************************
596 * EVENT_MotionNotify
598 static void EVENT_MotionNotify( HWND hWnd, XMotionEvent *event )
600 WND *pWnd = WIN_FindWndPtr(hWnd);
601 int xOffset = pWnd? pWnd->rectWindow.left : 0;
602 int yOffset = pWnd? pWnd->rectWindow.top : 0;
603 WIN_ReleaseWndPtr(pWnd);
605 MOUSE_SendEvent( MOUSEEVENTF_MOVE,
606 xOffset + event->x, yOffset + event->y,
607 EVENT_XStateToKeyState( event->state ),
608 event->time - MSG_WineStartTicks,
609 hWnd);
613 /***********************************************************************
614 * EVENT_ButtonPress
616 static void EVENT_ButtonPress( HWND hWnd, XButtonEvent *event )
618 static WORD statusCodes[NB_BUTTONS] =
619 { MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_RIGHTDOWN };
620 int buttonNum = event->button - 1;
622 WND *pWnd = WIN_FindWndPtr(hWnd);
623 int xOffset = pWnd? pWnd->rectWindow.left : 0;
624 int yOffset = pWnd? pWnd->rectWindow.top : 0;
625 WORD keystate;
627 WIN_ReleaseWndPtr(pWnd);
629 if (buttonNum >= NB_BUTTONS) return;
632 * Get the compatible keystate
634 keystate = EVENT_XStateToKeyState( event->state );
637 * Make sure that the state of the button that was just
638 * pressed is "down".
640 switch (buttonNum)
642 case 0:
643 keystate |= MK_LBUTTON;
644 break;
645 case 1:
646 keystate |= MK_MBUTTON;
647 break;
648 case 2:
649 keystate |= MK_RBUTTON;
650 break;
653 MOUSE_SendEvent( statusCodes[buttonNum],
654 xOffset + event->x, yOffset + event->y,
655 keystate,
656 event->time - MSG_WineStartTicks,
657 hWnd);
661 /***********************************************************************
662 * EVENT_ButtonRelease
664 static void EVENT_ButtonRelease( HWND hWnd, XButtonEvent *event )
666 static WORD statusCodes[NB_BUTTONS] =
667 { MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_RIGHTUP };
668 int buttonNum = event->button - 1;
669 WND *pWnd = WIN_FindWndPtr(hWnd);
670 int xOffset = pWnd? pWnd->rectWindow.left : 0;
671 int yOffset = pWnd? pWnd->rectWindow.top : 0;
672 WORD keystate;
674 WIN_ReleaseWndPtr(pWnd);
676 if (buttonNum >= NB_BUTTONS) return;
679 * Get the compatible keystate
681 keystate = EVENT_XStateToKeyState( event->state );
684 * Make sure that the state of the button that was just
685 * released is "up".
687 switch (buttonNum)
689 case 0:
690 keystate &= ~MK_LBUTTON;
691 break;
692 case 1:
693 keystate &= ~MK_MBUTTON;
694 break;
695 case 2:
696 keystate &= ~MK_RBUTTON;
697 break;
700 MOUSE_SendEvent( statusCodes[buttonNum],
701 xOffset + event->x, yOffset + event->y,
702 keystate,
703 event->time - MSG_WineStartTicks,
704 hWnd);
708 /**********************************************************************
709 * EVENT_FocusIn
711 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event )
713 if (event->detail != NotifyPointer)
714 if (hWnd != GetForegroundWindow())
716 SetForegroundWindow( hWnd );
717 X11DRV_KEYBOARD_UpdateState();
722 /**********************************************************************
723 * EVENT_FocusOut
725 * Note: only top-level override-redirect windows get FocusOut events.
727 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event )
729 if (event->detail != NotifyPointer)
730 if (hWnd == GetForegroundWindow())
732 SendMessageA( hWnd, WM_CANCELMODE, 0, 0 );
733 SetForegroundWindow( 0 );
737 /**********************************************************************
738 * X11DRV_EVENT_CheckFocus
740 BOOL X11DRV_EVENT_CheckFocus(void)
742 HWND hWnd;
743 Window xW;
744 int state;
746 TSXGetInputFocus(display, &xW, &state);
747 if( xW == None ||
748 TSXFindContext(display, xW, winContext, (char **)&hWnd) )
749 return FALSE;
750 return TRUE;
753 /**********************************************************************
754 * EVENT_GetGeometry
756 * Helper function for ConfigureNotify handling.
757 * Get the new geometry of a window relative to the root window.
759 static void EVENT_GetGeometry( Window win, int *px, int *py,
760 unsigned int *pwidth, unsigned int *pheight )
762 Window root, top;
763 int x, y, width, height, border, depth;
765 EnterCriticalSection( &X11DRV_CritSection );
767 /* Get the geometry of the window */
768 XGetGeometry( display, win, &root, &x, &y, &width, &height,
769 &border, &depth );
771 /* Translate the window origin to root coordinates */
772 XTranslateCoordinates( display, win, root, 0, 0, &x, &y, &top );
774 LeaveCriticalSection( &X11DRV_CritSection );
776 *px = x;
777 *py = y;
778 *pwidth = width;
779 *pheight = height;
782 /**********************************************************************
783 * EVENT_ConfigureNotify
785 * The ConfigureNotify event is only selected on top-level windows
786 * when the -managed flag is used.
788 static void EVENT_ConfigureNotify( HWND hWnd, XConfigureEvent *event )
790 RECT rectWindow;
791 int x, y, flags = 0;
792 unsigned int width, height;
793 HWND newInsertAfter, oldInsertAfter;
795 /* Get geometry and Z-order according to X */
797 EVENT_GetGeometry( event->window, &x, &y, &width, &height );
798 newInsertAfter = EVENT_QueryZOrder( hWnd );
800 /* Get geometry and Z-order according to Wine */
802 GetWindowRect( hWnd, &rectWindow );
803 oldInsertAfter = GetWindow( hWnd, GW_HWNDPREV );
804 if ( !oldInsertAfter ) oldInsertAfter = HWND_TOP;
806 /* Compare what has changed */
808 if ( rectWindow.left == x && rectWindow.top == y )
809 flags |= SWP_NOMOVE;
810 else
811 TRACE_(win)( "%04x moving from (%d,%d) to (%d,%d)\n", hWnd,
812 rectWindow.left, rectWindow.top, x, y );
814 if ( rectWindow.right - rectWindow.left == width
815 && rectWindow.bottom - rectWindow.top == height )
816 flags |= SWP_NOSIZE;
817 else
818 TRACE_(win)( "%04x resizing from (%d,%d) to (%d,%d)\n", hWnd,
819 rectWindow.right - rectWindow.left,
820 rectWindow.bottom - rectWindow.top, width, height );
822 if ( newInsertAfter == oldInsertAfter )
823 flags |= SWP_NOZORDER;
824 else
825 TRACE_(win)( "%04x restacking from after %04x to after %04x\n", hWnd,
826 oldInsertAfter, newInsertAfter );
828 /* If anything changed, call SetWindowPos */
830 if ( flags != (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER) )
831 SetWindowPos( hWnd, newInsertAfter, x, y, width, height,
832 flags | SWP_NOACTIVATE | SWP_WINE_NOHOSTMOVE );
836 /***********************************************************************
837 * EVENT_SelectionRequest
839 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event )
841 XSelectionEvent result;
842 Atom rprop = None;
843 Window request = event->requestor;
845 if(event->target == XA_STRING)
847 HANDLE16 hText;
848 LPSTR text;
849 int size,i,j;
851 rprop = event->property;
853 if( rprop == None )
854 rprop = event->target;
856 if( event->selection != XA_PRIMARY )
857 rprop = None;
858 else
859 if( !CLIPBOARD_IsPresent(CF_OEMTEXT) )
860 rprop = None;
861 else
863 /* open to make sure that clipboard is available */
865 BOOL couldOpen = OpenClipboard( hWnd );
866 char* lpstr = 0;
868 hText = GetClipboardData16(CF_TEXT);
869 text = GlobalLock16(hText);
870 size = GlobalSize16(hText);
872 /* remove carriage returns */
874 lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
875 for(i=0,j=0; i < size && text[i]; i++ )
877 if( text[i] == '\r' &&
878 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
879 lpstr[j++] = text[i];
881 lpstr[j]='\0';
883 TSXChangeProperty(display, request, rprop,
884 XA_STRING, 8, PropModeReplace,
885 lpstr, j);
886 HeapFree( GetProcessHeap(), 0, lpstr );
888 /* close only if we opened before */
890 if(couldOpen) CloseClipboard();
894 if( rprop == None)
895 TRACE_(event)("Request for %s ignored\n", TSXGetAtomName(display,event->target));
897 /* reply to sender */
899 result.type = SelectionNotify;
900 result.display = display;
901 result.requestor = request;
902 result.selection = event->selection;
903 result.property = rprop;
904 result.target = event->target;
905 result.time = event->time;
906 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
909 /***********************************************************************
910 * EVENT_SelectionClear
912 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
914 if (event->selection != XA_PRIMARY) return;
915 X11DRV_CLIPBOARD_ReleaseSelection( event->window, hWnd );
919 /**********************************************************************
920 * EVENT_DropFromOffix
922 * don't know if it still works (last Changlog is from 96/11/04)
924 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
926 unsigned long data_length;
927 unsigned long aux_long;
928 unsigned char* p_data = NULL;
929 union {
930 Atom atom_aux;
931 struct {
932 int x;
933 int y;
934 } pt_aux;
935 int i;
936 } u;
937 int x, y;
938 BOOL16 bAccept;
939 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
940 LPDRAGINFO lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
941 SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
942 Window w_aux_root, w_aux_child;
943 WND* pDropWnd;
944 WND* pWnd;
946 if( !lpDragInfo || !spDragInfo ) return;
948 pWnd = WIN_FindWndPtr(hWnd);
950 TSXQueryPointer( display, X11DRV_WND_GetXWindow(pWnd), &w_aux_root, &w_aux_child,
951 &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
952 (unsigned int*)&aux_long);
954 lpDragInfo->hScope = hWnd;
955 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
957 /* find out drop point and drop window */
958 if( x < 0 || y < 0 ||
959 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
960 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
961 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
962 else
964 bAccept = DRAG_QueryUpdate( hWnd, spDragInfo, TRUE );
965 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
967 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
968 WIN_ReleaseWndPtr(pWnd);
970 GlobalFree16( hDragInfo );
972 if( bAccept )
974 TSXGetWindowProperty( display, DefaultRootWindow(display),
975 dndSelection, 0, 65535, FALSE,
976 AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
977 &data_length, &aux_long, &p_data);
979 if( !aux_long && p_data) /* don't bother if > 64K */
981 char *p = (char*) p_data;
982 char *p_drop;
984 aux_long = 0;
985 while( *p ) /* calculate buffer size */
987 p_drop = p;
988 if((u.i = *p) != -1 )
989 u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
990 if( u.i == -1 ) *p = -1; /* mark as "bad" */
991 else
993 INT len = GetShortPathNameA( p, NULL, 0 );
994 if (len) aux_long += len + 1;
995 else *p = -1;
997 p += strlen(p) + 1;
999 if( aux_long && aux_long < 65535 )
1001 HDROP16 hDrop;
1002 LPDROPFILESTRUCT16 lpDrop;
1004 aux_long += sizeof(DROPFILESTRUCT16) + 1;
1005 hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
1006 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop );
1008 if( lpDrop )
1010 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1011 lpDrop->ptMousePos.x = (INT16)x;
1012 lpDrop->ptMousePos.y = (INT16)y;
1013 lpDrop->fInNonClientArea = (BOOL16)
1014 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1015 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1016 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1017 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1018 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1019 p = p_data;
1020 while(*p)
1022 if( *p != -1 ) /* use only "good" entries */
1024 GetShortPathNameA( p, p_drop, 65535 );
1025 p_drop += strlen( p_drop ) + 1;
1027 p += strlen(p) + 1;
1029 *p_drop = '\0';
1030 PostMessage16( hWnd, WM_DROPFILES,
1031 (WPARAM16)hDrop, 0L );
1035 if( p_data ) TSXFree(p_data);
1037 } /* WS_EX_ACCEPTFILES */
1039 WIN_ReleaseWndPtr(pDropWnd);
1042 /**********************************************************************
1043 * EVENT_DropURLs
1045 * drop items are separated by \n
1046 * each item is prefixed by its mime type
1048 * event->data.l[3], event->data.l[4] contains drop x,y position
1050 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1052 WND *pDropWnd;
1053 WND *pWnd;
1054 unsigned long data_length;
1055 unsigned long aux_long, drop_len = 0;
1056 unsigned char *p_data = NULL; /* property data */
1057 char *p_drop = NULL;
1058 char *p, *next;
1059 int x, y, drop32 = FALSE ;
1060 union {
1061 Atom atom_aux;
1062 int i;
1063 Window w_aux;
1064 } u; /* unused */
1065 union {
1066 HDROP16 h16;
1067 HDROP h32;
1068 } hDrop;
1070 pWnd = WIN_FindWndPtr(hWnd);
1071 drop32 = pWnd->flags & WIN_ISWIN32;
1073 if (!(pWnd->dwExStyle & WS_EX_ACCEPTFILES))
1075 WIN_ReleaseWndPtr(pWnd);
1076 return;
1078 WIN_ReleaseWndPtr(pWnd);
1080 TSXGetWindowProperty( display, DefaultRootWindow(display),
1081 dndSelection, 0, 65535, FALSE,
1082 AnyPropertyType, &u.atom_aux, &u.i,
1083 &data_length, &aux_long, &p_data);
1084 if (aux_long)
1085 WARN_(event)("property too large, truncated!\n");
1086 TRACE_(event)("urls=%s\n", p_data);
1088 if( !aux_long && p_data) { /* don't bother if > 64K */
1089 /* calculate length */
1090 p = p_data;
1091 next = strchr(p, '\n');
1092 while (p) {
1093 if (next) *next=0;
1094 if (strncmp(p,"file:",5) == 0 ) {
1095 INT len = GetShortPathNameA( p+5, NULL, 0 );
1096 if (len) drop_len += len + 1;
1098 if (next) {
1099 *next = '\n';
1100 p = next + 1;
1101 next = strchr(p, '\n');
1102 } else {
1103 p = NULL;
1107 if( drop_len && drop_len < 65535 ) {
1108 TSXQueryPointer( display, X11DRV_GetXRootWindow(), &u.w_aux, &u.w_aux,
1109 &x, &y, &u.i, &u.i, &u.i);
1111 pDropWnd = WIN_FindWndPtr( hWnd );
1113 if (drop32) {
1114 LPDROPFILESTRUCT lpDrop;
1115 drop_len += sizeof(DROPFILESTRUCT) + 1;
1116 hDrop.h32 = (HDROP)GlobalAlloc( GMEM_SHARE, drop_len );
1117 lpDrop = (LPDROPFILESTRUCT) GlobalLock( hDrop.h32 );
1119 if( lpDrop ) {
1120 lpDrop->lSize = sizeof(DROPFILESTRUCT);
1121 lpDrop->ptMousePos.x = (INT)x;
1122 lpDrop->ptMousePos.y = (INT)y;
1123 lpDrop->fInNonClientArea = (BOOL)
1124 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1125 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1126 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1127 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1128 lpDrop->fWideChar = FALSE;
1129 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT);
1131 } else {
1132 LPDROPFILESTRUCT16 lpDrop;
1133 drop_len += sizeof(DROPFILESTRUCT16) + 1;
1134 hDrop.h16 = (HDROP16)GlobalAlloc16( GMEM_SHARE, drop_len );
1135 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop.h16 );
1137 if( lpDrop ) {
1138 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1139 lpDrop->ptMousePos.x = (INT16)x;
1140 lpDrop->ptMousePos.y = (INT16)y;
1141 lpDrop->fInNonClientArea = (BOOL16)
1142 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1143 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1144 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1145 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1146 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1150 /* create message content */
1151 if (p_drop) {
1152 p = p_data;
1153 next = strchr(p, '\n');
1154 while (p) {
1155 if (next) *next=0;
1156 if (strncmp(p,"file:",5) == 0 ) {
1157 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1158 if (len) {
1159 TRACE_(event)("drop file %s as %s\n", p+5, p_drop);
1160 p_drop += len+1;
1161 } else {
1162 WARN_(event)("can't convert file %s to dos name \n", p+5);
1164 } else {
1165 WARN_(event)("unknown mime type %s\n", p);
1167 if (next) {
1168 *next = '\n';
1169 p = next + 1;
1170 next = strchr(p, '\n');
1171 } else {
1172 p = NULL;
1174 *p_drop = '\0';
1177 if (drop32) {
1178 /* can not use PostMessage32A because it is currently based on
1179 * PostMessage16 and WPARAM32 would be truncated to WPARAM16
1181 GlobalUnlock(hDrop.h32);
1182 SendMessageA( hWnd, WM_DROPFILES,
1183 (WPARAM)hDrop.h32, 0L );
1184 } else {
1185 GlobalUnlock16(hDrop.h16);
1186 PostMessage16( hWnd, WM_DROPFILES,
1187 (WPARAM16)hDrop.h16, 0L );
1190 WIN_ReleaseWndPtr(pDropWnd);
1192 if( p_data ) TSXFree(p_data);
1196 /**********************************************************************
1197 * EVENT_ClientMessage
1199 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
1201 if (event->message_type != None && event->format == 32) {
1202 if ((event->message_type == wmProtocols) &&
1203 (((Atom) event->data.l[0]) == wmDeleteWindow))
1205 /* Ignore the delete window request if the window has been disabled
1206 * and we are in managed mode. This is to disallow applications from
1207 * being closed by the window manager while in a modal state.
1209 BOOL bIsDisabled;
1210 bIsDisabled = GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED;
1212 if ( !Options.managed || !bIsDisabled )
1213 SendMessage16( hWnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
1215 else if ( event->message_type == dndProtocol &&
1216 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
1217 EVENT_DropFromOffiX(hWnd, event);
1218 else if ( event->message_type == dndProtocol &&
1219 event->data.l[0] == DndURL )
1220 EVENT_DropURLs(hWnd, event);
1221 else {
1222 #if 0
1223 /* enable this if you want to see the message */
1224 unsigned char* p_data = NULL;
1225 union {
1226 unsigned long l;
1227 int i;
1228 Atom atom;
1229 } u; /* unused */
1230 TSXGetWindowProperty( display, DefaultRootWindow(display),
1231 dndSelection, 0, 65535, FALSE,
1232 AnyPropertyType, &u.atom, &u.i,
1233 &u.l, &u.l, &p_data);
1234 TRACE_(event)("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1235 event->message_type, event->data.l[0], event->data.l[1],
1236 event->data.l[2], event->data.l[3], event->data.l[4],
1237 p_data);
1238 #endif
1239 TRACE_(event)("unrecognized ClientMessage\n" );
1244 /**********************************************************************
1245 * EVENT_EnterNotify
1247 * Install colormap when Wine window is focused in
1248 * self-managed mode with private colormap
1250 #if 0
1251 void EVENT_EnterNotify( HWND hWnd, XCrossingEvent *event )
1253 if( !Options.managed && X11DRV_GetXRootWindow() == DefaultRootWindow(display) &&
1254 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus() )
1255 TSXInstallColormap( display, X11DRV_PALETTE_GetColormap() );
1257 #endif
1259 /**********************************************************************
1260 * EVENT_MapNotify
1262 void EVENT_MapNotify( HWND hWnd, XMapEvent *event )
1264 HWND hwndFocus = GetFocus();
1265 WND *wndFocus = WIN_FindWndPtr(hwndFocus);
1266 WND *pWnd = WIN_FindWndPtr(hWnd);
1267 if (pWnd->flags & WIN_MANAGED)
1268 pWnd->dwStyle &= ~WS_MINIMIZE;
1269 WIN_ReleaseWndPtr(pWnd);
1271 if (hwndFocus && IsChild( hWnd, hwndFocus ))
1272 X11DRV_WND_SetFocus(wndFocus);
1274 WIN_ReleaseWndPtr(wndFocus);
1276 return;
1280 /**********************************************************************
1281 * EVENT_MapNotify
1283 void EVENT_UnmapNotify( HWND hWnd, XUnmapEvent *event )
1285 WND *pWnd = WIN_FindWndPtr(hWnd);
1286 if (pWnd->flags & WIN_MANAGED)
1288 EndMenu();
1289 if( pWnd->dwStyle & WS_VISIBLE )
1290 pWnd->dwStyle |= WS_MINIMIZE;
1292 WIN_ReleaseWndPtr(pWnd);
1296 #endif /* !defined(X_DISPLAY_MISSING) */