Small atom fixes.
[wine/multimedia.git] / windows / event.c
blob5858387171e8af983c7c7156da18a0f0ac5bd548
1 /*
2 * X events handling functions
3 *
4 * Copyright 1993 Alexandre Julliard
5 *
6 */
8 #include <assert.h>
9 #include <ctype.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <sys/time.h>
14 #include <sys/types.h>
15 #include <errno.h>
16 #include <X11/keysym.h>
17 #include "ts_xlib.h"
18 #include "ts_xresource.h"
19 #include "ts_xutil.h"
20 #include <X11/Xatom.h>
22 #include "windows.h"
23 #include "winnt.h"
24 #include "gdi.h"
25 #include "heap.h"
26 #include "queue.h"
27 #include "win.h"
28 #include "class.h"
29 #include "clipboard.h"
30 #include "dce.h"
31 #include "message.h"
32 #include "module.h"
33 #include "options.h"
34 #include "queue.h"
35 #include "winpos.h"
36 #include "drive.h"
37 #include "shell.h"
38 #include "keyboard.h"
39 #include "mouse.h"
40 #include "debug.h"
41 #include "dde_proc.h"
42 #include "winsock.h"
43 #include "mouse.h"
46 #define NB_BUTTONS 3 /* Windows can handle 3 buttons */
48 #define DndNotDnd -1 /* OffiX drag&drop */
49 #define DndUnknown 0
50 #define DndRawData 1
51 #define DndFile 2
52 #define DndFiles 3
53 #define DndText 4
54 #define DndDir 5
55 #define DndLink 6
56 #define DndExe 7
58 #define DndEND 8
60 #define DndURL 128 /* KDE drag&drop */
63 /* X context to associate a hwnd to an X window */
64 static XContext winContext = 0;
66 static Atom wmProtocols = None;
67 static Atom wmDeleteWindow = None;
68 static Atom dndProtocol = None;
69 static Atom dndSelection = None;
71 /* EVENT_WaitNetEvent() master fd sets */
73 static fd_set __event_io_set[3];
74 static int __event_max_fd = 0;
75 static int __event_x_connection = 0;
77 static const char * const event_names[] =
79 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
80 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
81 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
82 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
83 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
84 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
85 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
86 "ClientMessage", "MappingNotify"
89 /* Event handlers */
90 static void EVENT_Key( WND *pWnd, XKeyEvent *event );
91 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event );
92 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event );
93 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event );
94 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event );
95 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event );
96 static int EVENT_Expose( WND *pWnd, XExposeEvent *event );
97 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event );
98 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event );
99 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event);
100 static void EVENT_SelectionNotify( XSelectionEvent *event);
101 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event);
102 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event );
103 static void EVENT_MapNotify( HWND32 hwnd, XMapEvent *event );
105 /* Usable only with OLVWM - compile option perhaps?
106 static void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event );
109 static void EVENT_GetGeometry( Window win, int *px, int *py,
110 unsigned int *pwidth, unsigned int *pheight );
112 /***********************************************************************
113 * EVENT_Init
115 * Initialize network IO.
117 BOOL32 EVENT_Init(void)
119 int i;
120 for( i = 0; i < 3; i++ )
121 FD_ZERO( __event_io_set + i );
123 __event_max_fd = __event_x_connection = ConnectionNumber(display);
124 FD_SET( __event_x_connection, &__event_io_set[EVENT_IO_READ] );
125 __event_max_fd++;
126 return TRUE;
129 /***********************************************************************
130 * EVENT_AddIO
132 void EVENT_AddIO( int fd, unsigned io_type )
134 FD_SET( fd, &__event_io_set[io_type] );
135 if( __event_max_fd <= fd ) __event_max_fd = fd + 1;
138 void EVENT_DeleteIO( int fd, unsigned io_type )
140 FD_CLR( fd, &__event_io_set[io_type] );
143 /***********************************************************************
144 * EVENT_ProcessEvent
146 * Process an X event.
148 void EVENT_ProcessEvent( XEvent *event )
150 WND *pWnd;
152 if ( TSXFindContext( display, event->xany.window, winContext,
153 (char **)&pWnd ) != 0) {
154 if ( event->type == ClientMessage) {
155 /* query window (drag&drop event contains only drag window) */
156 Window root, child;
157 int root_x, root_y, child_x, child_y;
158 unsigned u;
159 TSXQueryPointer( display, rootWindow, &root, &child,
160 &root_x, &root_y, &child_x, &child_y, &u);
161 if (TSXFindContext( display, child, winContext, (char **)&pWnd ) != 0)
162 return;
163 } else {
164 pWnd = NULL; /* Not for a registered window */
168 TRACE(event, "Got event %s for hwnd %04x\n",
169 event_names[event->type], pWnd? pWnd->hwndSelf : 0 );
171 switch(event->type)
173 case KeyPress:
174 case KeyRelease:
175 EVENT_Key( pWnd, (XKeyEvent*)event );
176 break;
178 case ButtonPress:
179 EVENT_ButtonPress( pWnd, (XButtonEvent*)event );
180 break;
182 case ButtonRelease:
183 EVENT_ButtonRelease( pWnd, (XButtonEvent*)event );
184 break;
186 case MotionNotify:
187 /* Wine between two fast machines across the overloaded campus
188 ethernet gets very boged down in MotionEvents. The following
189 simply finds the last motion event in the queue and drops
190 the rest. On a good link events are servered before they build
191 up so this doesn't take place. On a slow link this may cause
192 problems if the event order is important. I'm not yet seen
193 of any problems. Jon 7/6/96.
195 while (TSXCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
196 MotionNotify, event));
197 EVENT_MotionNotify( pWnd, (XMotionEvent*)event );
198 break;
200 case FocusIn:
201 if (!pWnd) return;
202 EVENT_FocusIn( pWnd, (XFocusChangeEvent*)event );
203 break;
205 case FocusOut:
206 if (!pWnd) return;
207 EVENT_FocusOut( pWnd, (XFocusChangeEvent*)event );
208 break;
210 case Expose:
211 if (!pWnd) return;
212 if (EVENT_Expose( pWnd, (XExposeEvent *)event )) {
213 /* need to process ConfigureNotify first */
214 XEvent new_event;
216 /* attempt to find and process the ConfigureNotify event now */
217 if (TSXCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
218 ConfigureNotify, &new_event)) {
219 EVENT_ProcessEvent( &new_event );
220 EVENT_Expose( pWnd, (XExposeEvent *)event );
221 break;
224 /* no luck at this time, defer Expose event for later */
225 if (!pWnd->expose_event) pWnd->expose_event = malloc( sizeof(XExposeEvent) );
226 else { FIXME(x11,"can't handle more than one deferred Expose events\n"); }
227 *(pWnd->expose_event) = *(XExposeEvent *)event;
229 break;
231 case GraphicsExpose:
232 if (!pWnd) return;
233 EVENT_GraphicsExpose( pWnd, (XGraphicsExposeEvent *)event );
234 break;
236 case ConfigureNotify:
237 if (!pWnd) return;
238 EVENT_ConfigureNotify( pWnd, (XConfigureEvent*)event );
239 if (pWnd->expose_event) {
240 /* process deferred Expose event */
241 EVENT_Expose( pWnd, pWnd->expose_event );
242 free( pWnd->expose_event );
243 pWnd->expose_event = NULL;
245 break;
247 case SelectionRequest:
248 if (!pWnd) return;
249 EVENT_SelectionRequest( pWnd, (XSelectionRequestEvent *)event );
250 break;
252 case SelectionNotify:
253 if (!pWnd) return;
254 EVENT_SelectionNotify( (XSelectionEvent *)event );
255 break;
257 case SelectionClear:
258 if (!pWnd) return;
259 EVENT_SelectionClear( pWnd, (XSelectionClearEvent*) event );
260 break;
262 case ClientMessage:
263 if (!pWnd) return;
264 EVENT_ClientMessage( pWnd, (XClientMessageEvent *) event );
265 break;
267 /* case EnterNotify:
268 * EVENT_EnterNotify( pWnd, (XCrossingEvent *) event );
269 * break;
271 case NoExpose:
272 break;
274 /* We get all these because of StructureNotifyMask. */
275 case UnmapNotify:
276 case CirculateNotify:
277 case CreateNotify:
278 case DestroyNotify:
279 case GravityNotify:
280 case ReparentNotify:
281 break;
283 case MapNotify:
284 if (!pWnd) return;
285 EVENT_MapNotify( pWnd->hwndSelf, (XMapEvent *)event );
286 break;
288 default:
289 WARN(event, "Unprocessed event %s for hwnd %04x\n",
290 event_names[event->type], pWnd? pWnd->hwndSelf : 0 );
291 break;
296 /***********************************************************************
297 * EVENT_RegisterWindow
299 * Associate an X window to a HWND.
301 void EVENT_RegisterWindow( WND *pWnd )
303 if (wmProtocols == None)
304 wmProtocols = TSXInternAtom( display, "WM_PROTOCOLS", True );
305 if (wmDeleteWindow == None)
306 wmDeleteWindow = TSXInternAtom( display, "WM_DELETE_WINDOW", True );
307 if( dndProtocol == None )
308 dndProtocol = TSXInternAtom( display, "DndProtocol" , False );
309 if( dndSelection == None )
310 dndSelection = TSXInternAtom( display, "DndSelection" , False );
312 TSXSetWMProtocols( display, pWnd->window, &wmDeleteWindow, 1 );
314 if (!winContext) winContext = TSXUniqueContext();
315 TSXSaveContext( display, pWnd->window, winContext, (char *)pWnd );
318 /***********************************************************************
319 * EVENT_DestroyWindow
321 void EVENT_DestroyWindow( WND *pWnd )
323 XEvent xe;
325 if (pWnd->expose_event) {
326 free( pWnd->expose_event );
327 pWnd->expose_event = NULL;
329 TSXDeleteContext( display, pWnd->window, winContext );
330 TSXDestroyWindow( display, pWnd->window );
331 while( TSXCheckWindowEvent(display, pWnd->window, NoEventMask, &xe) );
335 /***********************************************************************
336 * IsUserIdle (USER.333)
338 * Check if we have pending X events.
340 BOOL16 WINAPI IsUserIdle(void)
342 struct timeval timeout = {0, 0};
343 fd_set check_set;
345 FD_ZERO(&check_set);
346 FD_SET(__event_x_connection, &check_set);
347 if( select(__event_x_connection + 1, &check_set, NULL, NULL, &timeout) > 0 )
348 return TRUE;
349 return FALSE;
353 /***********************************************************************
354 * EVENT_WaitNetEvent
356 * Wait for a network event, optionally sleeping until one arrives.
357 * Return TRUE if an event is pending, FALSE on timeout or error
358 * (for instance lost connection with the server).
360 BOOL32 EVENT_WaitNetEvent( BOOL32 sleep, BOOL32 peek )
362 XEvent event;
363 LONG maxWait = sleep ? TIMER_GetNextExpiration() : 0;
364 int pending = TSXPending(display);
366 /* Wait for an event or a timeout. If maxWait is -1, we have no timeout;
367 * in this case, we fall through directly to the XNextEvent loop.
370 if ((maxWait != -1) && !pending)
372 int num_pending;
373 struct timeval timeout;
374 fd_set io_set[3];
376 memcpy( io_set, __event_io_set, sizeof(io_set) );
378 timeout.tv_usec = (maxWait % 1000) * 1000;
379 timeout.tv_sec = maxWait / 1000;
381 #ifdef CONFIG_IPC
382 sigsetjmp(env_wait_x, 1);
383 stop_wait_op= CONT;
385 if (DDE_GetRemoteMessage()) {
386 while(DDE_GetRemoteMessage())
388 return TRUE;
390 stop_wait_op = STOP_WAIT_X;
391 /* The code up to the next "stop_wait_op = CONT" must be reentrant */
392 num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
393 &io_set[EVENT_IO_WRITE],
394 &io_set[EVENT_IO_EXCEPT], &timeout );
395 if ( num_pending == 0 )
397 stop_wait_op = CONT;
398 TIMER_ExpireTimers();
399 return FALSE;
401 else stop_wait_op = CONT;
402 #else /* CONFIG_IPC */
403 num_pending = select( __event_max_fd, &io_set[EVENT_IO_READ],
404 &io_set[EVENT_IO_WRITE],
405 &io_set[EVENT_IO_EXCEPT], &timeout );
406 if ( num_pending == 0)
408 /* Timeout or error */
409 TIMER_ExpireTimers();
410 return FALSE;
412 #endif /* CONFIG_IPC */
414 /* Winsock asynchronous services */
416 if( FD_ISSET( __event_x_connection, &io_set[EVENT_IO_READ]) )
418 num_pending--;
419 if( num_pending )
420 WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
422 else /* no X events */
423 return WINSOCK_HandleIO( &__event_max_fd, num_pending, io_set, __event_io_set );
425 else if(!pending)
426 { /* Wait for X11 input. */
427 fd_set set;
429 FD_ZERO(&set);
430 FD_SET(__event_x_connection, &set);
431 select(__event_x_connection + 1, &set, 0, 0, 0 );
434 /* Process current X event (and possibly others that occurred in the meantime) */
436 EnterCriticalSection(&X11DRV_CritSection);
437 while (XPending( display ))
440 #ifdef CONFIG_IPC
441 if (DDE_GetRemoteMessage())
443 LeaveCriticalSection(&X11DRV_CritSection);
444 while(DDE_GetRemoteMessage()) ;
445 return TRUE;
447 #endif /* CONFIG_IPC */
449 XNextEvent( display, &event );
451 LeaveCriticalSection(&X11DRV_CritSection);
452 if( peek )
454 WND* pWnd;
455 MESSAGEQUEUE* pQ;
458 /* Check only for those events which can be processed
459 * internally. */
461 if( event.type == MotionNotify ||
462 event.type == ButtonPress || event.type == ButtonRelease ||
463 event.type == KeyPress || event.type == KeyRelease ||
464 event.type == SelectionRequest || event.type == SelectionClear ||
465 event.type == ClientMessage )
467 EVENT_ProcessEvent( &event );
468 continue;
471 if (TSXFindContext( display, ((XAnyEvent *)&event)->window, winContext,
472 (char **)&pWnd ) || (event.type == NoExpose))
473 pWnd = NULL;
475 if( pWnd )
477 if( (pQ = (MESSAGEQUEUE*)GlobalLock16(pWnd->hmemTaskQ)) )
479 pQ->flags |= QUEUE_FLAG_XEVENT;
480 PostEvent(pQ->hTask);
481 TSXPutBackEvent(display, &event);
482 break;
486 else EVENT_ProcessEvent( &event );
487 EnterCriticalSection(&X11DRV_CritSection);
489 LeaveCriticalSection(&X11DRV_CritSection);
490 return TRUE;
494 /***********************************************************************
495 * EVENT_Synchronize
497 * Synchronize with the X server. Should not be used too often.
499 void EVENT_Synchronize()
501 XEvent event;
503 /* Use of the X critical section is needed or we have a small
504 * race between XPending() and XNextEvent().
506 EnterCriticalSection( &X11DRV_CritSection );
507 XSync( display, False );
508 while (XPending( display ))
510 XNextEvent( display, &event );
511 /* unlock X critsection for EVENT_ProcessEvent() might switch tasks */
512 LeaveCriticalSection( &X11DRV_CritSection );
513 EVENT_ProcessEvent( &event );
514 EnterCriticalSection( &X11DRV_CritSection );
516 LeaveCriticalSection( &X11DRV_CritSection );
519 /***********************************************************************
520 * EVENT_QueryZOrder
522 * Try to synchronize internal z-order with the window manager's.
523 * Probably a futile endeavor.
525 static BOOL32 __check_query_condition( WND** pWndA, WND** pWndB )
527 /* return TRUE if we have at least two managed windows */
529 for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
530 if( (*pWndA)->flags & WIN_MANAGED &&
531 (*pWndA)->dwStyle & WS_VISIBLE ) break;
532 if( *pWndA )
533 for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
534 if( (*pWndB)->flags & WIN_MANAGED &&
535 (*pWndB)->dwStyle & WS_VISIBLE ) break;
536 return ((*pWndB) != NULL);
539 static Window __get_common_ancestor( Window A, Window B,
540 Window** children, unsigned* total )
542 /* find the real root window */
544 Window root, *childrenB;
545 unsigned totalB;
549 if( *children ) TSXFree( *children );
550 TSXQueryTree( display, A, &root, &A, children, total );
551 TSXQueryTree( display, B, &root, &B, &childrenB, &totalB );
552 if( childrenB ) TSXFree( childrenB );
553 } while( A != B && A && B );
554 return ( A && B ) ? A : 0 ;
557 static Window __get_top_decoration( Window w, Window ancestor )
559 Window* children, root, prev = w, parent = w;
560 unsigned total;
564 w = parent;
565 TSXQueryTree( display, w, &root, &parent, &children, &total );
566 if( children ) TSXFree( children );
567 } while( parent && parent != ancestor );
568 TRACE(event, "\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
569 return ( parent ) ? w : 0 ;
572 static unsigned __td_lookup( Window w, Window* list, unsigned max )
574 unsigned i;
575 for( i = 0; i < max; i++ ) if( list[i] == w ) break;
576 return i;
579 static BOOL32 EVENT_QueryZOrder( WND* pWndCheck )
581 BOOL32 bRet = FALSE;
582 HWND32 hwndInsertAfter = HWND_TOP;
583 WND* pWnd, *pWndZ = WIN_GetDesktop()->child;
584 Window w, parent, *children = NULL;
585 unsigned total, check, pos, best;
587 if( !__check_query_condition(&pWndZ, &pWnd) ) return TRUE;
589 parent = __get_common_ancestor( pWndZ->window, pWnd->window,
590 &children, &total );
591 if( parent && children )
593 w = __get_top_decoration( pWndCheck->window, parent );
594 if( w != children[total - 1] )
596 check = __td_lookup( w, children, total );
597 best = total;
598 for( pWnd = pWndZ; pWnd; pWnd = pWnd->next )
600 if( pWnd != pWndCheck )
602 if( !(pWnd->flags & WIN_MANAGED) ||
603 !(w = __get_top_decoration( pWnd->window, parent )) )
604 continue;
605 pos = __td_lookup( w, children, total );
606 if( pos < best && pos > check )
608 best = pos;
609 hwndInsertAfter = pWnd->hwndSelf;
611 if( check - best == 1 ) break;
614 WIN_UnlinkWindow( pWndCheck->hwndSelf );
615 WIN_LinkWindow( pWndCheck->hwndSelf, hwndInsertAfter);
618 if( children ) TSXFree( children );
619 return bRet;
623 /***********************************************************************
624 * EVENT_XStateToKeyState
626 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
627 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
629 static WORD EVENT_XStateToKeyState( int state )
631 int kstate = 0;
633 if (state & Button1Mask) kstate |= MK_LBUTTON;
634 if (state & Button2Mask) kstate |= MK_MBUTTON;
635 if (state & Button3Mask) kstate |= MK_RBUTTON;
636 if (state & ShiftMask) kstate |= MK_SHIFT;
637 if (state & ControlMask) kstate |= MK_CONTROL;
638 return kstate;
641 /***********************************************************************
642 * EVENT_QueryPointer
644 BOOL32 EVENT_QueryPointer( DWORD *posX, DWORD *posY, DWORD *state )
646 Window root, child;
647 int rootX, rootY, winX, winY;
648 unsigned int xstate;
650 if (!TSXQueryPointer( display, rootWindow, &root, &child,
651 &rootX, &rootY, &winX, &winY, &xstate ))
652 return FALSE;
654 *posX = (DWORD)winX;
655 *posY = (DWORD)winY;
656 *state = EVENT_XStateToKeyState( xstate );
658 return TRUE;
661 /***********************************************************************
662 * EVENT_Expose
664 static int EVENT_Expose( WND *pWnd, XExposeEvent *event )
666 RECT32 rect;
667 int x, y;
668 unsigned int width, height;
670 /* When scrolling, many (fvwm2-based) window managers send the Expose
671 * event before sending the ConfigureNotify event, and we don't like
672 * that, so before processing the Expose event, we check whether the
673 * geometry has changed, and if so, we defer the Expose event until
674 * we get the ConfigureNotify event. -Ove KÃ¥ven */
675 EVENT_GetGeometry( event->window, &x, &y, &width, &height );
677 if ( x != pWnd->rectWindow.left || y != pWnd->rectWindow.top ||
678 (width != pWnd->rectWindow.right - pWnd->rectWindow.left) ||
679 (height != pWnd->rectWindow.bottom - pWnd->rectWindow.top))
680 return 1; /* tell EVENT_ProcessEvent() to defer it */
682 /* Make position relative to client area instead of window */
683 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
684 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
685 rect.right = rect.left + event->width;
686 rect.bottom = rect.top + event->height;
688 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
689 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
690 (event->count ? 0 : RDW_ERASENOW), 0 );
691 return 0;
695 /***********************************************************************
696 * EVENT_GraphicsExpose
698 * This is needed when scrolling area is partially obscured
699 * by non-Wine X window.
701 static void EVENT_GraphicsExpose( WND *pWnd, XGraphicsExposeEvent *event )
703 RECT32 rect;
705 /* Make position relative to client area instead of window */
706 rect.left = event->x - (pWnd->rectClient.left - pWnd->rectWindow.left);
707 rect.top = event->y - (pWnd->rectClient.top - pWnd->rectWindow.top);
708 rect.right = rect.left + event->width;
709 rect.bottom = rect.top + event->height;
711 PAINT_RedrawWindow( pWnd->hwndSelf, &rect, 0,
712 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
713 (event->count ? 0 : RDW_ERASENOW), 0 );
717 /***********************************************************************
718 * EVENT_Key
720 * Handle a X key event
722 static void EVENT_Key( WND *pWnd, XKeyEvent *event )
724 KEYBOARD_HandleEvent( pWnd, event );
728 /***********************************************************************
729 * EVENT_MotionNotify
731 static void EVENT_MotionNotify( WND *pWnd, XMotionEvent *event )
733 int xOffset = pWnd? pWnd->rectWindow.left : 0;
734 int yOffset = pWnd? pWnd->rectWindow.top : 0;
736 MOUSE_SendEvent( MOUSEEVENTF_MOVE,
737 xOffset + event->x, yOffset + event->y,
738 EVENT_XStateToKeyState( event->state ),
739 event->time - MSG_WineStartTicks,
740 pWnd? pWnd->hwndSelf : 0 );
744 /***********************************************************************
745 * EVENT_DummyMotionNotify
747 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
749 void EVENT_DummyMotionNotify(void)
751 DWORD winX, winY, state;
753 if ( EVENT_QueryPointer( &winX, &winY, &state ) )
755 MOUSE_SendEvent( MOUSEEVENTF_MOVE, winX, winY, state,
756 GetTickCount(), 0 );
761 /***********************************************************************
762 * EVENT_ButtonPress
764 static void EVENT_ButtonPress( WND *pWnd, XButtonEvent *event )
766 static WORD statusCodes[NB_BUTTONS] =
767 { MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_RIGHTDOWN };
768 int buttonNum = event->button - 1;
770 int xOffset = pWnd? pWnd->rectWindow.left : 0;
771 int yOffset = pWnd? pWnd->rectWindow.top : 0;
773 if (buttonNum >= NB_BUTTONS) return;
775 MOUSE_SendEvent( statusCodes[buttonNum],
776 xOffset + event->x, yOffset + event->y,
777 EVENT_XStateToKeyState( event->state ),
778 event->time - MSG_WineStartTicks,
779 pWnd? pWnd->hwndSelf : 0 );
783 /***********************************************************************
784 * EVENT_ButtonRelease
786 static void EVENT_ButtonRelease( WND *pWnd, XButtonEvent *event )
788 static WORD statusCodes[NB_BUTTONS] =
789 { MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_RIGHTUP };
790 int buttonNum = event->button - 1;
792 int xOffset = pWnd? pWnd->rectWindow.left : 0;
793 int yOffset = pWnd? pWnd->rectWindow.top : 0;
795 if (buttonNum >= NB_BUTTONS) return;
797 MOUSE_SendEvent( statusCodes[buttonNum],
798 xOffset + event->x, yOffset + event->y,
799 EVENT_XStateToKeyState( event->state ),
800 event->time - MSG_WineStartTicks,
801 pWnd? pWnd->hwndSelf : 0 );
805 /**********************************************************************
806 * EVENT_FocusIn
808 static void EVENT_FocusIn( WND *pWnd, XFocusChangeEvent *event )
810 if (Options.managed) EVENT_QueryZOrder( pWnd );
812 if (event->detail != NotifyPointer)
814 HWND32 hwnd = pWnd->hwndSelf;
816 if (hwnd != GetActiveWindow32())
818 WINPOS_ChangeActiveWindow( hwnd, FALSE );
819 KEYBOARD_UpdateState();
821 if ((hwnd != GetFocus32()) && !IsChild32( hwnd, GetFocus32()))
822 SetFocus32( hwnd );
827 /**********************************************************************
828 * EVENT_FocusOut
830 * Note: only top-level override-redirect windows get FocusOut events.
832 static void EVENT_FocusOut( WND *pWnd, XFocusChangeEvent *event )
834 if (event->detail != NotifyPointer)
836 HWND32 hwnd = pWnd->hwndSelf;
838 if (hwnd == GetActiveWindow32())
839 WINPOS_ChangeActiveWindow( 0, FALSE );
840 if ((hwnd == GetFocus32()) || IsChild32( hwnd, GetFocus32()))
841 SetFocus32( 0 );
845 /**********************************************************************
846 * EVENT_CheckFocus
848 BOOL32 EVENT_CheckFocus(void)
850 WND* pWnd;
851 Window xW;
852 int state;
854 TSXGetInputFocus(display, &xW, &state);
855 if( xW == None ||
856 TSXFindContext(display, xW, winContext, (char **)&pWnd) )
857 return FALSE;
858 return TRUE;
862 /**********************************************************************
863 * EVENT_GetGeometry
865 * Helper function for ConfigureNotify handling.
866 * Get the new geometry of a window relative to the root window.
868 static void EVENT_GetGeometry( Window win, int *px, int *py,
869 unsigned int *pwidth, unsigned int *pheight )
871 Window root, parent, *children;
872 int xpos, ypos;
873 unsigned int width, height, border, depth, nb_children;
875 if (!TSXGetGeometry( display, win, &root, px, py, pwidth, pheight,
876 &border, &depth )) return;
877 if (win == rootWindow)
879 *px = *py = 0;
880 return;
883 for (;;)
885 if (!TSXQueryTree(display, win, &root, &parent, &children, &nb_children))
886 return;
887 TSXFree( children );
888 if (parent == rootWindow) break;
889 win = parent;
890 if (!TSXGetGeometry( display, win, &root, &xpos, &ypos,
891 &width, &height, &border, &depth )) return;
892 *px += xpos;
893 *py += ypos;
898 /**********************************************************************
899 * EVENT_ConfigureNotify
901 * The ConfigureNotify event is only selected on top-level windows
902 * when the -managed flag is used.
904 static void EVENT_ConfigureNotify( WND *pWnd, XConfigureEvent *event )
906 WINDOWPOS32 winpos;
907 RECT32 newWindowRect, newClientRect;
908 HRGN32 hrgnOldPos, hrgnNewPos;
909 Window above = event->above;
910 int x, y;
911 unsigned int width, height;
913 assert (pWnd->flags & WIN_MANAGED);
915 /* We don't rely on the event geometry info, because it is relative
916 * to parent and not to root, and it may be wrong (XFree sets x,y to 0,0
917 * if the window hasn't moved).
919 EVENT_GetGeometry( event->window, &x, &y, &width, &height );
921 /* Fill WINDOWPOS struct */
922 winpos.flags = SWP_NOACTIVATE | SWP_NOZORDER;
923 winpos.hwnd = pWnd->hwndSelf;
924 winpos.x = x;
925 winpos.y = y;
926 winpos.cx = width;
927 winpos.cy = height;
929 /* Check for unchanged attributes */
930 if (winpos.x == pWnd->rectWindow.left && winpos.y == pWnd->rectWindow.top)
931 winpos.flags |= SWP_NOMOVE;
932 if ((winpos.cx == pWnd->rectWindow.right - pWnd->rectWindow.left) &&
933 (winpos.cy == pWnd->rectWindow.bottom - pWnd->rectWindow.top))
934 winpos.flags |= SWP_NOSIZE;
935 else
937 RECT32 rect = { 0, 0, pWnd->rectWindow.right - pWnd->rectWindow.left,
938 pWnd->rectWindow.bottom - pWnd->rectWindow.top };
939 DCE_InvalidateDCE( pWnd, &rect );
942 /* Send WM_WINDOWPOSCHANGING */
943 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)&winpos );
945 /* Calculate new position and size */
946 newWindowRect.left = x;
947 newWindowRect.right = x + width;
948 newWindowRect.top = y;
949 newWindowRect.bottom = y + height;
951 WINPOS_SendNCCalcSize( winpos.hwnd, TRUE, &newWindowRect,
952 &pWnd->rectWindow, &pWnd->rectClient,
953 &winpos, &newClientRect );
955 hrgnOldPos = CreateRectRgnIndirect32( &pWnd->rectWindow );
956 hrgnNewPos = CreateRectRgnIndirect32( &newWindowRect );
957 CombineRgn32( hrgnOldPos, hrgnOldPos, hrgnNewPos, RGN_DIFF );
958 DeleteObject32(hrgnOldPos);
959 DeleteObject32(hrgnNewPos);
961 /* Set new size and position */
962 pWnd->rectWindow = newWindowRect;
963 pWnd->rectClient = newClientRect;
964 SendMessage32A( winpos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)&winpos );
966 if (!IsWindow32( winpos.hwnd )) return;
967 if( above == None ) /* absolute bottom */
969 WIN_UnlinkWindow( winpos.hwnd );
970 WIN_LinkWindow( winpos.hwnd, HWND_BOTTOM);
972 else EVENT_QueryZOrder( pWnd ); /* try to outsmart window manager */
976 /***********************************************************************
977 * EVENT_SelectionRequest
979 static void EVENT_SelectionRequest( WND *pWnd, XSelectionRequestEvent *event )
981 XSelectionEvent result;
982 Atom rprop = None;
983 Window request = event->requestor;
985 if(event->target == XA_STRING)
987 HANDLE16 hText;
988 LPSTR text;
989 int size,i,j;
991 rprop = event->property;
993 if(rprop == None) rprop = event->target;
995 if(event->selection!=XA_PRIMARY) rprop = None;
996 else if(!CLIPBOARD_IsPresent(CF_OEMTEXT)) rprop = None;
997 else
999 /* open to make sure that clipboard is available */
1001 BOOL32 couldOpen = OpenClipboard32( pWnd->hwndSelf );
1002 char* lpstr = 0;
1004 hText = GetClipboardData16(CF_TEXT);
1005 text = GlobalLock16(hText);
1006 size = GlobalSize16(hText);
1008 /* remove carriage returns */
1010 lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
1011 for(i=0,j=0; i < size && text[i]; i++ )
1013 if( text[i] == '\r' &&
1014 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
1015 lpstr[j++] = text[i];
1017 lpstr[j]='\0';
1019 TSXChangeProperty(display, request, rprop,
1020 XA_STRING, 8, PropModeReplace,
1021 lpstr, j);
1022 HeapFree( GetProcessHeap(), 0, lpstr );
1024 /* close only if we opened before */
1026 if(couldOpen) CloseClipboard32();
1030 if(rprop == None)
1031 TRACE(event,"Request for %s ignored\n", TSXGetAtomName(display,event->target));
1033 result.type = SelectionNotify;
1034 result.display = display;
1035 result.requestor = request;
1036 result.selection = event->selection;
1037 result.property = rprop;
1038 result.target = event->target;
1039 result.time = event->time;
1040 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
1044 /***********************************************************************
1045 * EVENT_SelectionNotify
1047 static void EVENT_SelectionNotify( XSelectionEvent *event )
1049 if (event->selection != XA_PRIMARY) return;
1051 if (event->target != XA_STRING) CLIPBOARD_ReadSelection( 0, None );
1052 else CLIPBOARD_ReadSelection( event->requestor, event->property );
1054 TRACE(clipboard,"\tSelectionNotify done!\n");
1058 /***********************************************************************
1059 * EVENT_SelectionClear
1061 static void EVENT_SelectionClear( WND *pWnd, XSelectionClearEvent *event )
1063 if (event->selection != XA_PRIMARY) return;
1064 CLIPBOARD_ReleaseSelection( event->window, pWnd->hwndSelf );
1068 /**********************************************************************
1069 * EVENT_DropFromOffix
1071 * don't know if it still works (last Changlog is from 96/11/04)
1073 static void EVENT_DropFromOffiX( WND *pWnd, XClientMessageEvent *event )
1075 unsigned long data_length;
1076 unsigned long aux_long;
1077 unsigned char* p_data = NULL;
1078 union {
1079 Atom atom_aux;
1080 POINT32 pt_aux;
1081 int i;
1082 } u;
1083 int x, y;
1084 BOOL16 bAccept;
1085 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
1086 LPDRAGINFO lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
1087 SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
1088 Window w_aux_root, w_aux_child;
1089 WND* pDropWnd;
1091 if( !lpDragInfo || !spDragInfo ) return;
1093 TSXQueryPointer( display, pWnd->window, &w_aux_root, &w_aux_child,
1094 &x, &y, &u.pt_aux.x, &u.pt_aux.y, (unsigned int*)&aux_long);
1096 lpDragInfo->hScope = pWnd->hwndSelf;
1097 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1099 /* find out drop point and drop window */
1100 if( x < 0 || y < 0 ||
1101 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1102 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1103 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1104 else
1106 bAccept = DRAG_QueryUpdate( pWnd->hwndSelf, spDragInfo, TRUE );
1107 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1109 pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1110 GlobalFree16( hDragInfo );
1112 if( bAccept )
1114 TSXGetWindowProperty( display, DefaultRootWindow(display),
1115 dndSelection, 0, 65535, FALSE,
1116 AnyPropertyType, &u.atom_aux, &u.pt_aux.y,
1117 &data_length, &aux_long, &p_data);
1119 if( !aux_long && p_data) /* don't bother if > 64K */
1121 char *p = (char*) p_data;
1122 char *p_drop;
1124 aux_long = 0;
1125 while( *p ) /* calculate buffer size */
1127 p_drop = p;
1128 if((u.i = *p) != -1 )
1129 u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
1130 if( u.i == -1 ) *p = -1; /* mark as "bad" */
1131 else
1133 INT32 len = GetShortPathName32A( p, NULL, 0 );
1134 if (len) aux_long += len + 1;
1135 else *p = -1;
1137 p += strlen(p) + 1;
1139 if( aux_long && aux_long < 65535 )
1141 HDROP16 hDrop;
1142 LPDROPFILESTRUCT16 lpDrop;
1144 aux_long += sizeof(DROPFILESTRUCT16) + 1;
1145 hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
1146 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop );
1148 if( lpDrop )
1150 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1151 lpDrop->ptMousePos.x = (INT16)x;
1152 lpDrop->ptMousePos.y = (INT16)y;
1153 lpDrop->fInNonClientArea = (BOOL16)
1154 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1155 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1156 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1157 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1158 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1159 p = p_data;
1160 while(*p)
1162 if( *p != -1 ) /* use only "good" entries */
1164 GetShortPathName32A( p, p_drop, 65535 );
1165 p_drop += strlen( p_drop ) + 1;
1167 p += strlen(p) + 1;
1169 *p_drop = '\0';
1170 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1171 (WPARAM16)hDrop, 0L );
1175 if( p_data ) TSXFree(p_data);
1177 } /* WS_EX_ACCEPTFILES */
1180 /**********************************************************************
1181 * EVENT_DropURLs
1183 * drop items are separated by \n
1184 * each item is prefixed by its mime type
1186 * event->data.l[3], event->data.l[4] contains drop x,y position
1188 static void EVENT_DropURLs( WND *pWnd, XClientMessageEvent *event )
1190 WND *pDropWnd;
1191 unsigned long data_length;
1192 unsigned long aux_long, drop_len = 0;
1193 unsigned char *p_data = NULL; /* property data */
1194 char *p_drop = NULL;
1195 char *p, *next;
1196 int x, y, drop32 = FALSE ;
1197 union {
1198 Atom atom_aux;
1199 POINT32 pt_aux;
1200 int i;
1201 Window w_aux;
1202 } u; /* unused */
1203 union {
1204 HDROP16 h16;
1205 HDROP32 h32;
1206 } hDrop;
1208 drop32 = pWnd->flags & WIN_ISWIN32;
1210 if (!(pWnd->dwExStyle & WS_EX_ACCEPTFILES))
1211 return;
1213 TSXGetWindowProperty( display, DefaultRootWindow(display),
1214 dndSelection, 0, 65535, FALSE,
1215 AnyPropertyType, &u.atom_aux, &u.i,
1216 &data_length, &aux_long, &p_data);
1217 if (aux_long)
1218 WARN(event,"property too large, truncated!\n");
1219 TRACE(event,"urls=%s\n", p_data);
1221 if( !aux_long && p_data) { /* don't bother if > 64K */
1222 /* calculate length */
1223 p = p_data;
1224 next = strchr(p, '\n');
1225 while (p) {
1226 if (next) *next=0;
1227 if (strncmp(p,"file:",5) == 0 ) {
1228 INT32 len = GetShortPathName32A( p+5, NULL, 0 );
1229 if (len) drop_len += len + 1;
1231 if (next) {
1232 *next = '\n';
1233 p = next + 1;
1234 next = strchr(p, '\n');
1235 } else {
1236 p = NULL;
1240 if( drop_len && drop_len < 65535 ) {
1241 TSXQueryPointer( display, rootWindow, &u.w_aux, &u.w_aux,
1242 &x, &y, &u.i, &u.i, &u.i);
1243 pDropWnd = WIN_FindWndPtr( pWnd->hwndSelf );
1245 if (drop32) {
1246 LPDROPFILESTRUCT32 lpDrop;
1247 drop_len += sizeof(DROPFILESTRUCT32) + 1;
1248 hDrop.h32 = (HDROP32)GlobalAlloc32( GMEM_SHARE, drop_len );
1249 lpDrop = (LPDROPFILESTRUCT32) GlobalLock32( hDrop.h32 );
1251 if( lpDrop ) {
1252 lpDrop->lSize = sizeof(DROPFILESTRUCT32);
1253 lpDrop->ptMousePos.x = (INT32)x;
1254 lpDrop->ptMousePos.y = (INT32)y;
1255 lpDrop->fInNonClientArea = (BOOL32)
1256 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1257 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1258 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1259 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1260 lpDrop->fWideChar = FALSE;
1261 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT32);
1263 } else {
1264 LPDROPFILESTRUCT16 lpDrop;
1265 drop_len += sizeof(DROPFILESTRUCT16) + 1;
1266 hDrop.h16 = (HDROP16)GlobalAlloc16( GMEM_SHARE, drop_len );
1267 lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop.h16 );
1269 if( lpDrop ) {
1270 lpDrop->wSize = sizeof(DROPFILESTRUCT16);
1271 lpDrop->ptMousePos.x = (INT16)x;
1272 lpDrop->ptMousePos.y = (INT16)y;
1273 lpDrop->fInNonClientArea = (BOOL16)
1274 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1275 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1276 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1277 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1278 p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
1282 /* create message content */
1283 if (p_drop) {
1284 p = p_data;
1285 next = strchr(p, '\n');
1286 while (p) {
1287 if (next) *next=0;
1288 if (strncmp(p,"file:",5) == 0 ) {
1289 INT32 len = GetShortPathName32A( p+5, p_drop, 65535 );
1290 if (len) {
1291 TRACE(event, "drop file %s as %s\n", p+5, p_drop);
1292 p_drop += len+1;
1293 } else {
1294 WARN(event, "can't convert file %s to dos name \n", p+5);
1296 } else {
1297 WARN(event, "unknown mime type %s\n", p);
1299 if (next) {
1300 *next = '\n';
1301 p = next + 1;
1302 next = strchr(p, '\n');
1303 } else {
1304 p = NULL;
1306 *p_drop = '\0';
1309 if (drop32) {
1310 /* can not use PostMessage32A because it is currently based on
1311 * PostMessage16 and WPARAM32 would be truncated to WPARAM16
1313 GlobalUnlock32(hDrop.h32);
1314 SendMessage32A( pWnd->hwndSelf, WM_DROPFILES,
1315 (WPARAM32)hDrop.h32, 0L );
1316 } else {
1317 GlobalUnlock16(hDrop.h16);
1318 PostMessage16( pWnd->hwndSelf, WM_DROPFILES,
1319 (WPARAM16)hDrop.h16, 0L );
1323 if( p_data ) TSXFree(p_data);
1327 /**********************************************************************
1328 * EVENT_ClientMessage
1330 static void EVENT_ClientMessage( WND *pWnd, XClientMessageEvent *event )
1332 if (event->message_type != None && event->format == 32) {
1333 if ((event->message_type == wmProtocols) &&
1334 (((Atom) event->data.l[0]) == wmDeleteWindow))
1335 SendMessage16( pWnd->hwndSelf, WM_SYSCOMMAND, SC_CLOSE, 0 );
1336 else if ( event->message_type == dndProtocol &&
1337 (event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
1338 EVENT_DropFromOffiX(pWnd, event);
1339 else if ( event->message_type == dndProtocol &&
1340 event->data.l[0] == DndURL )
1341 EVENT_DropURLs(pWnd, event);
1342 else {
1343 #if 0
1344 /* enable this if you want to see the message */
1345 unsigned char* p_data = NULL;
1346 union {
1347 unsigned long l;
1348 int i;
1349 Atom atom;
1350 } u; /* unused */
1351 TSXGetWindowProperty( display, DefaultRootWindow(display),
1352 dndSelection, 0, 65535, FALSE,
1353 AnyPropertyType, &u.atom, &u.i,
1354 &u.l, &u.l, &p_data);
1355 TRACE(event, "message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1356 event->message_type, event->data.l[0], event->data.l[1],
1357 event->data.l[2], event->data.l[3], event->data.l[4],
1358 p_data);
1359 #endif
1360 TRACE(event, "unrecognized ClientMessage\n" );
1365 /**********************************************************************
1366 * EVENT_EnterNotify
1368 * Install colormap when Wine window is focused in
1369 * self-managed mode with private colormap
1372 void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
1374 if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
1375 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
1376 TSXInstallColormap( display, COLOR_GetColormap() );
1380 /**********************************************************************
1381 * EVENT_MapNotify
1383 void EVENT_MapNotify( HWND32 hWnd, XMapEvent *event )
1385 HWND32 hwndFocus = GetFocus32();
1387 if (hwndFocus && IsChild32( hWnd, hwndFocus ))
1388 FOCUS_SetXFocus( (HWND32)hwndFocus );
1390 return;