WS_POPUP windows (excluding the WS_POPUPWINDOW windows) should be
[wine/wine-kai.git] / windows / x11drv / event.c
blob7cee1eff98d7a103d6f473727eb4c4a406e6bc43
1 /*
2 * X11 event driver
4 * Copyright 1993 Alexandre Julliard
5 * 1999 Noel Borthwick
6 */
8 #include "config.h"
10 #ifndef X_DISPLAY_MISSING
12 #include <X11/Xatom.h>
13 #include <X11/keysym.h>
14 #include "ts_xlib.h"
15 #include "ts_xresource.h"
16 #include "ts_xutil.h"
18 #include <assert.h>
19 #include <string.h>
20 #include "callback.h"
21 #include "clipboard.h"
22 #include "dce.h"
23 #include "debugtools.h"
24 #include "drive.h"
25 #include "heap.h"
26 #include "keyboard.h"
27 #include "message.h"
28 #include "mouse.h"
29 #include "options.h"
30 #include "queue.h"
31 #include "shell.h"
32 #include "winpos.h"
33 #include "services.h"
34 #include "file.h"
35 #include "windef.h"
36 #include "x11drv.h"
38 DECLARE_DEBUG_CHANNEL(event)
39 DECLARE_DEBUG_CHANNEL(win)
41 /* X context to associate a hwnd to an X window */
42 extern XContext winContext;
44 extern Atom wmProtocols;
45 extern Atom wmDeleteWindow;
46 extern Atom dndProtocol;
47 extern Atom dndSelection;
49 extern void X11DRV_KEYBOARD_UpdateState(void);
50 extern void X11DRV_KEYBOARD_HandleEvent(WND *pWnd, XKeyEvent *event);
52 #define NB_BUTTONS 3 /* Windows can handle 3 buttons */
54 #define DndNotDnd -1 /* OffiX drag&drop */
55 #define DndUnknown 0
56 #define DndRawData 1
57 #define DndFile 2
58 #define DndFiles 3
59 #define DndText 4
60 #define DndDir 5
61 #define DndLink 6
62 #define DndExe 7
64 #define DndEND 8
66 #define DndURL 128 /* KDE drag&drop */
68 /* The last X window which had the focus */
69 static Window glastXFocusWin = 0;
71 static const char * const event_names[] =
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"
84 static void CALLBACK EVENT_Flush( ULONG_PTR arg );
85 static void CALLBACK EVENT_ProcessAllEvents( ULONG_PTR arg );
86 static void EVENT_ProcessEvent( XEvent *event );
88 /* Event handlers */
89 static void EVENT_Key( HWND hWnd, XKeyEvent *event );
90 static void EVENT_ButtonPress( HWND hWnd, XButtonEvent *event );
91 static void EVENT_ButtonRelease( HWND hWnd, XButtonEvent *event );
92 static void EVENT_MotionNotify( HWND hWnd, XMotionEvent *event );
93 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event );
94 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event );
95 static void EVENT_Expose( HWND hWnd, XExposeEvent *event );
96 static void EVENT_GraphicsExpose( HWND hWnd, XGraphicsExposeEvent *event );
97 static void EVENT_ConfigureNotify( HWND hWnd, XConfigureEvent *event );
98 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple );
99 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event);
100 static void EVENT_PropertyNotify( XPropertyEvent *event );
101 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event );
102 static void EVENT_MapNotify( HWND pWnd, XMapEvent *event );
103 static void EVENT_UnmapNotify( HWND pWnd, XUnmapEvent *event );
105 /* Usable only with OLVWM - compile option perhaps?
106 static void EVENT_EnterNotify( HWND hWnd, XCrossingEvent *event );
109 static void EVENT_GetGeometry( Window win, int *px, int *py,
110 unsigned int *pwidth, unsigned int *pheight );
113 static BOOL bUserRepaintDisabled = TRUE;
116 /***********************************************************************
117 * EVENT_Init
119 BOOL X11DRV_EVENT_Init(void)
121 /* Install the X event processing callback */
122 SERVICE_AddObject( FILE_DupUnixHandle( ConnectionNumber(display),
123 GENERIC_READ | SYNCHRONIZE ),
124 EVENT_ProcessAllEvents, 0 );
126 /* Install the XFlush timer callback */
127 if ( Options.synchronous )
128 TSXSynchronize( display, True );
129 else
130 SERVICE_AddTimer( 200000L, EVENT_Flush, 0 );
132 return TRUE;
135 /***********************************************************************
136 * EVENT_Flush
138 static void CALLBACK EVENT_Flush( ULONG_PTR arg )
140 TSXFlush( display );
143 /***********************************************************************
144 * EVENT_ProcessAllEvents
146 static void CALLBACK EVENT_ProcessAllEvents( ULONG_PTR arg )
148 XEvent event;
150 TRACE_(event)( "called.\n" );
152 EnterCriticalSection( &X11DRV_CritSection );
153 while ( XPending( display ) )
155 XNextEvent( display, &event );
157 LeaveCriticalSection( &X11DRV_CritSection );
158 EVENT_ProcessEvent( &event );
159 EnterCriticalSection( &X11DRV_CritSection );
161 LeaveCriticalSection( &X11DRV_CritSection );
164 /***********************************************************************
165 * EVENT_Synchronize
167 * Synchronize with the X server. Should not be used too often.
169 void X11DRV_EVENT_Synchronize( void )
171 TSXSync( display, False );
172 EVENT_ProcessAllEvents( 0 );
175 /***********************************************************************
176 * EVENT_UserRepaintDisable
178 void X11DRV_EVENT_UserRepaintDisable( BOOL bDisabled )
180 bUserRepaintDisabled = bDisabled;
183 /***********************************************************************
184 * EVENT_ProcessEvent
186 * Process an X event.
188 static void EVENT_ProcessEvent( XEvent *event )
190 HWND hWnd;
192 TRACE_(event)( "called.\n" );
194 switch (event->type)
196 case SelectionNotify: /* all of these should be caught by XCheckTypedWindowEvent() */
197 FIXME_(event)("Got SelectionNotify - must not happen!\n");
198 /* fall through */
200 /* We get all these because of StructureNotifyMask.
201 This check is placed here to avoid getting error messages below,
202 as X might send some of these even for windows that have already
203 been deleted ... */
204 case CirculateNotify:
205 case CreateNotify:
206 case DestroyNotify:
207 case GravityNotify:
208 case ReparentNotify:
209 return;
212 if ( TSXFindContext( display, event->xany.window, winContext,
213 (char **)&hWnd ) != 0) {
214 if ( event->type == ClientMessage) {
215 /* query window (drag&drop event contains only drag window) */
216 Window root, child;
217 int root_x, root_y, child_x, child_y;
218 unsigned u;
219 TSXQueryPointer( display, X11DRV_GetXRootWindow(), &root, &child,
220 &root_x, &root_y, &child_x, &child_y, &u);
221 if (TSXFindContext( display, child, winContext, (char **)&hWnd ) != 0)
222 return;
223 } else {
224 hWnd = 0; /* Not for a registered window */
228 if ( !hWnd && event->xany.window != X11DRV_GetXRootWindow()
229 && event->type != PropertyNotify )
230 ERR_(event)("Got event %s for unknown Window %08lx\n",
231 event_names[event->type], event->xany.window );
232 else
233 TRACE_(event)("Got event %s for hwnd %04x\n",
234 event_names[event->type], hWnd );
236 switch(event->type)
238 case KeyPress:
239 case KeyRelease:
240 EVENT_Key( hWnd, (XKeyEvent*)event );
241 break;
243 case ButtonPress:
244 EVENT_ButtonPress( hWnd, (XButtonEvent*)event );
245 break;
247 case ButtonRelease:
248 EVENT_ButtonRelease( hWnd, (XButtonEvent*)event );
249 break;
251 case MotionNotify:
252 /* Wine between two fast machines across the overloaded campus
253 ethernet gets very boged down in MotionEvents. The following
254 simply finds the last motion event in the queue and drops
255 the rest. On a good link events are servered before they build
256 up so this doesn't take place. On a slow link this may cause
257 problems if the event order is important. I'm not yet seen
258 of any problems. Jon 7/6/96.
260 while (TSXCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
261 MotionNotify, event));
262 EVENT_MotionNotify( hWnd, (XMotionEvent*)event );
263 break;
265 case FocusIn:
267 WND *pWndLastFocus = 0;
268 XWindowAttributes win_attr;
269 BOOL bIsDisabled;
270 XFocusChangeEvent *xfocChange = (XFocusChangeEvent*)event;
272 if (!hWnd || bUserRepaintDisabled) return;
274 bIsDisabled = GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED;
276 /* If the window has been disabled and we are in managed mode,
277 * revert the X focus back to the last focus window. This is to disallow
278 * the window manager from switching focus away while the app is
279 * in a modal state.
281 if ( Options.managed && bIsDisabled && glastXFocusWin)
283 /* Change focus only if saved focus window is registered and viewable */
284 if ( TSXFindContext( xfocChange->display, glastXFocusWin, winContext,
285 (char **)&pWndLastFocus ) == 0 )
287 if ( TSXGetWindowAttributes( display, glastXFocusWin, &win_attr ) &&
288 (win_attr.map_state == IsViewable) )
290 TSXSetInputFocus( xfocChange->display, glastXFocusWin, RevertToParent, CurrentTime );
291 EVENT_Synchronize();
292 break;
297 EVENT_FocusIn( hWnd, xfocChange );
298 break;
301 case FocusOut:
303 /* Save the last window which had the focus */
304 XFocusChangeEvent *xfocChange = (XFocusChangeEvent*)event;
305 glastXFocusWin = xfocChange->window;
306 if (!hWnd || bUserRepaintDisabled) return;
307 if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED) glastXFocusWin = 0;
308 EVENT_FocusOut( hWnd, (XFocusChangeEvent*)event );
309 break;
312 case Expose:
313 if (bUserRepaintDisabled) return;
314 EVENT_Expose( hWnd, (XExposeEvent *)event );
315 break;
317 case GraphicsExpose:
318 if (bUserRepaintDisabled) return;
319 EVENT_GraphicsExpose( hWnd, (XGraphicsExposeEvent *)event );
320 break;
322 case ConfigureNotify:
323 if (!hWnd || bUserRepaintDisabled) return;
324 EVENT_ConfigureNotify( hWnd, (XConfigureEvent*)event );
325 break;
327 case SelectionRequest:
328 if (!hWnd || bUserRepaintDisabled) return;
329 EVENT_SelectionRequest( hWnd, (XSelectionRequestEvent *)event, FALSE );
330 break;
332 case SelectionClear:
333 if (!hWnd || bUserRepaintDisabled) return;
334 EVENT_SelectionClear( hWnd, (XSelectionClearEvent*) event );
335 break;
337 case PropertyNotify:
338 EVENT_PropertyNotify( (XPropertyEvent *)event );
339 break;
341 case ClientMessage:
342 if (!hWnd || bUserRepaintDisabled) return;
343 EVENT_ClientMessage( hWnd, (XClientMessageEvent *) event );
344 break;
346 #if 0
347 case EnterNotify:
348 EVENT_EnterNotify( hWnd, (XCrossingEvent *) event );
349 break;
350 #endif
352 case NoExpose:
353 break;
355 case MapNotify:
356 if (!hWnd || bUserRepaintDisabled) return;
357 EVENT_MapNotify( hWnd, (XMapEvent *)event );
358 break;
360 case UnmapNotify:
361 if (!hWnd || bUserRepaintDisabled) return;
362 EVENT_UnmapNotify( hWnd, (XUnmapEvent *)event );
363 break;
365 default:
366 WARN_(event)("Unprocessed event %s for hwnd %04x\n",
367 event_names[event->type], hWnd );
368 break;
372 /***********************************************************************
373 * EVENT_QueryZOrder
375 * Synchronize internal z-order with the window manager's.
377 static BOOL __check_query_condition( WND** pWndA, WND** pWndB )
379 /* return TRUE if we have at least two managed windows */
381 for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
382 if( (*pWndA)->flags & WIN_MANAGED &&
383 (*pWndA)->dwStyle & WS_VISIBLE ) break;
384 if( *pWndA )
385 for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
386 if( (*pWndB)->flags & WIN_MANAGED &&
387 (*pWndB)->dwStyle & WS_VISIBLE ) break;
388 return ((*pWndB) != NULL);
391 static Window __get_common_ancestor( Window A, Window B,
392 Window** children, unsigned* total )
394 /* find the real root window */
396 Window root, *childrenB;
397 unsigned totalB;
401 TSXQueryTree( display, A, &root, &A, children, total );
402 TSXQueryTree( display, B, &root, &B, &childrenB, &totalB );
403 if( childrenB ) TSXFree( childrenB );
404 if( *children ) TSXFree( *children ), *children = NULL;
405 } while( A != B && A && B );
407 if( A && B )
409 TSXQueryTree( display, A, &root, &B, children, total );
410 return A;
412 return 0 ;
415 static Window __get_top_decoration( Window w, Window ancestor )
417 Window* children, root, prev = w, parent = w;
418 unsigned total;
422 w = parent;
423 TSXQueryTree( display, w, &root, &parent, &children, &total );
424 if( children ) TSXFree( children );
425 } while( parent && parent != ancestor );
426 TRACE_(event)("\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
427 return ( parent ) ? w : 0 ;
430 static unsigned __td_lookup( Window w, Window* list, unsigned max )
432 unsigned i;
433 for( i = max - 1; i >= 0; i-- ) if( list[i] == w ) break;
434 return i;
437 static HWND EVENT_QueryZOrder( HWND hWndCheck)
439 HWND hwndInsertAfter = HWND_TOP;
440 WND *pWndCheck = WIN_FindWndPtr(hWndCheck);
441 WND *pDesktop = WIN_GetDesktop();
442 WND *pWnd, *pWndZ = WIN_LockWndPtr(pDesktop->child);
443 Window w, parent, *children = NULL;
444 unsigned total, check, pos, best;
446 if( !__check_query_condition(&pWndZ, &pWnd) )
448 WIN_ReleaseWndPtr(pWndCheck);
449 WIN_ReleaseWndPtr(pDesktop->child);
450 WIN_ReleaseDesktop();
451 return hwndInsertAfter;
453 WIN_LockWndPtr(pWndZ);
454 WIN_LockWndPtr(pWnd);
455 WIN_ReleaseWndPtr(pDesktop->child);
456 WIN_ReleaseDesktop();
458 parent = __get_common_ancestor( X11DRV_WND_GetXWindow(pWndZ),
459 X11DRV_WND_GetXWindow(pWnd),
460 &children, &total );
461 if( parent && children )
463 /* w is the ancestor if pWndCheck that is a direct descendant of 'parent' */
465 w = __get_top_decoration( X11DRV_WND_GetXWindow(pWndCheck), parent );
467 if( w != children[total-1] ) /* check if at the top */
469 /* X child at index 0 is at the bottom, at index total-1 is at the top */
470 check = __td_lookup( w, children, total );
471 best = total;
473 for( WIN_UpdateWndPtr(&pWnd,pWndZ); pWnd;WIN_UpdateWndPtr(&pWnd,pWnd->next))
475 /* go through all windows in Wine z-order... */
477 if( pWnd != pWndCheck )
479 if( !(pWnd->flags & WIN_MANAGED) ||
480 !(w = __get_top_decoration( X11DRV_WND_GetXWindow(pWnd), parent )) )
481 continue;
482 pos = __td_lookup( w, children, total );
483 if( pos < best && pos > check )
485 /* find a nearest Wine window precedes
486 * pWndCheck in the real z-order... */
487 best = pos;
488 hwndInsertAfter = pWnd->hwndSelf;
490 if( best - check == 1 ) break;
495 if( children ) TSXFree( children );
496 WIN_ReleaseWndPtr(pWnd);
497 WIN_ReleaseWndPtr(pWndZ);
498 WIN_ReleaseWndPtr(pWndCheck);
499 return hwndInsertAfter;
502 /***********************************************************************
503 * EVENT_XStateToKeyState
505 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
506 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
508 static WORD EVENT_XStateToKeyState( int state )
510 int kstate = 0;
512 if (state & Button1Mask) kstate |= MK_LBUTTON;
513 if (state & Button2Mask) kstate |= MK_MBUTTON;
514 if (state & Button3Mask) kstate |= MK_RBUTTON;
515 if (state & ShiftMask) kstate |= MK_SHIFT;
516 if (state & ControlMask) kstate |= MK_CONTROL;
517 return kstate;
520 /***********************************************************************
521 * X11DRV_EVENT_QueryPointer
523 BOOL X11DRV_EVENT_QueryPointer(DWORD *posX, DWORD *posY, DWORD *state)
525 Window root, child;
526 int rootX, rootY, winX, winY;
527 unsigned int xstate;
529 if (!TSXQueryPointer( display, X11DRV_GetXRootWindow(), &root, &child,
530 &rootX, &rootY, &winX, &winY, &xstate ))
531 return FALSE;
533 if(posX)
534 *posX = (DWORD)winX;
535 if(posY)
536 *posY = (DWORD)winY;
537 if(state)
538 *state = EVENT_XStateToKeyState( xstate );
540 return TRUE;
543 /***********************************************************************
544 * EVENT_Expose
546 static void EVENT_Expose( HWND hWnd, XExposeEvent *event )
548 RECT rect;
550 WND *pWnd = WIN_FindWndPtr(hWnd);
551 /* Make position relative to client area instead of window */
552 rect.left = event->x - (pWnd? (pWnd->rectClient.left - pWnd->rectWindow.left) : 0);
553 rect.top = event->y - (pWnd? (pWnd->rectClient.top - pWnd->rectWindow.top) : 0);
554 rect.right = rect.left + event->width;
555 rect.bottom = rect.top + event->height;
556 WIN_ReleaseWndPtr(pWnd);
558 Callout.RedrawWindow( hWnd, &rect, 0,
559 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
560 (event->count ? 0 : RDW_ERASENOW) );
564 /***********************************************************************
565 * EVENT_GraphicsExpose
567 * This is needed when scrolling area is partially obscured
568 * by non-Wine X window.
570 static void EVENT_GraphicsExpose( HWND hWnd, XGraphicsExposeEvent *event )
572 RECT rect;
573 WND *pWnd = WIN_FindWndPtr(hWnd);
575 /* Make position relative to client area instead of window */
576 rect.left = event->x - (pWnd? (pWnd->rectClient.left - pWnd->rectWindow.left) : 0);
577 rect.top = event->y - (pWnd? (pWnd->rectClient.top - pWnd->rectWindow.top) : 0);
578 rect.right = rect.left + event->width;
579 rect.bottom = rect.top + event->height;
581 WIN_ReleaseWndPtr(pWnd);
583 Callout.RedrawWindow( hWnd, &rect, 0,
584 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
585 (event->count ? 0 : RDW_ERASENOW) );
589 /***********************************************************************
590 * EVENT_Key
592 * Handle a X key event
594 static void EVENT_Key( HWND hWnd, XKeyEvent *event )
596 WND *pWnd = WIN_FindWndPtr(hWnd);
597 X11DRV_KEYBOARD_HandleEvent( pWnd, event );
598 WIN_ReleaseWndPtr(pWnd);
603 /***********************************************************************
604 * EVENT_MotionNotify
606 static void EVENT_MotionNotify( HWND hWnd, XMotionEvent *event )
608 WND *pWnd = WIN_FindWndPtr(hWnd);
609 int xOffset = pWnd? pWnd->rectWindow.left : 0;
610 int yOffset = pWnd? pWnd->rectWindow.top : 0;
611 WIN_ReleaseWndPtr(pWnd);
613 MOUSE_SendEvent( MOUSEEVENTF_MOVE,
614 xOffset + event->x, yOffset + event->y,
615 EVENT_XStateToKeyState( event->state ),
616 event->time - MSG_WineStartTicks,
617 hWnd);
621 /***********************************************************************
622 * EVENT_ButtonPress
624 static void EVENT_ButtonPress( HWND hWnd, XButtonEvent *event )
626 static WORD statusCodes[NB_BUTTONS] =
627 { MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_RIGHTDOWN };
628 int buttonNum = event->button - 1;
630 WND *pWnd = WIN_FindWndPtr(hWnd);
631 int xOffset = pWnd? pWnd->rectWindow.left : 0;
632 int yOffset = pWnd? pWnd->rectWindow.top : 0;
633 WORD keystate;
635 WIN_ReleaseWndPtr(pWnd);
637 if (buttonNum >= NB_BUTTONS) return;
640 * Get the compatible keystate
642 keystate = EVENT_XStateToKeyState( event->state );
645 * Make sure that the state of the button that was just
646 * pressed is "down".
648 switch (buttonNum)
650 case 0:
651 keystate |= MK_LBUTTON;
652 break;
653 case 1:
654 keystate |= MK_MBUTTON;
655 break;
656 case 2:
657 keystate |= MK_RBUTTON;
658 break;
661 MOUSE_SendEvent( statusCodes[buttonNum],
662 xOffset + event->x, yOffset + event->y,
663 keystate,
664 event->time - MSG_WineStartTicks,
665 hWnd);
669 /***********************************************************************
670 * EVENT_ButtonRelease
672 static void EVENT_ButtonRelease( HWND hWnd, XButtonEvent *event )
674 static WORD statusCodes[NB_BUTTONS] =
675 { MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_RIGHTUP };
676 int buttonNum = event->button - 1;
677 WND *pWnd = WIN_FindWndPtr(hWnd);
678 int xOffset = pWnd? pWnd->rectWindow.left : 0;
679 int yOffset = pWnd? pWnd->rectWindow.top : 0;
680 WORD keystate;
682 WIN_ReleaseWndPtr(pWnd);
684 if (buttonNum >= NB_BUTTONS) return;
687 * Get the compatible keystate
689 keystate = EVENT_XStateToKeyState( event->state );
692 * Make sure that the state of the button that was just
693 * released is "up".
695 switch (buttonNum)
697 case 0:
698 keystate &= ~MK_LBUTTON;
699 break;
700 case 1:
701 keystate &= ~MK_MBUTTON;
702 break;
703 case 2:
704 keystate &= ~MK_RBUTTON;
705 break;
708 MOUSE_SendEvent( statusCodes[buttonNum],
709 xOffset + event->x, yOffset + event->y,
710 keystate,
711 event->time - MSG_WineStartTicks,
712 hWnd);
716 /**********************************************************************
717 * EVENT_FocusIn
719 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event )
721 if (event->detail != NotifyPointer)
722 if (hWnd != GetForegroundWindow())
724 SetForegroundWindow( hWnd );
725 X11DRV_KEYBOARD_UpdateState();
730 /**********************************************************************
731 * EVENT_FocusOut
733 * Note: only top-level override-redirect windows get FocusOut events.
735 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event )
737 if (event->detail != NotifyPointer)
738 if (hWnd == GetForegroundWindow())
740 WND *pWnd = WIN_FindWndPtr(hWnd);
742 if( ((pWnd->dwStyle & WS_POPUP) == WS_POPUP) &&
743 ((pWnd->dwStyle & WS_POPUPWINDOW) != WS_POPUPWINDOW) )
744 SendMessageA(hWnd, WM_CLOSE, 0, 0 );
745 else
746 SendMessageA( hWnd, WM_CANCELMODE, 0, 0 );
747 WIN_ReleaseWndPtr(pWnd);
748 SetForegroundWindow( 0 );
752 /**********************************************************************
753 * X11DRV_EVENT_CheckFocus
755 BOOL X11DRV_EVENT_CheckFocus(void)
757 HWND hWnd;
758 Window xW;
759 int state;
761 TSXGetInputFocus(display, &xW, &state);
762 if( xW == None ||
763 TSXFindContext(display, xW, winContext, (char **)&hWnd) )
764 return FALSE;
765 return TRUE;
768 /**********************************************************************
769 * EVENT_GetGeometry
771 * Helper function for ConfigureNotify handling.
772 * Get the new geometry of a window relative to the root window.
774 static void EVENT_GetGeometry( Window win, int *px, int *py,
775 unsigned int *pwidth, unsigned int *pheight )
777 Window root, top;
778 int x, y, width, height, border, depth;
780 EnterCriticalSection( &X11DRV_CritSection );
782 /* Get the geometry of the window */
783 XGetGeometry( display, win, &root, &x, &y, &width, &height,
784 &border, &depth );
786 /* Translate the window origin to root coordinates */
787 XTranslateCoordinates( display, win, root, 0, 0, &x, &y, &top );
789 LeaveCriticalSection( &X11DRV_CritSection );
791 *px = x;
792 *py = y;
793 *pwidth = width;
794 *pheight = height;
797 /**********************************************************************
798 * EVENT_ConfigureNotify
800 * The ConfigureNotify event is only selected on top-level windows
801 * when the -managed flag is used.
803 static void EVENT_ConfigureNotify( HWND hWnd, XConfigureEvent *event )
805 RECT rectWindow;
806 int x, y, flags = 0;
807 unsigned int width, height;
808 HWND newInsertAfter, oldInsertAfter;
810 /* Get geometry and Z-order according to X */
812 EVENT_GetGeometry( event->window, &x, &y, &width, &height );
813 newInsertAfter = EVENT_QueryZOrder( hWnd );
815 /* Get geometry and Z-order according to Wine */
817 GetWindowRect( hWnd, &rectWindow );
818 oldInsertAfter = GetWindow( hWnd, GW_HWNDPREV );
819 if ( !oldInsertAfter ) oldInsertAfter = HWND_TOP;
821 /* Compare what has changed */
823 if ( rectWindow.left == x && rectWindow.top == y )
824 flags |= SWP_NOMOVE;
825 else
826 TRACE_(win)( "%04x moving from (%d,%d) to (%d,%d)\n", hWnd,
827 rectWindow.left, rectWindow.top, x, y );
829 if ( rectWindow.right - rectWindow.left == width
830 && rectWindow.bottom - rectWindow.top == height )
831 flags |= SWP_NOSIZE;
832 else
833 TRACE_(win)( "%04x resizing from (%d,%d) to (%d,%d)\n", hWnd,
834 rectWindow.right - rectWindow.left,
835 rectWindow.bottom - rectWindow.top, width, height );
837 if ( newInsertAfter == oldInsertAfter )
838 flags |= SWP_NOZORDER;
839 else
840 TRACE_(win)( "%04x restacking from after %04x to after %04x\n", hWnd,
841 oldInsertAfter, newInsertAfter );
843 /* If anything changed, call SetWindowPos */
845 if ( flags != (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER) )
846 SetWindowPos( hWnd, newInsertAfter, x, y, width, height,
847 flags | SWP_NOACTIVATE | SWP_WINE_NOHOSTMOVE );
851 /***********************************************************************
852 * EVENT_SelectionRequest_TARGETS
853 * Service a TARGETS selection request event
855 static Atom EVENT_SelectionRequest_TARGETS( Window requestor, Atom target, Atom rprop )
857 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
858 Atom* targets;
859 Atom prop;
860 UINT wFormat;
861 unsigned long cTargets;
862 BOOL bHavePixmap;
863 int xRc;
865 TRACE_(event)("Request for %s\n", TSXGetAtomName(display, target));
868 * Count the number of items we wish to expose as selection targets.
869 * We include the TARGETS item, and a PIXMAP if we have CF_DIB or CF_BITMAP
871 cTargets = CountClipboardFormats() + 1;
872 if ( CLIPBOARD_IsPresent(CF_DIB) || CLIPBOARD_IsPresent(CF_BITMAP) )
873 cTargets++;
875 /* Allocate temp buffer */
876 targets = (Atom*)HEAP_xalloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
878 /* Create TARGETS property list (First item in list is TARGETS itself) */
880 for ( targets[0] = xaTargets, cTargets = 1, wFormat = 0, bHavePixmap = FALSE;
881 (wFormat = EnumClipboardFormats( wFormat )); )
883 if ( (prop = X11DRV_CLIPBOARD_MapFormatToProperty(wFormat)) != None )
885 /* Scan through what we have so far to avoid duplicates */
886 int i;
887 BOOL bExists;
888 for (i = 0, bExists = FALSE; i < cTargets; i++)
890 if (targets[i] == prop)
892 bExists = TRUE;
893 break;
896 if (!bExists)
898 targets[cTargets++] = prop;
900 /* Add PIXMAP prop for bitmaps additionally */
901 if ( (wFormat == CF_DIB || wFormat == CF_BITMAP )
902 && !bHavePixmap )
904 targets[cTargets++] = XA_PIXMAP;
905 bHavePixmap = TRUE;
911 #ifdef DEBUG_RUNTIME
913 int i;
914 for ( i = 0; i < cTargets; i++)
916 if (targets[i])
918 char *itemFmtName = TSXGetAtomName(display, targets[i]);
919 TRACE_(event)("\tAtom# %d: Type %s\n", i, itemFmtName);
920 TSXFree(itemFmtName);
924 #endif
926 /* Update the X property */
927 TRACE_(event)("\tUpdating property %s...", TSXGetAtomName(display, rprop));
929 /* We may want to consider setting the type to xaTargets instead,
930 * in case some apps expect this instead of XA_ATOM */
931 xRc = TSXChangeProperty(display, requestor, rprop,
932 XA_ATOM, 32, PropModeReplace,
933 (unsigned char *)targets, cTargets);
934 TRACE_(event)("(Rc=%d)\n", xRc);
936 HeapFree( GetProcessHeap(), 0, targets );
938 return rprop;
942 /***********************************************************************
943 * EVENT_SelectionRequest_STRING
944 * Service a STRING selection request event
946 static Atom EVENT_SelectionRequest_STRING( Window requestor, Atom target, Atom rprop )
948 HANDLE16 hText;
949 LPSTR text;
950 int size,i,j;
951 char* lpstr = 0;
952 char *itemFmtName;
953 int xRc;
956 * Map the requested X selection property type atom name to a
957 * windows clipboard format ID.
959 itemFmtName = TSXGetAtomName(display, target);
960 TRACE_(event)("Request for %s (wFormat=%x %s)\n",
961 itemFmtName, CF_TEXT, CLIPBOARD_GetFormatName(CF_TEXT));
962 TSXFree(itemFmtName);
964 if ( !CLIPBOARD_IsPresent(CF_TEXT) )
966 rprop = None;
967 goto END;
970 hText = GetClipboardData16(CF_TEXT);
971 text = GlobalLock16(hText);
972 size = GlobalSize16(hText);
974 /* remove carriage returns */
976 lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
977 for(i=0,j=0; i < size && text[i]; i++ )
979 if( text[i] == '\r' &&
980 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
981 lpstr[j++] = text[i];
983 lpstr[j]='\0';
985 /* Update the X property */
986 TRACE_(event)("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
987 xRc = TSXChangeProperty(display, requestor, rprop,
988 XA_STRING, 8, PropModeReplace,
989 lpstr, j);
990 TRACE_(event)("(Rc=%d)\n", xRc);
992 GlobalUnlock16(hText);
993 HeapFree( GetProcessHeap(), 0, lpstr );
995 END:
996 return rprop;
999 /***********************************************************************
1000 * EVENT_SelectionRequest_PIXMAP
1001 * Service a PIXMAP selection request event
1003 static Atom EVENT_SelectionRequest_PIXMAP( Window requestor, Atom target, Atom rprop )
1005 HANDLE hClipData = 0;
1006 Pixmap pixmap = NULL;
1007 UINT wFormat;
1008 char * itemFmtName;
1009 int xRc;
1010 #if(0)
1011 XSetWindowAttributes win_attr;
1012 XWindowAttributes win_attr_src;
1013 #endif
1016 * Map the requested X selection property type atom name to a
1017 * windows clipboard format ID.
1019 itemFmtName = TSXGetAtomName(display, target);
1020 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
1021 TRACE_(event)("Request for %s (wFormat=%x %s)\n",
1022 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat));
1023 TSXFree(itemFmtName);
1025 hClipData = GetClipboardData(wFormat);
1026 if ( !hClipData )
1028 TRACE_(event)("Could not retrieve a Pixmap compatible format from clipboard!\n");
1029 rprop = None; /* Fail the request */
1030 goto END;
1033 if (wFormat == CF_DIB)
1035 HWND hwnd = GetOpenClipboardWindow();
1036 HDC hdc = GetDC(hwnd);
1038 /* For convert from packed DIB to Pixmap */
1039 pixmap = X11DRV_DIB_CreatePixmapFromDIB(hClipData, hdc);
1041 ReleaseDC(hdc, hwnd);
1043 else if (wFormat == CF_BITMAP)
1045 HWND hwnd = GetOpenClipboardWindow();
1046 HDC hdc = GetDC(hwnd);
1048 pixmap = X11DRV_BITMAP_CreatePixmapFromBitmap(hClipData, hdc);
1050 ReleaseDC(hdc, hwnd);
1052 else
1054 FIXME_(event)("%s to PIXMAP conversion not yet implemented!\n",
1055 CLIPBOARD_GetFormatName(wFormat));
1056 rprop = None;
1057 goto END;
1060 TRACE_(event)("\tUpdating property %s on Window %ld with %s %ld...\n",
1061 TSXGetAtomName(display, rprop), (long)requestor,
1062 TSXGetAtomName(display, target),
1063 pixmap);
1065 /* Store the Pixmap handle in the property */
1066 xRc = TSXChangeProperty(display, requestor, rprop, target,
1067 32, PropModeReplace,
1068 (unsigned char *)&pixmap, 1);
1069 TRACE_(event)("(Rc=%d)\n", xRc);
1071 /* Enable the code below if you want to handle destroying Pixmap resources
1072 * in response to property notify events. Clients like XPaint don't
1073 * appear to be duplicating Pixmaps so they don't like us deleting,
1074 * the resource in response to the property being deleted.
1076 #if(0)
1077 /* Express interest in property notify events so that we can delete the
1078 * pixmap when the client deletes the property atom.
1080 xRc = TSXGetWindowAttributes(display, requestor, &win_attr_src);
1081 TRACE_(event)("Turning on PropertyChangeEvent notifications from window %ld\n",
1082 (long)requestor);
1083 win_attr.event_mask = win_attr_src.your_event_mask | PropertyChangeMask;
1084 TSXChangeWindowAttributes(display, requestor, CWEventMask, &win_attr);
1086 /* Register the Pixmap we created with the request property Atom.
1087 * When this property is destroyed we also destroy the Pixmap in
1088 * response to the PropertyNotify event.
1090 X11DRV_CLIPBOARD_RegisterPixmapResource( rprop, pixmap );
1091 #endif
1093 END:
1094 return rprop;
1098 /***********************************************************************
1099 * EVENT_SelectionRequest_WCF
1100 * Service a Wine Clipboard Format selection request event.
1101 * For <WCF>* data types we simply copy the data to X without conversion.
1103 static Atom EVENT_SelectionRequest_WCF( Window requestor, Atom target, Atom rprop )
1105 HANDLE hClipData = 0;
1106 void* lpClipData;
1107 UINT wFormat;
1108 char * itemFmtName;
1109 int cBytes;
1110 int xRc;
1113 * Map the requested X selection property type atom name to a
1114 * windows clipboard format ID.
1116 itemFmtName = TSXGetAtomName(display, target);
1117 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
1118 TRACE_(event)("Request for %s (wFormat=%x %s)\n",
1119 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat));
1120 TSXFree(itemFmtName);
1122 hClipData = GetClipboardData16(wFormat);
1124 if( hClipData && (lpClipData = GlobalLock16(hClipData)) )
1126 cBytes = GlobalSize16(hClipData);
1128 TRACE_(event)("\tUpdating property %s, %d bytes...\n",
1129 TSXGetAtomName(display, rprop), cBytes);
1131 xRc = TSXChangeProperty(display, requestor, rprop,
1132 target, 8, PropModeReplace,
1133 (unsigned char *)lpClipData, cBytes);
1134 TRACE_(event)("(Rc=%d)\n", xRc);
1136 GlobalUnlock16(hClipData);
1138 else
1140 TRACE_(event)("\tCould not retrieve native format!\n");
1141 rprop = None; /* Fail the request */
1144 return rprop;
1148 /***********************************************************************
1149 * EVENT_SelectionRequest_MULTIPLE
1150 * Service a MULTIPLE selection request event
1151 * rprop contains a list of (target,property) atom pairs.
1152 * The first atom names a target and the second names a property.
1153 * The effect is as if we have received a sequence of SelectionRequest events
1154 * (one for each atom pair) except that:
1155 * 1. We reply with a SelectionNotify only when all the requested conversions
1156 * have been performed.
1157 * 2. If we fail to convert the target named by an atom in the MULTIPLE property,
1158 * we replace the atom in the property by None.
1160 static Atom EVENT_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
1162 Atom rprop;
1163 Atom atype=AnyPropertyType;
1164 int aformat;
1165 unsigned long remain;
1166 Atom* targetPropList=NULL;
1167 unsigned long cTargetPropList = 0;
1168 /* Atom xAtomPair = TSXInternAtom(display, "ATOM_PAIR", False); */
1170 /* If the specified property is None the requestor is an obsolete client.
1171 * We support these by using the specified target atom as the reply property.
1173 rprop = pevent->property;
1174 if( rprop == None )
1175 rprop = pevent->target;
1176 if (!rprop)
1177 goto END;
1179 /* Read the MULTIPLE property contents. This should contain a list of
1180 * (target,property) atom pairs.
1182 if(TSXGetWindowProperty(display, pevent->requestor, rprop,
1183 0, 0x3FFF, False, AnyPropertyType, &atype, &aformat,
1184 &cTargetPropList, &remain, (unsigned char**)&targetPropList) != Success)
1185 TRACE_(event)("\tCouldn't read MULTIPLE property\n");
1186 else
1188 TRACE_(event)("\tType %s,Format %d,nItems %ld, Remain %ld\n",
1189 TSXGetAtomName(display,atype),aformat,cTargetPropList,remain);
1192 * Make sure we got what we expect.
1193 * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
1194 * in a MULTIPLE selection request should be of type ATOM_PAIR.
1195 * However some X apps(such as XPaint) are not compliant with this and return
1196 * a user defined atom in atype when XGetWindowProperty is called.
1197 * The data *is* an atom pair but is not denoted as such.
1199 if(aformat == 32 /* atype == xAtomPair */ )
1201 int i;
1203 /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
1204 * for each (target,property) pair */
1206 for (i = 0; i < cTargetPropList; i+=2)
1208 char *targetName = TSXGetAtomName(display, targetPropList[i]);
1209 char *propName = TSXGetAtomName(display, targetPropList[i+1]);
1210 XSelectionRequestEvent event;
1212 TRACE_(event)("MULTIPLE(%d): Target='%s' Prop='%s'\n", i/2, targetName, propName);
1213 TSXFree(targetName);
1214 TSXFree(propName);
1216 /* We must have a non "None" property to service a MULTIPLE target atom */
1217 if ( !targetPropList[i+1] )
1219 TRACE_(event)("\tMULTIPLE(%d): Skipping target with empty property!", i);
1220 continue;
1223 /* Set up an XSelectionRequestEvent for this (target,property) pair */
1224 memcpy( &event, pevent, sizeof(XSelectionRequestEvent) );
1225 event.target = targetPropList[i];
1226 event.property = targetPropList[i+1];
1228 /* Fire a SelectionRequest, informing the handler that we are processing
1229 * a MULTIPLE selection request event.
1231 EVENT_SelectionRequest( hWnd, &event, TRUE );
1235 /* Free the list of targets/properties */
1236 TSXFree(targetPropList);
1239 END:
1240 return rprop;
1244 /***********************************************************************
1245 * EVENT_SelectionRequest
1246 * Process an event selection request event.
1247 * The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
1248 * recursively while servicing a "MULTIPLE" selection target.
1250 * Note: We only receive this event when WINE owns the X selection
1252 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
1254 XSelectionEvent result;
1255 Atom rprop = None;
1256 Window request = event->requestor;
1257 BOOL couldOpen = FALSE;
1258 Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
1259 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
1260 Atom xaMultiple = TSXInternAtom(display, "MULTIPLE", False);
1263 * We can only handle the selection request if :
1264 * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
1265 * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
1266 * since this has been already done.
1268 if ( !bIsMultiple )
1270 if ( ( (event->selection != XA_PRIMARY) && (event->selection != xaClipboard) )
1271 || !(couldOpen = OpenClipboard(hWnd)) )
1272 goto END;
1275 /* If the specified property is None the requestor is an obsolete client.
1276 * We support these by using the specified target atom as the reply property.
1278 rprop = event->property;
1279 if( rprop == None )
1280 rprop = event->target;
1282 if(event->target == xaTargets) /* Return a list of all supported targets */
1284 /* TARGETS selection request */
1285 rprop = EVENT_SelectionRequest_TARGETS( request, event->target, rprop );
1287 else if(event->target == xaMultiple) /* rprop contains a list of (target, property) atom pairs */
1289 /* MULTIPLE selection request */
1290 rprop = EVENT_SelectionRequest_MULTIPLE( hWnd, event );
1292 else if(event->target == XA_STRING) /* treat CF_TEXT as Unix text */
1294 /* XA_STRING selection request */
1295 rprop = EVENT_SelectionRequest_STRING( request, event->target, rprop );
1297 else if(event->target == XA_PIXMAP) /* Convert DIB's to Pixmaps */
1299 /* XA_PIXMAP selection request */
1300 rprop = EVENT_SelectionRequest_PIXMAP( request, event->target, rprop );
1302 else if(event->target == XA_BITMAP) /* Convert DIB's to 1-bit Pixmaps */
1304 /* XA_BITMAP selection request - TODO: create a monochrome Pixmap */
1305 rprop = EVENT_SelectionRequest_PIXMAP( request, XA_PIXMAP, rprop );
1307 else if(X11DRV_CLIPBOARD_IsNativeProperty(event->target)) /* <WCF>* */
1309 /* All <WCF> selection requests */
1310 rprop = EVENT_SelectionRequest_WCF( request, event->target, rprop );
1312 else
1313 rprop = None; /* Don't support this format */
1315 END:
1316 /* close clipboard only if we opened before */
1317 if(couldOpen) CloseClipboard();
1319 if( rprop == None)
1320 TRACE_(event)("\tRequest ignored\n");
1322 /* reply to sender
1323 * SelectionNotify should be sent only at the end of a MULTIPLE request
1325 if ( !bIsMultiple )
1327 result.type = SelectionNotify;
1328 result.display = display;
1329 result.requestor = request;
1330 result.selection = event->selection;
1331 result.property = rprop;
1332 result.target = event->target;
1333 result.time = event->time;
1334 TRACE_(event)("Sending SelectionNotify event...\n");
1335 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
1339 /***********************************************************************
1340 * EVENT_SelectionClear
1342 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
1344 Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
1346 if (event->selection == XA_PRIMARY || event->selection == xaClipboard)
1347 X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd );
1350 /***********************************************************************
1351 * EVENT_PropertyNotify
1352 * We use this to release resources like Pixmaps when a selection
1353 * client no longer needs them.
1355 static void EVENT_PropertyNotify( XPropertyEvent *event )
1357 /* Check if we have any resources to free */
1358 TRACE_(event)("Received PropertyNotify event: ");
1360 switch(event->state)
1362 case PropertyDelete:
1364 TRACE_(event)("\tPropertyDelete for atom %s on window %ld\n",
1365 TSXGetAtomName(event->display, event->atom), (long)event->window);
1367 if (X11DRV_CLIPBOARD_IsSelectionowner())
1368 X11DRV_CLIPBOARD_FreeResources( event->atom );
1369 break;
1372 case PropertyNewValue:
1374 TRACE_(event)("\tPropertyNewValue for atom %s on window %ld\n\n",
1375 TSXGetAtomName(event->display, event->atom), (long)event->window);
1376 break;
1379 default:
1380 break;
1384 /**********************************************************************
1385 * EVENT_DropFromOffix
1387 * don't know if it still works (last Changlog is from 96/11/04)
1389 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1391 unsigned long data_length;
1392 unsigned long aux_long;
1393 unsigned char* p_data = NULL;
1394 union {
1395 Atom atom_aux;
1396 struct {
1397 int x;
1398 int y;
1399 } pt_aux;
1400 int i;
1401 } u;
1402 int x, y;
1403 BOOL16 bAccept;
1404 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
1405 LPDRAGINFO lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
1406 SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
1407 Window w_aux_root, w_aux_child;
1408 WND* pDropWnd;
1409 WND* pWnd;
1411 if( !lpDragInfo || !spDragInfo ) return;
1413 pWnd = WIN_FindWndPtr(hWnd);
1415 TSXQueryPointer( display, X11DRV_WND_GetXWindow(pWnd), &w_aux_root, &w_aux_child,
1416 &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
1417 (unsigned int*)&aux_long);
1419 lpDragInfo->hScope = hWnd;
1420 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1422 /* find out drop point and drop window */
1423 if( x < 0 || y < 0 ||
1424 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1425 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1426 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1427 else
1429 bAccept = DRAG_QueryUpdate( hWnd, spDragInfo, TRUE );
1430 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1432 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1433 WIN_ReleaseWndPtr(pWnd);
1435 GlobalFree16( hDragInfo );
1437 if( bAccept )
1439 TSXGetWindowProperty( display, DefaultRootWindow(display),
1440 dndSelection, 0, 65535, FALSE,
1441 AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
1442 &data_length, &aux_long, &p_data);
1444 if( !aux_long && p_data) /* don't bother if > 64K */
1446 char *p = (char*) p_data;
1447 char *p_drop;
1449 aux_long = 0;
1450 while( *p ) /* calculate buffer size */
1452 p_drop = p;
1453 if((u.i = *p) != -1 )
1454 u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
1455 if( u.i == -1 ) *p = -1; /* mark as "bad" */
1456 else
1458 INT len = GetShortPathNameA( p, NULL, 0 );
1459 if (len) aux_long += len + 1;
1460 else *p = -1;
1462 p += strlen(p) + 1;
1464 if( aux_long && aux_long < 65535 )
1466 HDROP16 hDrop;
1467 LPDROPFILESTRUCT16 lpDrop;
1469 aux_long += sizeof(DROPFILESTRUCT16) + 1;
1470 hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
1471 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop );
1473 if( lpDrop )
1475 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1476 lpDrop->ptMousePos.x = (INT16)x;
1477 lpDrop->ptMousePos.y = (INT16)y;
1478 lpDrop->fInNonClientArea = (BOOL16)
1479 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1480 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1481 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1482 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1483 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1484 p = p_data;
1485 while(*p)
1487 if( *p != -1 ) /* use only "good" entries */
1489 GetShortPathNameA( p, p_drop, 65535 );
1490 p_drop += strlen( p_drop ) + 1;
1492 p += strlen(p) + 1;
1494 *p_drop = '\0';
1495 PostMessage16( hWnd, WM_DROPFILES,
1496 (WPARAM16)hDrop, 0L );
1500 if( p_data ) TSXFree(p_data);
1502 } /* WS_EX_ACCEPTFILES */
1504 WIN_ReleaseWndPtr(pDropWnd);
1507 /**********************************************************************
1508 * EVENT_DropURLs
1510 * drop items are separated by \n
1511 * each item is prefixed by its mime type
1513 * event->data.l[3], event->data.l[4] contains drop x,y position
1515 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1517 WND *pDropWnd;
1518 WND *pWnd;
1519 unsigned long data_length;
1520 unsigned long aux_long, drop_len = 0;
1521 unsigned char *p_data = NULL; /* property data */
1522 char *p_drop = NULL;
1523 char *p, *next;
1524 int x, y, drop32 = FALSE ;
1525 union {
1526 Atom atom_aux;
1527 int i;
1528 Window w_aux;
1529 } u; /* unused */
1530 union {
1531 HDROP16 h16;
1532 HDROP h32;
1533 } hDrop;
1535 pWnd = WIN_FindWndPtr(hWnd);
1536 drop32 = pWnd->flags & WIN_ISWIN32;
1538 if (!(pWnd->dwExStyle & WS_EX_ACCEPTFILES))
1540 WIN_ReleaseWndPtr(pWnd);
1541 return;
1543 WIN_ReleaseWndPtr(pWnd);
1545 TSXGetWindowProperty( display, DefaultRootWindow(display),
1546 dndSelection, 0, 65535, FALSE,
1547 AnyPropertyType, &u.atom_aux, &u.i,
1548 &data_length, &aux_long, &p_data);
1549 if (aux_long)
1550 WARN_(event)("property too large, truncated!\n");
1551 TRACE_(event)("urls=%s\n", p_data);
1553 if( !aux_long && p_data) { /* don't bother if > 64K */
1554 /* calculate length */
1555 p = p_data;
1556 next = strchr(p, '\n');
1557 while (p) {
1558 if (next) *next=0;
1559 if (strncmp(p,"file:",5) == 0 ) {
1560 INT len = GetShortPathNameA( p+5, NULL, 0 );
1561 if (len) drop_len += len + 1;
1563 if (next) {
1564 *next = '\n';
1565 p = next + 1;
1566 next = strchr(p, '\n');
1567 } else {
1568 p = NULL;
1572 if( drop_len && drop_len < 65535 ) {
1573 TSXQueryPointer( display, X11DRV_GetXRootWindow(), &u.w_aux, &u.w_aux,
1574 &x, &y, &u.i, &u.i, &u.i);
1576 pDropWnd = WIN_FindWndPtr( hWnd );
1578 if (drop32) {
1579 LPDROPFILESTRUCT lpDrop;
1580 drop_len += sizeof(DROPFILESTRUCT) + 1;
1581 hDrop.h32 = (HDROP)GlobalAlloc( GMEM_SHARE, drop_len );
1582 lpDrop = (LPDROPFILESTRUCT) GlobalLock( hDrop.h32 );
1584 if( lpDrop ) {
1585 lpDrop->lSize = sizeof(DROPFILESTRUCT);
1586 lpDrop->ptMousePos.x = (INT)x;
1587 lpDrop->ptMousePos.y = (INT)y;
1588 lpDrop->fInNonClientArea = (BOOL)
1589 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1590 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1591 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1592 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1593 lpDrop->fWideChar = FALSE;
1594 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT);
1596 } else {
1597 LPDROPFILESTRUCT16 lpDrop;
1598 drop_len += sizeof(DROPFILESTRUCT16) + 1;
1599 hDrop.h16 = (HDROP16)GlobalAlloc16( GMEM_SHARE, drop_len );
1600 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop.h16 );
1602 if( lpDrop ) {
1603 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1604 lpDrop->ptMousePos.x = (INT16)x;
1605 lpDrop->ptMousePos.y = (INT16)y;
1606 lpDrop->fInNonClientArea = (BOOL16)
1607 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1608 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1609 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1610 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1611 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1615 /* create message content */
1616 if (p_drop) {
1617 p = p_data;
1618 next = strchr(p, '\n');
1619 while (p) {
1620 if (next) *next=0;
1621 if (strncmp(p,"file:",5) == 0 ) {
1622 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1623 if (len) {
1624 TRACE_(event)("drop file %s as %s\n", p+5, p_drop);
1625 p_drop += len+1;
1626 } else {
1627 WARN_(event)("can't convert file %s to dos name \n", p+5);
1629 } else {
1630 WARN_(event)("unknown mime type %s\n", p);
1632 if (next) {
1633 *next = '\n';
1634 p = next + 1;
1635 next = strchr(p, '\n');
1636 } else {
1637 p = NULL;
1639 *p_drop = '\0';
1642 if (drop32) {
1643 /* can not use PostMessage32A because it is currently based on
1644 * PostMessage16 and WPARAM32 would be truncated to WPARAM16
1646 GlobalUnlock(hDrop.h32);
1647 SendMessageA( hWnd, WM_DROPFILES,
1648 (WPARAM)hDrop.h32, 0L );
1649 } else {
1650 GlobalUnlock16(hDrop.h16);
1651 PostMessage16( hWnd, WM_DROPFILES,
1652 (WPARAM16)hDrop.h16, 0L );
1655 WIN_ReleaseWndPtr(pDropWnd);
1657 if( p_data ) TSXFree(p_data);
1661 /**********************************************************************
1662 * EVENT_ClientMessage
1664 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
1666 if (event->message_type != None && event->format == 32) {
1667 if ((event->message_type == wmProtocols) &&
1668 (((Atom) event->data.l[0]) == wmDeleteWindow))
1670 /* Ignore the delete window request if the window has been disabled
1671 * and we are in managed mode. This is to disallow applications from
1672 * being closed by the window manager while in a modal state.
1674 BOOL bIsDisabled;
1675 bIsDisabled = GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED;
1677 if ( !Options.managed || !bIsDisabled )
1678 PostMessage16( hWnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
1680 else if ( event->message_type == dndProtocol &&
1681 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
1682 EVENT_DropFromOffiX(hWnd, event);
1683 else if ( event->message_type == dndProtocol &&
1684 event->data.l[0] == DndURL )
1685 EVENT_DropURLs(hWnd, event);
1686 else {
1687 #if 0
1688 /* enable this if you want to see the message */
1689 unsigned char* p_data = NULL;
1690 union {
1691 unsigned long l;
1692 int i;
1693 Atom atom;
1694 } u; /* unused */
1695 TSXGetWindowProperty( display, DefaultRootWindow(display),
1696 dndSelection, 0, 65535, FALSE,
1697 AnyPropertyType, &u.atom, &u.i,
1698 &u.l, &u.l, &p_data);
1699 TRACE_(event)("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1700 event->message_type, event->data.l[0], event->data.l[1],
1701 event->data.l[2], event->data.l[3], event->data.l[4],
1702 p_data);
1703 #endif
1704 TRACE_(event)("unrecognized ClientMessage\n" );
1709 /**********************************************************************
1710 * EVENT_EnterNotify
1712 * Install colormap when Wine window is focused in
1713 * self-managed mode with private colormap
1715 #if 0
1716 void EVENT_EnterNotify( HWND hWnd, XCrossingEvent *event )
1718 if( !Options.managed && X11DRV_GetXRootWindow() == DefaultRootWindow(display) &&
1719 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus() )
1720 TSXInstallColormap( display, X11DRV_PALETTE_GetColormap() );
1722 #endif
1724 /**********************************************************************
1725 * EVENT_MapNotify
1727 void EVENT_MapNotify( HWND hWnd, XMapEvent *event )
1729 HWND hwndFocus = GetFocus();
1730 WND *wndFocus = WIN_FindWndPtr(hwndFocus);
1731 WND *pWnd = WIN_FindWndPtr(hWnd);
1732 if (pWnd->flags & WIN_MANAGED)
1733 pWnd->dwStyle &= ~WS_MINIMIZE;
1734 WIN_ReleaseWndPtr(pWnd);
1736 if (hwndFocus && IsChild( hWnd, hwndFocus ))
1737 X11DRV_WND_SetFocus(wndFocus);
1739 WIN_ReleaseWndPtr(wndFocus);
1741 return;
1745 /**********************************************************************
1746 * EVENT_MapNotify
1748 void EVENT_UnmapNotify( HWND hWnd, XUnmapEvent *event )
1750 WND *pWnd = WIN_FindWndPtr(hWnd);
1751 if (pWnd->flags & WIN_MANAGED)
1753 EndMenu();
1754 if( pWnd->dwStyle & WS_VISIBLE )
1755 pWnd->dwStyle |= WS_MINIMIZE;
1757 WIN_ReleaseWndPtr(pWnd);
1761 #endif /* !defined(X_DISPLAY_MISSING) */