Release 990523.
[wine/multimedia.git] / windows / x11drv / event.c
blobc4d41df7a19bc28599849df5e22aeff455efc806
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 "class.h"
21 #include "clipboard.h"
22 #include "dce.h"
23 #include "dde_proc.h"
24 #include "debugtools.h"
25 #include "drive.h"
26 #include "heap.h"
27 #include "keyboard.h"
28 #include "message.h"
29 #include "mouse.h"
30 #include "options.h"
31 #include "queue.h"
32 #include "shell.h"
33 #include "winpos.h"
34 #include "services.h"
35 #include "file.h"
36 #include "windef.h"
37 #include "x11drv.h"
39 DECLARE_DEBUG_CHANNEL(event)
40 DECLARE_DEBUG_CHANNEL(win)
42 /* X context to associate a hwnd to an X window */
43 extern XContext winContext;
45 extern Atom wmProtocols;
46 extern Atom wmDeleteWindow;
47 extern Atom dndProtocol;
48 extern Atom dndSelection;
50 extern void X11DRV_KEYBOARD_UpdateState(void);
51 extern void X11DRV_KEYBOARD_HandleEvent(WND *pWnd, XKeyEvent *event);
53 #define NB_BUTTONS 3 /* Windows can handle 3 buttons */
55 #define DndNotDnd -1 /* OffiX drag&drop */
56 #define DndUnknown 0
57 #define DndRawData 1
58 #define DndFile 2
59 #define DndFiles 3
60 #define DndText 4
61 #define DndDir 5
62 #define DndLink 6
63 #define DndExe 7
65 #define DndEND 8
67 #define DndURL 128 /* KDE drag&drop */
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_ProcessAllEvents( ULONG_PTR arg );
83 static void EVENT_ProcessEvent( XEvent *event );
85 /* Event handlers */
86 static void EVENT_Key( HWND hWnd, XKeyEvent *event );
87 static void EVENT_ButtonPress( HWND hWnd, XButtonEvent *event );
88 static void EVENT_ButtonRelease( HWND hWnd, XButtonEvent *event );
89 static void EVENT_MotionNotify( HWND hWnd, XMotionEvent *event );
90 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event );
91 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event );
92 static void EVENT_Expose( HWND hWnd, XExposeEvent *event );
93 static void EVENT_GraphicsExpose( HWND hWnd, XGraphicsExposeEvent *event );
94 static void EVENT_ConfigureNotify( HWND hWnd, XConfigureEvent *event );
95 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event);
96 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event);
97 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event );
98 static void EVENT_MapNotify( HWND pWnd, XMapEvent *event );
99 static void EVENT_UnmapNotify( HWND pWnd, XUnmapEvent *event );
101 /* Usable only with OLVWM - compile option perhaps?
102 static void EVENT_EnterNotify( HWND hWnd, XCrossingEvent *event );
105 static void EVENT_GetGeometry( Window win, int *px, int *py,
106 unsigned int *pwidth, unsigned int *pheight );
109 static BOOL bUserRepaintDisabled = TRUE;
112 /***********************************************************************
113 * EVENT_Init
115 BOOL X11DRV_EVENT_Init(void)
117 /* Install the X event processing callback */
118 SERVICE_AddObject( FILE_DupUnixHandle( ConnectionNumber(display),
119 GENERIC_READ | SYNCHRONIZE ),
120 EVENT_ProcessAllEvents, 0 );
121 return TRUE;
124 /***********************************************************************
125 * EVENT_ProcessAllEvents
127 static void CALLBACK EVENT_ProcessAllEvents( ULONG_PTR arg )
129 XEvent event;
131 TRACE_(event)( "called.\n" );
133 EnterCriticalSection( &X11DRV_CritSection );
134 while ( XPending( display ) )
136 XNextEvent( display, &event );
138 LeaveCriticalSection( &X11DRV_CritSection );
139 EVENT_ProcessEvent( &event );
140 EnterCriticalSection( &X11DRV_CritSection );
142 LeaveCriticalSection( &X11DRV_CritSection );
145 /***********************************************************************
146 * EVENT_Synchronize
148 * Synchronize with the X server. Should not be used too often.
150 void X11DRV_EVENT_Synchronize( BOOL bProcessEvents )
152 TSXSync( display, False );
154 if ( bProcessEvents )
155 EVENT_ProcessAllEvents( 0 );
158 /***********************************************************************
159 * EVENT_UserRepaintDisable
161 void X11DRV_EVENT_UserRepaintDisable( BOOL bDisabled )
163 bUserRepaintDisabled = bDisabled;
166 /***********************************************************************
167 * EVENT_ProcessEvent
169 * Process an X event.
171 static void EVENT_ProcessEvent( XEvent *event )
173 HWND hWnd;
175 TRACE_(event)( "called.\n" );
177 switch (event->type)
179 case SelectionNotify: /* all of these should be caught by XCheckTypedWindowEvent() */
180 FIXME_(event)("Got SelectionNotify - must not happen!\n");
181 /* fall through */
183 /* We get all these because of StructureNotifyMask.
184 This check is placed here to avoid getting error messages below,
185 as X might send some of these even for windows that have already
186 been deleted ... */
187 case CirculateNotify:
188 case CreateNotify:
189 case DestroyNotify:
190 case GravityNotify:
191 case ReparentNotify:
192 return;
195 if ( TSXFindContext( display, event->xany.window, winContext,
196 (char **)&hWnd ) != 0) {
197 if ( event->type == ClientMessage) {
198 /* query window (drag&drop event contains only drag window) */
199 Window root, child;
200 int root_x, root_y, child_x, child_y;
201 unsigned u;
202 TSXQueryPointer( display, X11DRV_GetXRootWindow(), &root, &child,
203 &root_x, &root_y, &child_x, &child_y, &u);
204 if (TSXFindContext( display, child, winContext, (char **)&hWnd ) != 0)
205 return;
206 } else {
207 hWnd = 0; /* Not for a registered window */
211 if ( !hWnd && event->xany.window != X11DRV_GetXRootWindow() )
212 ERR_(event)("Got event %s for unknown Window %08lx\n",
213 event_names[event->type], event->xany.window );
214 else
215 TRACE_(event)("Got event %s for hwnd %04x\n",
216 event_names[event->type], hWnd );
219 switch(event->type)
221 case KeyPress:
222 case KeyRelease:
223 EVENT_Key( hWnd, (XKeyEvent*)event );
224 break;
226 case ButtonPress:
227 EVENT_ButtonPress( hWnd, (XButtonEvent*)event );
228 break;
230 case ButtonRelease:
231 EVENT_ButtonRelease( hWnd, (XButtonEvent*)event );
232 break;
234 case MotionNotify:
235 /* Wine between two fast machines across the overloaded campus
236 ethernet gets very boged down in MotionEvents. The following
237 simply finds the last motion event in the queue and drops
238 the rest. On a good link events are servered before they build
239 up so this doesn't take place. On a slow link this may cause
240 problems if the event order is important. I'm not yet seen
241 of any problems. Jon 7/6/96.
243 while (TSXCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
244 MotionNotify, event));
245 EVENT_MotionNotify( hWnd, (XMotionEvent*)event );
246 break;
248 case FocusIn:
249 if (!hWnd || bUserRepaintDisabled) return;
250 EVENT_FocusIn( hWnd, (XFocusChangeEvent*)event );
251 break;
253 case FocusOut:
254 if (!hWnd || bUserRepaintDisabled) return;
255 EVENT_FocusOut( hWnd, (XFocusChangeEvent*)event );
256 break;
258 case Expose:
259 if (bUserRepaintDisabled) return;
260 EVENT_Expose( hWnd, (XExposeEvent *)event );
261 break;
263 case GraphicsExpose:
264 if (bUserRepaintDisabled) return;
265 EVENT_GraphicsExpose( hWnd, (XGraphicsExposeEvent *)event );
266 break;
268 case ConfigureNotify:
269 if (!hWnd || bUserRepaintDisabled) return;
270 EVENT_ConfigureNotify( hWnd, (XConfigureEvent*)event );
271 break;
273 case SelectionRequest:
274 if (!hWnd || bUserRepaintDisabled) return;
275 EVENT_SelectionRequest( hWnd, (XSelectionRequestEvent *)event );
276 break;
278 case SelectionClear:
279 if (!hWnd || bUserRepaintDisabled) return;
280 EVENT_SelectionClear( hWnd, (XSelectionClearEvent*) event );
281 break;
283 case ClientMessage:
284 if (!hWnd || bUserRepaintDisabled) return;
285 EVENT_ClientMessage( hWnd, (XClientMessageEvent *) event );
286 break;
288 #if 0
289 case EnterNotify:
290 EVENT_EnterNotify( hWnd, (XCrossingEvent *) event );
291 break;
292 #endif
294 case NoExpose:
295 break;
297 case MapNotify:
298 if (!hWnd || bUserRepaintDisabled) return;
299 EVENT_MapNotify( hWnd, (XMapEvent *)event );
300 break;
302 case UnmapNotify:
303 if (!hWnd || bUserRepaintDisabled) return;
304 EVENT_UnmapNotify( hWnd, (XUnmapEvent *)event );
305 break;
307 default:
308 WARN_(event)("Unprocessed event %s for hwnd %04x\n",
309 event_names[event->type], hWnd );
310 break;
314 /***********************************************************************
315 * EVENT_QueryZOrder
317 * Synchronize internal z-order with the window manager's.
319 static BOOL __check_query_condition( WND** pWndA, WND** pWndB )
321 /* return TRUE if we have at least two managed windows */
323 for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
324 if( (*pWndA)->flags & WIN_MANAGED &&
325 (*pWndA)->dwStyle & WS_VISIBLE ) break;
326 if( *pWndA )
327 for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
328 if( (*pWndB)->flags & WIN_MANAGED &&
329 (*pWndB)->dwStyle & WS_VISIBLE ) break;
330 return ((*pWndB) != NULL);
333 static Window __get_common_ancestor( Window A, Window B,
334 Window** children, unsigned* total )
336 /* find the real root window */
338 Window root, *childrenB;
339 unsigned totalB;
343 TSXQueryTree( display, A, &root, &A, children, total );
344 TSXQueryTree( display, B, &root, &B, &childrenB, &totalB );
345 if( childrenB ) TSXFree( childrenB );
346 if( *children ) TSXFree( *children );
347 } while( A != B && A && B );
349 if( A && B )
351 TSXQueryTree( display, A, &root, &B, children, total );
352 return A;
354 return 0 ;
357 static Window __get_top_decoration( Window w, Window ancestor )
359 Window* children, root, prev = w, parent = w;
360 unsigned total;
364 w = parent;
365 TSXQueryTree( display, w, &root, &parent, &children, &total );
366 if( children ) TSXFree( children );
367 } while( parent && parent != ancestor );
368 TRACE_(event)("\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
369 return ( parent ) ? w : 0 ;
372 static unsigned __td_lookup( Window w, Window* list, unsigned max )
374 unsigned i;
375 for( i = max - 1; i >= 0; i-- ) if( list[i] == w ) break;
376 return i;
379 static BOOL EVENT_QueryZOrder( HWND hWndCheck)
381 BOOL bRet = FALSE;
382 HWND hwndInsertAfter = HWND_TOP;
383 WND *pWndCheck = WIN_FindWndPtr(hWndCheck);
384 WND *pDesktop = WIN_GetDesktop();
385 WND *pWnd, *pWndZ = WIN_LockWndPtr(pDesktop->child);
386 Window w, parent, *children = NULL;
387 unsigned total, check, pos, best;
389 if( !__check_query_condition(&pWndZ, &pWnd) )
391 WIN_ReleaseWndPtr(pWndCheck);
392 WIN_ReleaseWndPtr(pDesktop->child);
393 WIN_ReleaseDesktop();
394 return TRUE;
396 WIN_LockWndPtr(pWndZ);
397 WIN_LockWndPtr(pWnd);
398 WIN_ReleaseWndPtr(pDesktop->child);
399 WIN_ReleaseDesktop();
401 parent = __get_common_ancestor( X11DRV_WND_GetXWindow(pWndZ),
402 X11DRV_WND_GetXWindow(pWnd),
403 &children, &total );
404 if( parent && children )
406 /* w is the ancestor if pWndCheck that is a direct descendant of 'parent' */
408 w = __get_top_decoration( X11DRV_WND_GetXWindow(pWndCheck), parent );
410 if( w != children[total-1] ) /* check if at the top */
412 /* X child at index 0 is at the bottom, at index total-1 is at the top */
413 check = __td_lookup( w, children, total );
414 best = total;
416 for( WIN_UpdateWndPtr(&pWnd,pWndZ); pWnd;WIN_UpdateWndPtr(&pWnd,pWnd->next))
418 /* go through all windows in Wine z-order... */
420 if( pWnd != pWndCheck )
422 if( !(pWnd->flags & WIN_MANAGED) ||
423 !(w = __get_top_decoration( X11DRV_WND_GetXWindow(pWnd), parent )) )
424 continue;
425 pos = __td_lookup( w, children, total );
426 if( pos < best && pos > check )
428 /* find a nearest Wine window precedes
429 * pWndCheck in the real z-order... */
430 best = pos;
431 hwndInsertAfter = pWnd->hwndSelf;
433 if( best - check == 1 ) break;
436 /* and link pWndCheck right behind it in the local z-order */
438 WIN_UnlinkWindow( pWndCheck->hwndSelf );
439 WIN_LinkWindow( pWndCheck->hwndSelf, hwndInsertAfter);
441 if( children ) TSXFree( children );
442 WIN_ReleaseWndPtr(pWnd);
443 WIN_ReleaseWndPtr(pWndZ);
444 WIN_ReleaseWndPtr(pWndCheck);
445 return bRet;
448 /***********************************************************************
449 * EVENT_XStateToKeyState
451 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
452 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
454 static WORD EVENT_XStateToKeyState( int state )
456 int kstate = 0;
458 if (state & Button1Mask) kstate |= MK_LBUTTON;
459 if (state & Button2Mask) kstate |= MK_MBUTTON;
460 if (state & Button3Mask) kstate |= MK_RBUTTON;
461 if (state & ShiftMask) kstate |= MK_SHIFT;
462 if (state & ControlMask) kstate |= MK_CONTROL;
463 return kstate;
466 /***********************************************************************
467 * X11DRV_EVENT_QueryPointer
469 BOOL X11DRV_EVENT_QueryPointer(DWORD *posX, DWORD *posY, DWORD *state)
471 Window root, child;
472 int rootX, rootY, winX, winY;
473 unsigned int xstate;
475 if (!TSXQueryPointer( display, X11DRV_GetXRootWindow(), &root, &child,
476 &rootX, &rootY, &winX, &winY, &xstate ))
477 return FALSE;
479 if(posX)
480 *posX = (DWORD)winX;
481 if(posY)
482 *posY = (DWORD)winY;
483 if(state)
484 *state = EVENT_XStateToKeyState( xstate );
486 return TRUE;
489 /***********************************************************************
490 * EVENT_Expose
492 static void EVENT_Expose( HWND hWnd, XExposeEvent *event )
494 RECT rect;
496 WND *pWnd = WIN_FindWndPtr(hWnd);
497 /* Make position relative to client area instead of window */
498 rect.left = event->x - (pWnd? (pWnd->rectClient.left - pWnd->rectWindow.left) : 0);
499 rect.top = event->y - (pWnd? (pWnd->rectClient.top - pWnd->rectWindow.top) : 0);
500 rect.right = rect.left + event->width;
501 rect.bottom = rect.top + event->height;
502 WIN_ReleaseWndPtr(pWnd);
504 Callout.RedrawWindow( hWnd, &rect, 0,
505 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
506 (event->count ? 0 : RDW_ERASENOW) );
510 /***********************************************************************
511 * EVENT_GraphicsExpose
513 * This is needed when scrolling area is partially obscured
514 * by non-Wine X window.
516 static void EVENT_GraphicsExpose( HWND hWnd, XGraphicsExposeEvent *event )
518 RECT rect;
519 WND *pWnd = WIN_FindWndPtr(hWnd);
521 /* Make position relative to client area instead of window */
522 rect.left = event->x - (pWnd? (pWnd->rectClient.left - pWnd->rectWindow.left) : 0);
523 rect.top = event->y - (pWnd? (pWnd->rectClient.top - pWnd->rectWindow.top) : 0);
524 rect.right = rect.left + event->width;
525 rect.bottom = rect.top + event->height;
527 WIN_ReleaseWndPtr(pWnd);
529 Callout.RedrawWindow( hWnd, &rect, 0,
530 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
531 (event->count ? 0 : RDW_ERASENOW) );
535 /***********************************************************************
536 * EVENT_Key
538 * Handle a X key event
540 static void EVENT_Key( HWND hWnd, XKeyEvent *event )
542 WND *pWnd = WIN_FindWndPtr(hWnd);
543 X11DRV_KEYBOARD_HandleEvent( pWnd, event );
544 WIN_ReleaseWndPtr(pWnd);
549 /***********************************************************************
550 * EVENT_MotionNotify
552 static void EVENT_MotionNotify( HWND hWnd, XMotionEvent *event )
554 WND *pWnd = WIN_FindWndPtr(hWnd);
555 int xOffset = pWnd? pWnd->rectWindow.left : 0;
556 int yOffset = pWnd? pWnd->rectWindow.top : 0;
557 WIN_ReleaseWndPtr(pWnd);
559 MOUSE_SendEvent( MOUSEEVENTF_MOVE,
560 xOffset + event->x, yOffset + event->y,
561 EVENT_XStateToKeyState( event->state ),
562 event->time - MSG_WineStartTicks,
563 hWnd);
567 /***********************************************************************
568 * X11DRV_EVENT_DummyMotionNotify
570 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
572 void X11DRV_EVENT_DummyMotionNotify(void)
574 DWORD winX, winY, state;
576 if ( EVENT_QueryPointer( &winX, &winY, &state ) )
578 MOUSE_SendEvent( MOUSEEVENTF_MOVE, winX, winY, state,
579 GetTickCount(), 0 );
584 /***********************************************************************
585 * EVENT_ButtonPress
587 static void EVENT_ButtonPress( HWND hWnd, XButtonEvent *event )
589 static WORD statusCodes[NB_BUTTONS] =
590 { MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_RIGHTDOWN };
591 int buttonNum = event->button - 1;
593 WND *pWnd = WIN_FindWndPtr(hWnd);
594 int xOffset = pWnd? pWnd->rectWindow.left : 0;
595 int yOffset = pWnd? pWnd->rectWindow.top : 0;
596 WORD keystate;
598 WIN_ReleaseWndPtr(pWnd);
600 if (buttonNum >= NB_BUTTONS) return;
603 * Get the compatible keystate
605 keystate = EVENT_XStateToKeyState( event->state );
608 * Make sure that the state of the button that was just
609 * pressed is "down".
611 switch (buttonNum)
613 case 0:
614 keystate |= MK_LBUTTON;
615 break;
616 case 1:
617 keystate |= MK_MBUTTON;
618 break;
619 case 2:
620 keystate |= MK_RBUTTON;
621 break;
624 MOUSE_SendEvent( statusCodes[buttonNum],
625 xOffset + event->x, yOffset + event->y,
626 keystate,
627 event->time - MSG_WineStartTicks,
628 hWnd);
632 /***********************************************************************
633 * EVENT_ButtonRelease
635 static void EVENT_ButtonRelease( HWND hWnd, XButtonEvent *event )
637 static WORD statusCodes[NB_BUTTONS] =
638 { MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_RIGHTUP };
639 int buttonNum = event->button - 1;
640 WND *pWnd = WIN_FindWndPtr(hWnd);
641 int xOffset = pWnd? pWnd->rectWindow.left : 0;
642 int yOffset = pWnd? pWnd->rectWindow.top : 0;
643 WORD keystate;
645 WIN_ReleaseWndPtr(pWnd);
647 if (buttonNum >= NB_BUTTONS) return;
650 * Get the compatible keystate
652 keystate = EVENT_XStateToKeyState( event->state );
655 * Make sure that the state of the button that was just
656 * released is "up".
658 switch (buttonNum)
660 case 0:
661 keystate &= ~MK_LBUTTON;
662 break;
663 case 1:
664 keystate &= ~MK_MBUTTON;
665 break;
666 case 2:
667 keystate &= ~MK_RBUTTON;
668 break;
671 MOUSE_SendEvent( statusCodes[buttonNum],
672 xOffset + event->x, yOffset + event->y,
673 keystate,
674 event->time - MSG_WineStartTicks,
675 hWnd);
679 /**********************************************************************
680 * EVENT_FocusIn
682 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event )
684 if (Options.managed) EVENT_QueryZOrder( hWnd );
686 if (event->detail != NotifyPointer)
688 if (hWnd != GetActiveWindow())
690 WINPOS_ChangeActiveWindow( hWnd, FALSE );
691 X11DRV_KEYBOARD_UpdateState();
693 if ((hWnd != GetFocus()) && !IsChild( hWnd, GetFocus()))
694 SetFocus( hWnd );
699 /**********************************************************************
700 * EVENT_FocusOut
702 * Note: only top-level override-redirect windows get FocusOut events.
704 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event )
706 if (event->detail != NotifyPointer)
708 if (hWnd == GetActiveWindow())
710 SendMessageA( hWnd, WM_CANCELMODE, 0, 0 );
711 WINPOS_ChangeActiveWindow( 0, FALSE );
713 if ((hWnd == GetFocus()) || IsChild( hWnd, GetFocus()))
714 SetFocus( 0 );
718 /**********************************************************************
719 * X11DRV_EVENT_CheckFocus
721 BOOL X11DRV_EVENT_CheckFocus(void)
723 WND* pWnd;
724 Window xW;
725 int state;
727 TSXGetInputFocus(display, &xW, &state);
728 if( xW == None ||
729 TSXFindContext(display, xW, winContext, (char **)&pWnd) )
730 return FALSE;
731 return TRUE;
734 /**********************************************************************
735 * EVENT_GetGeometry
737 * Helper function for ConfigureNotify handling.
738 * Get the new geometry of a window relative to the root window.
740 static void EVENT_GetGeometry( Window win, int *px, int *py,
741 unsigned int *pwidth, unsigned int *pheight )
743 Window root, parent, *children;
744 int xpos, ypos;
745 unsigned int width, height, border, depth, nb_children;
747 if (!TSXGetGeometry( display, win, &root, px, py, pwidth, pheight,
748 &border, &depth )) return;
749 if (win == X11DRV_GetXRootWindow())
751 *px = *py = 0;
752 return;
755 for (;;)
757 if (!TSXQueryTree(display, win, &root, &parent, &children, &nb_children))
758 return;
759 TSXFree( children );
760 if (parent == X11DRV_GetXRootWindow()) break;
761 win = parent;
762 if (!TSXGetGeometry( display, win, &root, &xpos, &ypos,
763 &width, &height, &border, &depth )) return;
764 *px += xpos;
765 *py += ypos;
770 /**********************************************************************
771 * EVENT_ConfigureNotify
773 * The ConfigureNotify event is only selected on top-level windows
774 * when the -managed flag is used.
776 static void EVENT_ConfigureNotify( HWND hWnd, XConfigureEvent *event )
778 WINDOWPOS winpos;
779 RECT newWindowRect, newClientRect;
780 RECT oldWindowRect, oldClientRect;
781 Window above = event->above;
782 int x, y;
783 unsigned int width, height;
785 WND *pWnd = WIN_FindWndPtr(hWnd);
786 assert (pWnd->flags & WIN_MANAGED);
788 /* We don't rely on the event geometry info, because it is relative
789 * to parent and not to root, and it may be wrong (XFree sets x,y to 0,0
790 * if the window hasn't moved).
792 EVENT_GetGeometry( event->window, &x, &y, &width, &height );
794 TRACE_(win)("%04x adjusted to (%i,%i)-(%i,%i)\n", pWnd->hwndSelf,
795 x, y, x + width, y + height );
797 /* Fill WINDOWPOS struct */
798 winpos.flags = SWP_NOACTIVATE | SWP_NOZORDER;
799 winpos.hwnd = hWnd;
800 winpos.x = x;
801 winpos.y = y;
802 winpos.cx = width;
803 winpos.cy = height;
805 /* Check for unchanged attributes */
806 if (winpos.x == pWnd->rectWindow.left && winpos.y == pWnd->rectWindow.top)
807 winpos.flags |= SWP_NOMOVE;
808 if ((winpos.cx == pWnd->rectWindow.right - pWnd->rectWindow.left) &&
809 (winpos.cy == pWnd->rectWindow.bottom - pWnd->rectWindow.top))
810 winpos.flags |= SWP_NOSIZE;
811 else
813 RECT rect;
815 rect.left = 0;
816 rect.top = 0;
817 rect.right = pWnd->rectWindow.right - pWnd->rectWindow.left;
818 rect.bottom = pWnd->rectWindow.bottom - pWnd->rectWindow.top;
820 DCE_InvalidateDCE( pWnd, &rect );
823 /* Send WM_WINDOWPOSCHANGING */
824 SendMessageA( winpos.hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)&winpos );
826 if (!IsWindow( winpos.hwnd ))
828 WIN_ReleaseWndPtr(pWnd);
829 return;
832 /* Calculate new position and size */
833 newWindowRect.left = x;
834 newWindowRect.right = x + width;
835 newWindowRect.top = y;
836 newWindowRect.bottom = y + height;
838 WINPOS_SendNCCalcSize( winpos.hwnd, TRUE, &newWindowRect,
839 &pWnd->rectWindow, &pWnd->rectClient,
840 &winpos, &newClientRect );
842 if (!IsWindow( winpos.hwnd ))
844 WIN_ReleaseWndPtr(pWnd);
845 return;
848 oldWindowRect = pWnd->rectWindow;
849 oldClientRect = pWnd->rectClient;
851 /* Set new size and position */
852 pWnd->rectWindow = newWindowRect;
853 pWnd->rectClient = newClientRect;
855 /* FIXME: Copy valid bits */
857 if( oldClientRect.top - oldWindowRect.top != newClientRect.top - newWindowRect.top ||
858 oldClientRect.left - oldWindowRect.left != newClientRect.left - newWindowRect.left )
859 RedrawWindow( winpos.hwnd, NULL, 0, RDW_FRAME | RDW_ALLCHILDREN |
860 RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW );
862 WIN_ReleaseWndPtr(pWnd);
864 SendMessageA( winpos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)&winpos );
866 if (!IsWindow( winpos.hwnd )) return;
867 if( above == None ) /* absolute bottom */
869 WIN_UnlinkWindow( winpos.hwnd );
870 WIN_LinkWindow( winpos.hwnd, HWND_BOTTOM);
872 else EVENT_QueryZOrder( hWnd ); /* try to outsmart window manager */
876 /***********************************************************************
877 * EVENT_SelectionRequest
879 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event )
881 XSelectionEvent result;
882 Atom rprop = None;
883 Window request = event->requestor;
885 if(event->target == XA_STRING)
887 HANDLE16 hText;
888 LPSTR text;
889 int size,i,j;
891 rprop = event->property;
893 if( rprop == None )
894 rprop = event->target;
896 if( event->selection != XA_PRIMARY )
897 rprop = None;
898 else
899 if( !CLIPBOARD_IsPresent(CF_OEMTEXT) )
900 rprop = None;
901 else
903 /* open to make sure that clipboard is available */
905 BOOL couldOpen = OpenClipboard( hWnd );
906 char* lpstr = 0;
908 hText = GetClipboardData16(CF_TEXT);
909 text = GlobalLock16(hText);
910 size = GlobalSize16(hText);
912 /* remove carriage returns */
914 lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
915 for(i=0,j=0; i < size && text[i]; i++ )
917 if( text[i] == '\r' &&
918 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
919 lpstr[j++] = text[i];
921 lpstr[j]='\0';
923 TSXChangeProperty(display, request, rprop,
924 XA_STRING, 8, PropModeReplace,
925 lpstr, j);
926 HeapFree( GetProcessHeap(), 0, lpstr );
928 /* close only if we opened before */
930 if(couldOpen) CloseClipboard();
934 if( rprop == None)
935 TRACE_(event)("Request for %s ignored\n", TSXGetAtomName(display,event->target));
937 /* reply to sender */
939 result.type = SelectionNotify;
940 result.display = display;
941 result.requestor = request;
942 result.selection = event->selection;
943 result.property = rprop;
944 result.target = event->target;
945 result.time = event->time;
946 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
949 /***********************************************************************
950 * EVENT_SelectionClear
952 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
954 if (event->selection != XA_PRIMARY) return;
955 X11DRV_CLIPBOARD_ReleaseSelection( event->window, hWnd );
959 /**********************************************************************
960 * EVENT_DropFromOffix
962 * don't know if it still works (last Changlog is from 96/11/04)
964 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
966 unsigned long data_length;
967 unsigned long aux_long;
968 unsigned char* p_data = NULL;
969 union {
970 Atom atom_aux;
971 struct {
972 int x;
973 int y;
974 } pt_aux;
975 int i;
976 } u;
977 int x, y;
978 BOOL16 bAccept;
979 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
980 LPDRAGINFO lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
981 SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
982 Window w_aux_root, w_aux_child;
983 WND* pDropWnd;
984 WND* pWnd;
986 if( !lpDragInfo || !spDragInfo ) return;
988 pWnd = WIN_FindWndPtr(hWnd);
990 TSXQueryPointer( display, X11DRV_WND_GetXWindow(pWnd), &w_aux_root, &w_aux_child,
991 &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
992 (unsigned int*)&aux_long);
994 lpDragInfo->hScope = hWnd;
995 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
997 /* find out drop point and drop window */
998 if( x < 0 || y < 0 ||
999 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1000 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1001 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1002 else
1004 bAccept = DRAG_QueryUpdate( hWnd, spDragInfo, TRUE );
1005 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1007 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1008 WIN_ReleaseWndPtr(pWnd);
1010 GlobalFree16( hDragInfo );
1012 if( bAccept )
1014 TSXGetWindowProperty( display, DefaultRootWindow(display),
1015 dndSelection, 0, 65535, FALSE,
1016 AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
1017 &data_length, &aux_long, &p_data);
1019 if( !aux_long && p_data) /* don't bother if > 64K */
1021 char *p = (char*) p_data;
1022 char *p_drop;
1024 aux_long = 0;
1025 while( *p ) /* calculate buffer size */
1027 p_drop = p;
1028 if((u.i = *p) != -1 )
1029 u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
1030 if( u.i == -1 ) *p = -1; /* mark as "bad" */
1031 else
1033 INT len = GetShortPathNameA( p, NULL, 0 );
1034 if (len) aux_long += len + 1;
1035 else *p = -1;
1037 p += strlen(p) + 1;
1039 if( aux_long && aux_long < 65535 )
1041 HDROP16 hDrop;
1042 LPDROPFILESTRUCT16 lpDrop;
1044 aux_long += sizeof(DROPFILESTRUCT16) + 1;
1045 hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
1046 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop );
1048 if( lpDrop )
1050 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1051 lpDrop->ptMousePos.x = (INT16)x;
1052 lpDrop->ptMousePos.y = (INT16)y;
1053 lpDrop->fInNonClientArea = (BOOL16)
1054 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1055 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1056 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1057 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1058 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1059 p = p_data;
1060 while(*p)
1062 if( *p != -1 ) /* use only "good" entries */
1064 GetShortPathNameA( p, p_drop, 65535 );
1065 p_drop += strlen( p_drop ) + 1;
1067 p += strlen(p) + 1;
1069 *p_drop = '\0';
1070 PostMessage16( hWnd, WM_DROPFILES,
1071 (WPARAM16)hDrop, 0L );
1075 if( p_data ) TSXFree(p_data);
1077 } /* WS_EX_ACCEPTFILES */
1079 WIN_ReleaseWndPtr(pDropWnd);
1082 /**********************************************************************
1083 * EVENT_DropURLs
1085 * drop items are separated by \n
1086 * each item is prefixed by its mime type
1088 * event->data.l[3], event->data.l[4] contains drop x,y position
1090 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1092 WND *pDropWnd;
1093 WND *pWnd;
1094 unsigned long data_length;
1095 unsigned long aux_long, drop_len = 0;
1096 unsigned char *p_data = NULL; /* property data */
1097 char *p_drop = NULL;
1098 char *p, *next;
1099 int x, y, drop32 = FALSE ;
1100 union {
1101 Atom atom_aux;
1102 int i;
1103 Window w_aux;
1104 } u; /* unused */
1105 union {
1106 HDROP16 h16;
1107 HDROP h32;
1108 } hDrop;
1110 pWnd = WIN_FindWndPtr(hWnd);
1111 drop32 = pWnd->flags & WIN_ISWIN32;
1113 if (!(pWnd->dwExStyle & WS_EX_ACCEPTFILES))
1115 WIN_ReleaseWndPtr(pWnd);
1116 return;
1118 WIN_ReleaseWndPtr(pWnd);
1120 TSXGetWindowProperty( display, DefaultRootWindow(display),
1121 dndSelection, 0, 65535, FALSE,
1122 AnyPropertyType, &u.atom_aux, &u.i,
1123 &data_length, &aux_long, &p_data);
1124 if (aux_long)
1125 WARN_(event)("property too large, truncated!\n");
1126 TRACE_(event)("urls=%s\n", p_data);
1128 if( !aux_long && p_data) { /* don't bother if > 64K */
1129 /* calculate length */
1130 p = p_data;
1131 next = strchr(p, '\n');
1132 while (p) {
1133 if (next) *next=0;
1134 if (strncmp(p,"file:",5) == 0 ) {
1135 INT len = GetShortPathNameA( p+5, NULL, 0 );
1136 if (len) drop_len += len + 1;
1138 if (next) {
1139 *next = '\n';
1140 p = next + 1;
1141 next = strchr(p, '\n');
1142 } else {
1143 p = NULL;
1147 if( drop_len && drop_len < 65535 ) {
1148 TSXQueryPointer( display, X11DRV_GetXRootWindow(), &u.w_aux, &u.w_aux,
1149 &x, &y, &u.i, &u.i, &u.i);
1151 pDropWnd = WIN_FindWndPtr( hWnd );
1153 if (drop32) {
1154 LPDROPFILESTRUCT lpDrop;
1155 drop_len += sizeof(DROPFILESTRUCT) + 1;
1156 hDrop.h32 = (HDROP)GlobalAlloc( GMEM_SHARE, drop_len );
1157 lpDrop = (LPDROPFILESTRUCT) GlobalLock( hDrop.h32 );
1159 if( lpDrop ) {
1160 lpDrop->lSize = sizeof(DROPFILESTRUCT);
1161 lpDrop->ptMousePos.x = (INT)x;
1162 lpDrop->ptMousePos.y = (INT)y;
1163 lpDrop->fInNonClientArea = (BOOL)
1164 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1165 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1166 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1167 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1168 lpDrop->fWideChar = FALSE;
1169 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT);
1171 } else {
1172 LPDROPFILESTRUCT16 lpDrop;
1173 drop_len += sizeof(DROPFILESTRUCT16) + 1;
1174 hDrop.h16 = (HDROP16)GlobalAlloc16( GMEM_SHARE, drop_len );
1175 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop.h16 );
1177 if( lpDrop ) {
1178 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1179 lpDrop->ptMousePos.x = (INT16)x;
1180 lpDrop->ptMousePos.y = (INT16)y;
1181 lpDrop->fInNonClientArea = (BOOL16)
1182 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1183 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1184 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1185 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1186 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1190 /* create message content */
1191 if (p_drop) {
1192 p = p_data;
1193 next = strchr(p, '\n');
1194 while (p) {
1195 if (next) *next=0;
1196 if (strncmp(p,"file:",5) == 0 ) {
1197 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1198 if (len) {
1199 TRACE_(event)("drop file %s as %s\n", p+5, p_drop);
1200 p_drop += len+1;
1201 } else {
1202 WARN_(event)("can't convert file %s to dos name \n", p+5);
1204 } else {
1205 WARN_(event)("unknown mime type %s\n", p);
1207 if (next) {
1208 *next = '\n';
1209 p = next + 1;
1210 next = strchr(p, '\n');
1211 } else {
1212 p = NULL;
1214 *p_drop = '\0';
1217 if (drop32) {
1218 /* can not use PostMessage32A because it is currently based on
1219 * PostMessage16 and WPARAM32 would be truncated to WPARAM16
1221 GlobalUnlock(hDrop.h32);
1222 SendMessageA( hWnd, WM_DROPFILES,
1223 (WPARAM)hDrop.h32, 0L );
1224 } else {
1225 GlobalUnlock16(hDrop.h16);
1226 PostMessage16( hWnd, WM_DROPFILES,
1227 (WPARAM16)hDrop.h16, 0L );
1230 WIN_ReleaseWndPtr(pDropWnd);
1232 if( p_data ) TSXFree(p_data);
1236 /**********************************************************************
1237 * EVENT_ClientMessage
1239 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
1241 if (event->message_type != None && event->format == 32) {
1242 if ((event->message_type == wmProtocols) &&
1243 (((Atom) event->data.l[0]) == wmDeleteWindow))
1245 /* Ignore the delete window request if the window has been disabled
1246 * and we are in managed mode. This is to disallow applications from
1247 * being closed by the window manager while in a modal state.
1249 BOOL bIsDisabled;
1250 bIsDisabled = GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED;
1252 if ( !Options.managed || !bIsDisabled )
1253 SendMessage16( hWnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
1255 else if ( event->message_type == dndProtocol &&
1256 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
1257 EVENT_DropFromOffiX(hWnd, event);
1258 else if ( event->message_type == dndProtocol &&
1259 event->data.l[0] == DndURL )
1260 EVENT_DropURLs(hWnd, event);
1261 else {
1262 #if 0
1263 /* enable this if you want to see the message */
1264 unsigned char* p_data = NULL;
1265 union {
1266 unsigned long l;
1267 int i;
1268 Atom atom;
1269 } u; /* unused */
1270 TSXGetWindowProperty( display, DefaultRootWindow(display),
1271 dndSelection, 0, 65535, FALSE,
1272 AnyPropertyType, &u.atom, &u.i,
1273 &u.l, &u.l, &p_data);
1274 TRACE_(event)("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1275 event->message_type, event->data.l[0], event->data.l[1],
1276 event->data.l[2], event->data.l[3], event->data.l[4],
1277 p_data);
1278 #endif
1279 TRACE_(event)("unrecognized ClientMessage\n" );
1284 /**********************************************************************
1285 * EVENT_EnterNotify
1287 * Install colormap when Wine window is focused in
1288 * self-managed mode with private colormap
1290 #if 0
1291 void EVENT_EnterNotify( HWND hWnd, XCrossingEvent *event )
1293 if( !Options.managed && X11DRV_GetXRootWindow() == DefaultRootWindow(display) &&
1294 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus() )
1295 TSXInstallColormap( display, X11DRV_PALETTE_GetColormap() );
1297 #endif
1299 /**********************************************************************
1300 * EVENT_MapNotify
1302 void EVENT_MapNotify( HWND hWnd, XMapEvent *event )
1304 HWND hwndFocus = GetFocus();
1305 WND *wndFocus = WIN_FindWndPtr(hwndFocus);
1306 WND *pWnd = WIN_FindWndPtr(hWnd);
1307 if (pWnd->flags & WIN_MANAGED)
1308 pWnd->dwStyle &= ~WS_MINIMIZE;
1309 WIN_ReleaseWndPtr(pWnd);
1311 if (hwndFocus && IsChild( hWnd, hwndFocus ))
1312 X11DRV_WND_SetFocus(wndFocus);
1314 WIN_ReleaseWndPtr(wndFocus);
1316 return;
1320 /**********************************************************************
1321 * EVENT_MapNotify
1323 void EVENT_UnmapNotify( HWND hWnd, XUnmapEvent *event )
1325 WND *pWnd = WIN_FindWndPtr(hWnd);
1326 if (pWnd->flags & WIN_MANAGED)
1328 EndMenu();
1329 if( pWnd->dwStyle & WS_VISIBLE )
1330 pWnd->dwStyle |= WS_MINIMIZE;
1332 WIN_ReleaseWndPtr(pWnd);
1336 #endif /* !defined(X_DISPLAY_MISSING) */