1297 lines
37 KiB
C
1297 lines
37 KiB
C
/*
|
|
* X11 event driver
|
|
*
|
|
* Copyright 1993 Alexandre Julliard
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#ifndef X_DISPLAY_MISSING
|
|
|
|
#include <X11/Xatom.h>
|
|
#include <X11/keysym.h>
|
|
#include "ts_xlib.h"
|
|
#include "ts_xresource.h"
|
|
#include "ts_xutil.h"
|
|
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include "callback.h"
|
|
#include "clipboard.h"
|
|
#include "dce.h"
|
|
#include "debugtools.h"
|
|
#include "drive.h"
|
|
#include "heap.h"
|
|
#include "keyboard.h"
|
|
#include "message.h"
|
|
#include "mouse.h"
|
|
#include "options.h"
|
|
#include "queue.h"
|
|
#include "shell.h"
|
|
#include "winpos.h"
|
|
#include "services.h"
|
|
#include "file.h"
|
|
#include "windef.h"
|
|
#include "x11drv.h"
|
|
|
|
DECLARE_DEBUG_CHANNEL(event)
|
|
DECLARE_DEBUG_CHANNEL(win)
|
|
|
|
/* X context to associate a hwnd to an X window */
|
|
extern XContext winContext;
|
|
|
|
extern Atom wmProtocols;
|
|
extern Atom wmDeleteWindow;
|
|
extern Atom dndProtocol;
|
|
extern Atom dndSelection;
|
|
|
|
extern void X11DRV_KEYBOARD_UpdateState(void);
|
|
extern void X11DRV_KEYBOARD_HandleEvent(WND *pWnd, XKeyEvent *event);
|
|
|
|
#define NB_BUTTONS 3 /* Windows can handle 3 buttons */
|
|
|
|
#define DndNotDnd -1 /* OffiX drag&drop */
|
|
#define DndUnknown 0
|
|
#define DndRawData 1
|
|
#define DndFile 2
|
|
#define DndFiles 3
|
|
#define DndText 4
|
|
#define DndDir 5
|
|
#define DndLink 6
|
|
#define DndExe 7
|
|
|
|
#define DndEND 8
|
|
|
|
#define DndURL 128 /* KDE drag&drop */
|
|
|
|
/* The last X window which had the focus */
|
|
static Window glastXFocusWin = 0;
|
|
|
|
static const char * const event_names[] =
|
|
{
|
|
"", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
|
|
"MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
|
|
"KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
|
|
"CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
|
|
"ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
|
|
"ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
|
|
"SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
|
|
"ClientMessage", "MappingNotify"
|
|
};
|
|
|
|
static void CALLBACK EVENT_Flush( ULONG_PTR arg );
|
|
static void CALLBACK EVENT_ProcessAllEvents( ULONG_PTR arg );
|
|
static void EVENT_ProcessEvent( XEvent *event );
|
|
|
|
/* Event handlers */
|
|
static void EVENT_Key( HWND hWnd, XKeyEvent *event );
|
|
static void EVENT_ButtonPress( HWND hWnd, XButtonEvent *event );
|
|
static void EVENT_ButtonRelease( HWND hWnd, XButtonEvent *event );
|
|
static void EVENT_MotionNotify( HWND hWnd, XMotionEvent *event );
|
|
static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event );
|
|
static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event );
|
|
static void EVENT_Expose( HWND hWnd, XExposeEvent *event );
|
|
static void EVENT_GraphicsExpose( HWND hWnd, XGraphicsExposeEvent *event );
|
|
static void EVENT_ConfigureNotify( HWND hWnd, XConfigureEvent *event );
|
|
static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event);
|
|
static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event);
|
|
static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event );
|
|
static void EVENT_MapNotify( HWND pWnd, XMapEvent *event );
|
|
static void EVENT_UnmapNotify( HWND pWnd, XUnmapEvent *event );
|
|
|
|
/* Usable only with OLVWM - compile option perhaps?
|
|
static void EVENT_EnterNotify( HWND hWnd, XCrossingEvent *event );
|
|
*/
|
|
|
|
static void EVENT_GetGeometry( Window win, int *px, int *py,
|
|
unsigned int *pwidth, unsigned int *pheight );
|
|
|
|
|
|
static BOOL bUserRepaintDisabled = TRUE;
|
|
|
|
|
|
/***********************************************************************
|
|
* EVENT_Init
|
|
*/
|
|
BOOL X11DRV_EVENT_Init(void)
|
|
{
|
|
/* Install the X event processing callback */
|
|
SERVICE_AddObject( FILE_DupUnixHandle( ConnectionNumber(display),
|
|
GENERIC_READ | SYNCHRONIZE ),
|
|
EVENT_ProcessAllEvents, 0 );
|
|
|
|
/* Install the XFlush timer callback */
|
|
if ( Options.synchronous )
|
|
TSXSynchronize( display, True );
|
|
else
|
|
SERVICE_AddTimer( 200000L, EVENT_Flush, 0 );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* EVENT_Flush
|
|
*/
|
|
static void CALLBACK EVENT_Flush( ULONG_PTR arg )
|
|
{
|
|
TSXFlush( display );
|
|
}
|
|
|
|
/***********************************************************************
|
|
* EVENT_ProcessAllEvents
|
|
*/
|
|
static void CALLBACK EVENT_ProcessAllEvents( ULONG_PTR arg )
|
|
{
|
|
XEvent event;
|
|
|
|
TRACE_(event)( "called.\n" );
|
|
|
|
EnterCriticalSection( &X11DRV_CritSection );
|
|
while ( XPending( display ) )
|
|
{
|
|
XNextEvent( display, &event );
|
|
|
|
LeaveCriticalSection( &X11DRV_CritSection );
|
|
EVENT_ProcessEvent( &event );
|
|
EnterCriticalSection( &X11DRV_CritSection );
|
|
}
|
|
LeaveCriticalSection( &X11DRV_CritSection );
|
|
}
|
|
|
|
/***********************************************************************
|
|
* EVENT_Synchronize
|
|
*
|
|
* Synchronize with the X server. Should not be used too often.
|
|
*/
|
|
void X11DRV_EVENT_Synchronize( void )
|
|
{
|
|
TSXSync( display, False );
|
|
EVENT_ProcessAllEvents( 0 );
|
|
}
|
|
|
|
/***********************************************************************
|
|
* EVENT_UserRepaintDisable
|
|
*/
|
|
void X11DRV_EVENT_UserRepaintDisable( BOOL bDisabled )
|
|
{
|
|
bUserRepaintDisabled = bDisabled;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* EVENT_ProcessEvent
|
|
*
|
|
* Process an X event.
|
|
*/
|
|
static void EVENT_ProcessEvent( XEvent *event )
|
|
{
|
|
HWND hWnd;
|
|
|
|
TRACE_(event)( "called.\n" );
|
|
|
|
switch (event->type)
|
|
{
|
|
case SelectionNotify: /* all of these should be caught by XCheckTypedWindowEvent() */
|
|
FIXME_(event)("Got SelectionNotify - must not happen!\n");
|
|
/* fall through */
|
|
|
|
/* We get all these because of StructureNotifyMask.
|
|
This check is placed here to avoid getting error messages below,
|
|
as X might send some of these even for windows that have already
|
|
been deleted ... */
|
|
case CirculateNotify:
|
|
case CreateNotify:
|
|
case DestroyNotify:
|
|
case GravityNotify:
|
|
case ReparentNotify:
|
|
return;
|
|
}
|
|
|
|
if ( TSXFindContext( display, event->xany.window, winContext,
|
|
(char **)&hWnd ) != 0) {
|
|
if ( event->type == ClientMessage) {
|
|
/* query window (drag&drop event contains only drag window) */
|
|
Window root, child;
|
|
int root_x, root_y, child_x, child_y;
|
|
unsigned u;
|
|
TSXQueryPointer( display, X11DRV_GetXRootWindow(), &root, &child,
|
|
&root_x, &root_y, &child_x, &child_y, &u);
|
|
if (TSXFindContext( display, child, winContext, (char **)&hWnd ) != 0)
|
|
return;
|
|
} else {
|
|
hWnd = 0; /* Not for a registered window */
|
|
}
|
|
}
|
|
|
|
if ( !hWnd && event->xany.window != X11DRV_GetXRootWindow() )
|
|
ERR_(event)("Got event %s for unknown Window %08lx\n",
|
|
event_names[event->type], event->xany.window );
|
|
else
|
|
TRACE_(event)("Got event %s for hwnd %04x\n",
|
|
event_names[event->type], hWnd );
|
|
|
|
|
|
switch(event->type)
|
|
{
|
|
case KeyPress:
|
|
case KeyRelease:
|
|
EVENT_Key( hWnd, (XKeyEvent*)event );
|
|
break;
|
|
|
|
case ButtonPress:
|
|
EVENT_ButtonPress( hWnd, (XButtonEvent*)event );
|
|
break;
|
|
|
|
case ButtonRelease:
|
|
EVENT_ButtonRelease( hWnd, (XButtonEvent*)event );
|
|
break;
|
|
|
|
case MotionNotify:
|
|
/* Wine between two fast machines across the overloaded campus
|
|
ethernet gets very boged down in MotionEvents. The following
|
|
simply finds the last motion event in the queue and drops
|
|
the rest. On a good link events are servered before they build
|
|
up so this doesn't take place. On a slow link this may cause
|
|
problems if the event order is important. I'm not yet seen
|
|
of any problems. Jon 7/6/96.
|
|
*/
|
|
while (TSXCheckTypedWindowEvent(display,((XAnyEvent *)event)->window,
|
|
MotionNotify, event));
|
|
EVENT_MotionNotify( hWnd, (XMotionEvent*)event );
|
|
break;
|
|
|
|
case FocusIn:
|
|
{
|
|
WND *pWndLastFocus = 0;
|
|
XWindowAttributes win_attr;
|
|
BOOL bIsDisabled;
|
|
XFocusChangeEvent *xfocChange = (XFocusChangeEvent*)event;
|
|
|
|
if (!hWnd || bUserRepaintDisabled) return;
|
|
|
|
bIsDisabled = GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED;
|
|
|
|
/* If the window has been disabled and we are in managed mode,
|
|
* revert the X focus back to the last focus window. This is to disallow
|
|
* the window manager from switching focus away while the app is
|
|
* in a modal state.
|
|
*/
|
|
if ( Options.managed && bIsDisabled && glastXFocusWin)
|
|
{
|
|
/* Change focus only if saved focus window is registered and viewable */
|
|
if ( TSXFindContext( xfocChange->display, glastXFocusWin, winContext,
|
|
(char **)&pWndLastFocus ) == 0 )
|
|
{
|
|
if ( TSXGetWindowAttributes( display, glastXFocusWin, &win_attr ) &&
|
|
(win_attr.map_state == IsViewable) )
|
|
{
|
|
TSXSetInputFocus( xfocChange->display, glastXFocusWin, RevertToParent, CurrentTime );
|
|
EVENT_Synchronize();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
EVENT_FocusIn( hWnd, xfocChange );
|
|
break;
|
|
}
|
|
|
|
case FocusOut:
|
|
{
|
|
/* Save the last window which had the focus */
|
|
XFocusChangeEvent *xfocChange = (XFocusChangeEvent*)event;
|
|
glastXFocusWin = xfocChange->window;
|
|
if (!hWnd || bUserRepaintDisabled) return;
|
|
EVENT_FocusOut( hWnd, (XFocusChangeEvent*)event );
|
|
break;
|
|
}
|
|
|
|
case Expose:
|
|
if (bUserRepaintDisabled) return;
|
|
EVENT_Expose( hWnd, (XExposeEvent *)event );
|
|
break;
|
|
|
|
case GraphicsExpose:
|
|
if (bUserRepaintDisabled) return;
|
|
EVENT_GraphicsExpose( hWnd, (XGraphicsExposeEvent *)event );
|
|
break;
|
|
|
|
case ConfigureNotify:
|
|
if (!hWnd || bUserRepaintDisabled) return;
|
|
EVENT_ConfigureNotify( hWnd, (XConfigureEvent*)event );
|
|
break;
|
|
|
|
case SelectionRequest:
|
|
if (!hWnd || bUserRepaintDisabled) return;
|
|
EVENT_SelectionRequest( hWnd, (XSelectionRequestEvent *)event );
|
|
break;
|
|
|
|
case SelectionClear:
|
|
if (!hWnd || bUserRepaintDisabled) return;
|
|
EVENT_SelectionClear( hWnd, (XSelectionClearEvent*) event );
|
|
break;
|
|
|
|
case ClientMessage:
|
|
if (!hWnd || bUserRepaintDisabled) return;
|
|
EVENT_ClientMessage( hWnd, (XClientMessageEvent *) event );
|
|
break;
|
|
|
|
#if 0
|
|
case EnterNotify:
|
|
EVENT_EnterNotify( hWnd, (XCrossingEvent *) event );
|
|
break;
|
|
#endif
|
|
|
|
case NoExpose:
|
|
break;
|
|
|
|
case MapNotify:
|
|
if (!hWnd || bUserRepaintDisabled) return;
|
|
EVENT_MapNotify( hWnd, (XMapEvent *)event );
|
|
break;
|
|
|
|
case UnmapNotify:
|
|
if (!hWnd || bUserRepaintDisabled) return;
|
|
EVENT_UnmapNotify( hWnd, (XUnmapEvent *)event );
|
|
break;
|
|
|
|
default:
|
|
WARN_(event)("Unprocessed event %s for hwnd %04x\n",
|
|
event_names[event->type], hWnd );
|
|
break;
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
* EVENT_QueryZOrder
|
|
*
|
|
* Synchronize internal z-order with the window manager's.
|
|
*/
|
|
static BOOL __check_query_condition( WND** pWndA, WND** pWndB )
|
|
{
|
|
/* return TRUE if we have at least two managed windows */
|
|
|
|
for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
|
|
if( (*pWndA)->flags & WIN_MANAGED &&
|
|
(*pWndA)->dwStyle & WS_VISIBLE ) break;
|
|
if( *pWndA )
|
|
for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
|
|
if( (*pWndB)->flags & WIN_MANAGED &&
|
|
(*pWndB)->dwStyle & WS_VISIBLE ) break;
|
|
return ((*pWndB) != NULL);
|
|
}
|
|
|
|
static Window __get_common_ancestor( Window A, Window B,
|
|
Window** children, unsigned* total )
|
|
{
|
|
/* find the real root window */
|
|
|
|
Window root, *childrenB;
|
|
unsigned totalB;
|
|
|
|
do
|
|
{
|
|
TSXQueryTree( display, A, &root, &A, children, total );
|
|
TSXQueryTree( display, B, &root, &B, &childrenB, &totalB );
|
|
if( childrenB ) TSXFree( childrenB );
|
|
if( *children ) TSXFree( *children ), *children = NULL;
|
|
} while( A != B && A && B );
|
|
|
|
if( A && B )
|
|
{
|
|
TSXQueryTree( display, A, &root, &B, children, total );
|
|
return A;
|
|
}
|
|
return 0 ;
|
|
}
|
|
|
|
static Window __get_top_decoration( Window w, Window ancestor )
|
|
{
|
|
Window* children, root, prev = w, parent = w;
|
|
unsigned total;
|
|
|
|
do
|
|
{
|
|
w = parent;
|
|
TSXQueryTree( display, w, &root, &parent, &children, &total );
|
|
if( children ) TSXFree( children );
|
|
} while( parent && parent != ancestor );
|
|
TRACE_(event)("\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
|
|
return ( parent ) ? w : 0 ;
|
|
}
|
|
|
|
static unsigned __td_lookup( Window w, Window* list, unsigned max )
|
|
{
|
|
unsigned i;
|
|
for( i = max - 1; i >= 0; i-- ) if( list[i] == w ) break;
|
|
return i;
|
|
}
|
|
|
|
static HWND EVENT_QueryZOrder( HWND hWndCheck)
|
|
{
|
|
HWND hwndInsertAfter = HWND_TOP;
|
|
WND *pWndCheck = WIN_FindWndPtr(hWndCheck);
|
|
WND *pDesktop = WIN_GetDesktop();
|
|
WND *pWnd, *pWndZ = WIN_LockWndPtr(pDesktop->child);
|
|
Window w, parent, *children = NULL;
|
|
unsigned total, check, pos, best;
|
|
|
|
if( !__check_query_condition(&pWndZ, &pWnd) )
|
|
{
|
|
WIN_ReleaseWndPtr(pWndCheck);
|
|
WIN_ReleaseWndPtr(pDesktop->child);
|
|
WIN_ReleaseDesktop();
|
|
return hwndInsertAfter;
|
|
}
|
|
WIN_LockWndPtr(pWndZ);
|
|
WIN_LockWndPtr(pWnd);
|
|
WIN_ReleaseWndPtr(pDesktop->child);
|
|
WIN_ReleaseDesktop();
|
|
|
|
parent = __get_common_ancestor( X11DRV_WND_GetXWindow(pWndZ),
|
|
X11DRV_WND_GetXWindow(pWnd),
|
|
&children, &total );
|
|
if( parent && children )
|
|
{
|
|
/* w is the ancestor if pWndCheck that is a direct descendant of 'parent' */
|
|
|
|
w = __get_top_decoration( X11DRV_WND_GetXWindow(pWndCheck), parent );
|
|
|
|
if( w != children[total-1] ) /* check if at the top */
|
|
{
|
|
/* X child at index 0 is at the bottom, at index total-1 is at the top */
|
|
check = __td_lookup( w, children, total );
|
|
best = total;
|
|
|
|
for( WIN_UpdateWndPtr(&pWnd,pWndZ); pWnd;WIN_UpdateWndPtr(&pWnd,pWnd->next))
|
|
{
|
|
/* go through all windows in Wine z-order... */
|
|
|
|
if( pWnd != pWndCheck )
|
|
{
|
|
if( !(pWnd->flags & WIN_MANAGED) ||
|
|
!(w = __get_top_decoration( X11DRV_WND_GetXWindow(pWnd), parent )) )
|
|
continue;
|
|
pos = __td_lookup( w, children, total );
|
|
if( pos < best && pos > check )
|
|
{
|
|
/* find a nearest Wine window precedes
|
|
* pWndCheck in the real z-order... */
|
|
best = pos;
|
|
hwndInsertAfter = pWnd->hwndSelf;
|
|
}
|
|
if( best - check == 1 ) break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if( children ) TSXFree( children );
|
|
WIN_ReleaseWndPtr(pWnd);
|
|
WIN_ReleaseWndPtr(pWndZ);
|
|
WIN_ReleaseWndPtr(pWndCheck);
|
|
return hwndInsertAfter;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* EVENT_XStateToKeyState
|
|
*
|
|
* Translate a X event state (Button1Mask, ShiftMask, etc...) to
|
|
* a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
|
|
*/
|
|
static WORD EVENT_XStateToKeyState( int state )
|
|
{
|
|
int kstate = 0;
|
|
|
|
if (state & Button1Mask) kstate |= MK_LBUTTON;
|
|
if (state & Button2Mask) kstate |= MK_MBUTTON;
|
|
if (state & Button3Mask) kstate |= MK_RBUTTON;
|
|
if (state & ShiftMask) kstate |= MK_SHIFT;
|
|
if (state & ControlMask) kstate |= MK_CONTROL;
|
|
return kstate;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* X11DRV_EVENT_QueryPointer
|
|
*/
|
|
BOOL X11DRV_EVENT_QueryPointer(DWORD *posX, DWORD *posY, DWORD *state)
|
|
{
|
|
Window root, child;
|
|
int rootX, rootY, winX, winY;
|
|
unsigned int xstate;
|
|
|
|
if (!TSXQueryPointer( display, X11DRV_GetXRootWindow(), &root, &child,
|
|
&rootX, &rootY, &winX, &winY, &xstate ))
|
|
return FALSE;
|
|
|
|
if(posX)
|
|
*posX = (DWORD)winX;
|
|
if(posY)
|
|
*posY = (DWORD)winY;
|
|
if(state)
|
|
*state = EVENT_XStateToKeyState( xstate );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* EVENT_Expose
|
|
*/
|
|
static void EVENT_Expose( HWND hWnd, XExposeEvent *event )
|
|
{
|
|
RECT rect;
|
|
|
|
WND *pWnd = WIN_FindWndPtr(hWnd);
|
|
/* Make position relative to client area instead of window */
|
|
rect.left = event->x - (pWnd? (pWnd->rectClient.left - pWnd->rectWindow.left) : 0);
|
|
rect.top = event->y - (pWnd? (pWnd->rectClient.top - pWnd->rectWindow.top) : 0);
|
|
rect.right = rect.left + event->width;
|
|
rect.bottom = rect.top + event->height;
|
|
WIN_ReleaseWndPtr(pWnd);
|
|
|
|
Callout.RedrawWindow( hWnd, &rect, 0,
|
|
RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
|
|
(event->count ? 0 : RDW_ERASENOW) );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* EVENT_GraphicsExpose
|
|
*
|
|
* This is needed when scrolling area is partially obscured
|
|
* by non-Wine X window.
|
|
*/
|
|
static void EVENT_GraphicsExpose( HWND hWnd, XGraphicsExposeEvent *event )
|
|
{
|
|
RECT rect;
|
|
WND *pWnd = WIN_FindWndPtr(hWnd);
|
|
|
|
/* Make position relative to client area instead of window */
|
|
rect.left = event->x - (pWnd? (pWnd->rectClient.left - pWnd->rectWindow.left) : 0);
|
|
rect.top = event->y - (pWnd? (pWnd->rectClient.top - pWnd->rectWindow.top) : 0);
|
|
rect.right = rect.left + event->width;
|
|
rect.bottom = rect.top + event->height;
|
|
|
|
WIN_ReleaseWndPtr(pWnd);
|
|
|
|
Callout.RedrawWindow( hWnd, &rect, 0,
|
|
RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
|
|
(event->count ? 0 : RDW_ERASENOW) );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* EVENT_Key
|
|
*
|
|
* Handle a X key event
|
|
*/
|
|
static void EVENT_Key( HWND hWnd, XKeyEvent *event )
|
|
{
|
|
WND *pWnd = WIN_FindWndPtr(hWnd);
|
|
X11DRV_KEYBOARD_HandleEvent( pWnd, event );
|
|
WIN_ReleaseWndPtr(pWnd);
|
|
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* EVENT_MotionNotify
|
|
*/
|
|
static void EVENT_MotionNotify( HWND hWnd, XMotionEvent *event )
|
|
{
|
|
WND *pWnd = WIN_FindWndPtr(hWnd);
|
|
int xOffset = pWnd? pWnd->rectWindow.left : 0;
|
|
int yOffset = pWnd? pWnd->rectWindow.top : 0;
|
|
WIN_ReleaseWndPtr(pWnd);
|
|
|
|
MOUSE_SendEvent( MOUSEEVENTF_MOVE,
|
|
xOffset + event->x, yOffset + event->y,
|
|
EVENT_XStateToKeyState( event->state ),
|
|
event->time - MSG_WineStartTicks,
|
|
hWnd);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* EVENT_ButtonPress
|
|
*/
|
|
static void EVENT_ButtonPress( HWND hWnd, XButtonEvent *event )
|
|
{
|
|
static WORD statusCodes[NB_BUTTONS] =
|
|
{ MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_RIGHTDOWN };
|
|
int buttonNum = event->button - 1;
|
|
|
|
WND *pWnd = WIN_FindWndPtr(hWnd);
|
|
int xOffset = pWnd? pWnd->rectWindow.left : 0;
|
|
int yOffset = pWnd? pWnd->rectWindow.top : 0;
|
|
WORD keystate;
|
|
|
|
WIN_ReleaseWndPtr(pWnd);
|
|
|
|
if (buttonNum >= NB_BUTTONS) return;
|
|
|
|
/*
|
|
* Get the compatible keystate
|
|
*/
|
|
keystate = EVENT_XStateToKeyState( event->state );
|
|
|
|
/*
|
|
* Make sure that the state of the button that was just
|
|
* pressed is "down".
|
|
*/
|
|
switch (buttonNum)
|
|
{
|
|
case 0:
|
|
keystate |= MK_LBUTTON;
|
|
break;
|
|
case 1:
|
|
keystate |= MK_MBUTTON;
|
|
break;
|
|
case 2:
|
|
keystate |= MK_RBUTTON;
|
|
break;
|
|
}
|
|
|
|
MOUSE_SendEvent( statusCodes[buttonNum],
|
|
xOffset + event->x, yOffset + event->y,
|
|
keystate,
|
|
event->time - MSG_WineStartTicks,
|
|
hWnd);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* EVENT_ButtonRelease
|
|
*/
|
|
static void EVENT_ButtonRelease( HWND hWnd, XButtonEvent *event )
|
|
{
|
|
static WORD statusCodes[NB_BUTTONS] =
|
|
{ MOUSEEVENTF_LEFTUP, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_RIGHTUP };
|
|
int buttonNum = event->button - 1;
|
|
WND *pWnd = WIN_FindWndPtr(hWnd);
|
|
int xOffset = pWnd? pWnd->rectWindow.left : 0;
|
|
int yOffset = pWnd? pWnd->rectWindow.top : 0;
|
|
WORD keystate;
|
|
|
|
WIN_ReleaseWndPtr(pWnd);
|
|
|
|
if (buttonNum >= NB_BUTTONS) return;
|
|
|
|
/*
|
|
* Get the compatible keystate
|
|
*/
|
|
keystate = EVENT_XStateToKeyState( event->state );
|
|
|
|
/*
|
|
* Make sure that the state of the button that was just
|
|
* released is "up".
|
|
*/
|
|
switch (buttonNum)
|
|
{
|
|
case 0:
|
|
keystate &= ~MK_LBUTTON;
|
|
break;
|
|
case 1:
|
|
keystate &= ~MK_MBUTTON;
|
|
break;
|
|
case 2:
|
|
keystate &= ~MK_RBUTTON;
|
|
break;
|
|
}
|
|
|
|
MOUSE_SendEvent( statusCodes[buttonNum],
|
|
xOffset + event->x, yOffset + event->y,
|
|
keystate,
|
|
event->time - MSG_WineStartTicks,
|
|
hWnd);
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* EVENT_FocusIn
|
|
*/
|
|
static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event )
|
|
{
|
|
if (event->detail != NotifyPointer)
|
|
if (hWnd != GetForegroundWindow())
|
|
{
|
|
SetForegroundWindow( hWnd );
|
|
X11DRV_KEYBOARD_UpdateState();
|
|
}
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* EVENT_FocusOut
|
|
*
|
|
* Note: only top-level override-redirect windows get FocusOut events.
|
|
*/
|
|
static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event )
|
|
{
|
|
if (event->detail != NotifyPointer)
|
|
if (hWnd == GetForegroundWindow())
|
|
{
|
|
SendMessageA( hWnd, WM_CANCELMODE, 0, 0 );
|
|
SetForegroundWindow( 0 );
|
|
}
|
|
}
|
|
|
|
/**********************************************************************
|
|
* X11DRV_EVENT_CheckFocus
|
|
*/
|
|
BOOL X11DRV_EVENT_CheckFocus(void)
|
|
{
|
|
HWND hWnd;
|
|
Window xW;
|
|
int state;
|
|
|
|
TSXGetInputFocus(display, &xW, &state);
|
|
if( xW == None ||
|
|
TSXFindContext(display, xW, winContext, (char **)&hWnd) )
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* EVENT_GetGeometry
|
|
*
|
|
* Helper function for ConfigureNotify handling.
|
|
* Get the new geometry of a window relative to the root window.
|
|
*/
|
|
static void EVENT_GetGeometry( Window win, int *px, int *py,
|
|
unsigned int *pwidth, unsigned int *pheight )
|
|
{
|
|
Window root, top;
|
|
int x, y, width, height, border, depth;
|
|
|
|
EnterCriticalSection( &X11DRV_CritSection );
|
|
|
|
/* Get the geometry of the window */
|
|
XGetGeometry( display, win, &root, &x, &y, &width, &height,
|
|
&border, &depth );
|
|
|
|
/* Translate the window origin to root coordinates */
|
|
XTranslateCoordinates( display, win, root, 0, 0, &x, &y, &top );
|
|
|
|
LeaveCriticalSection( &X11DRV_CritSection );
|
|
|
|
*px = x;
|
|
*py = y;
|
|
*pwidth = width;
|
|
*pheight = height;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* EVENT_ConfigureNotify
|
|
*
|
|
* The ConfigureNotify event is only selected on top-level windows
|
|
* when the -managed flag is used.
|
|
*/
|
|
static void EVENT_ConfigureNotify( HWND hWnd, XConfigureEvent *event )
|
|
{
|
|
RECT rectWindow;
|
|
int x, y, flags = 0;
|
|
unsigned int width, height;
|
|
HWND newInsertAfter, oldInsertAfter;
|
|
|
|
/* Get geometry and Z-order according to X */
|
|
|
|
EVENT_GetGeometry( event->window, &x, &y, &width, &height );
|
|
newInsertAfter = EVENT_QueryZOrder( hWnd );
|
|
|
|
/* Get geometry and Z-order according to Wine */
|
|
|
|
GetWindowRect( hWnd, &rectWindow );
|
|
oldInsertAfter = GetWindow( hWnd, GW_HWNDPREV );
|
|
if ( !oldInsertAfter ) oldInsertAfter = HWND_TOP;
|
|
|
|
/* Compare what has changed */
|
|
|
|
if ( rectWindow.left == x && rectWindow.top == y )
|
|
flags |= SWP_NOMOVE;
|
|
else
|
|
TRACE_(win)( "%04x moving from (%d,%d) to (%d,%d)\n", hWnd,
|
|
rectWindow.left, rectWindow.top, x, y );
|
|
|
|
if ( rectWindow.right - rectWindow.left == width
|
|
&& rectWindow.bottom - rectWindow.top == height )
|
|
flags |= SWP_NOSIZE;
|
|
else
|
|
TRACE_(win)( "%04x resizing from (%d,%d) to (%d,%d)\n", hWnd,
|
|
rectWindow.right - rectWindow.left,
|
|
rectWindow.bottom - rectWindow.top, width, height );
|
|
|
|
if ( newInsertAfter == oldInsertAfter )
|
|
flags |= SWP_NOZORDER;
|
|
else
|
|
TRACE_(win)( "%04x restacking from after %04x to after %04x\n", hWnd,
|
|
oldInsertAfter, newInsertAfter );
|
|
|
|
/* If anything changed, call SetWindowPos */
|
|
|
|
if ( flags != (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER) )
|
|
SetWindowPos( hWnd, newInsertAfter, x, y, width, height,
|
|
flags | SWP_NOACTIVATE | SWP_WINE_NOHOSTMOVE );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* EVENT_SelectionRequest
|
|
*/
|
|
static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event )
|
|
{
|
|
XSelectionEvent result;
|
|
Atom rprop = None;
|
|
Window request = event->requestor;
|
|
|
|
if(event->target == XA_STRING)
|
|
{
|
|
HANDLE16 hText;
|
|
LPSTR text;
|
|
int size,i,j;
|
|
|
|
rprop = event->property;
|
|
|
|
if( rprop == None )
|
|
rprop = event->target;
|
|
|
|
if( event->selection != XA_PRIMARY )
|
|
rprop = None;
|
|
else
|
|
if( !CLIPBOARD_IsPresent(CF_OEMTEXT) )
|
|
rprop = None;
|
|
else
|
|
{
|
|
/* open to make sure that clipboard is available */
|
|
|
|
BOOL couldOpen = OpenClipboard( hWnd );
|
|
char* lpstr = 0;
|
|
|
|
hText = GetClipboardData16(CF_TEXT);
|
|
text = GlobalLock16(hText);
|
|
size = GlobalSize16(hText);
|
|
|
|
/* remove carriage returns */
|
|
|
|
lpstr = (char*)HEAP_xalloc( GetProcessHeap(), 0, size-- );
|
|
for(i=0,j=0; i < size && text[i]; i++ )
|
|
{
|
|
if( text[i] == '\r' &&
|
|
(text[i+1] == '\n' || text[i+1] == '\0') ) continue;
|
|
lpstr[j++] = text[i];
|
|
}
|
|
lpstr[j]='\0';
|
|
|
|
TSXChangeProperty(display, request, rprop,
|
|
XA_STRING, 8, PropModeReplace,
|
|
lpstr, j);
|
|
HeapFree( GetProcessHeap(), 0, lpstr );
|
|
|
|
/* close only if we opened before */
|
|
|
|
if(couldOpen) CloseClipboard();
|
|
}
|
|
}
|
|
|
|
if( rprop == None)
|
|
TRACE_(event)("Request for %s ignored\n", TSXGetAtomName(display,event->target));
|
|
|
|
/* reply to sender */
|
|
|
|
result.type = SelectionNotify;
|
|
result.display = display;
|
|
result.requestor = request;
|
|
result.selection = event->selection;
|
|
result.property = rprop;
|
|
result.target = event->target;
|
|
result.time = event->time;
|
|
TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* EVENT_SelectionClear
|
|
*/
|
|
static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
|
|
{
|
|
if (event->selection != XA_PRIMARY) return;
|
|
X11DRV_CLIPBOARD_ReleaseSelection( event->window, hWnd );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* EVENT_DropFromOffix
|
|
*
|
|
* don't know if it still works (last Changlog is from 96/11/04)
|
|
*/
|
|
static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
|
|
{
|
|
unsigned long data_length;
|
|
unsigned long aux_long;
|
|
unsigned char* p_data = NULL;
|
|
union {
|
|
Atom atom_aux;
|
|
struct {
|
|
int x;
|
|
int y;
|
|
} pt_aux;
|
|
int i;
|
|
} u;
|
|
int x, y;
|
|
BOOL16 bAccept;
|
|
HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO));
|
|
LPDRAGINFO lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
|
|
SEGPTR spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
|
|
Window w_aux_root, w_aux_child;
|
|
WND* pDropWnd;
|
|
WND* pWnd;
|
|
|
|
if( !lpDragInfo || !spDragInfo ) return;
|
|
|
|
pWnd = WIN_FindWndPtr(hWnd);
|
|
|
|
TSXQueryPointer( display, X11DRV_WND_GetXWindow(pWnd), &w_aux_root, &w_aux_child,
|
|
&x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
|
|
(unsigned int*)&aux_long);
|
|
|
|
lpDragInfo->hScope = hWnd;
|
|
lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
|
|
|
|
/* find out drop point and drop window */
|
|
if( x < 0 || y < 0 ||
|
|
x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
|
|
y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
|
|
{ bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
|
|
else
|
|
{
|
|
bAccept = DRAG_QueryUpdate( hWnd, spDragInfo, TRUE );
|
|
x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
|
|
}
|
|
pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
|
|
WIN_ReleaseWndPtr(pWnd);
|
|
|
|
GlobalFree16( hDragInfo );
|
|
|
|
if( bAccept )
|
|
{
|
|
TSXGetWindowProperty( display, DefaultRootWindow(display),
|
|
dndSelection, 0, 65535, FALSE,
|
|
AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
|
|
&data_length, &aux_long, &p_data);
|
|
|
|
if( !aux_long && p_data) /* don't bother if > 64K */
|
|
{
|
|
char *p = (char*) p_data;
|
|
char *p_drop;
|
|
|
|
aux_long = 0;
|
|
while( *p ) /* calculate buffer size */
|
|
{
|
|
p_drop = p;
|
|
if((u.i = *p) != -1 )
|
|
u.i = DRIVE_FindDriveRoot( (const char **)&p_drop );
|
|
if( u.i == -1 ) *p = -1; /* mark as "bad" */
|
|
else
|
|
{
|
|
INT len = GetShortPathNameA( p, NULL, 0 );
|
|
if (len) aux_long += len + 1;
|
|
else *p = -1;
|
|
}
|
|
p += strlen(p) + 1;
|
|
}
|
|
if( aux_long && aux_long < 65535 )
|
|
{
|
|
HDROP16 hDrop;
|
|
LPDROPFILESTRUCT16 lpDrop;
|
|
|
|
aux_long += sizeof(DROPFILESTRUCT16) + 1;
|
|
hDrop = (HDROP16)GlobalAlloc16( GMEM_SHARE, aux_long );
|
|
lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop );
|
|
|
|
if( lpDrop )
|
|
{
|
|
lpDrop->wSize = sizeof(DROPFILESTRUCT16);
|
|
lpDrop->ptMousePos.x = (INT16)x;
|
|
lpDrop->ptMousePos.y = (INT16)y;
|
|
lpDrop->fInNonClientArea = (BOOL16)
|
|
( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
|
|
y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
|
|
x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
|
|
y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
|
|
p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
|
|
p = p_data;
|
|
while(*p)
|
|
{
|
|
if( *p != -1 ) /* use only "good" entries */
|
|
{
|
|
GetShortPathNameA( p, p_drop, 65535 );
|
|
p_drop += strlen( p_drop ) + 1;
|
|
}
|
|
p += strlen(p) + 1;
|
|
}
|
|
*p_drop = '\0';
|
|
PostMessage16( hWnd, WM_DROPFILES,
|
|
(WPARAM16)hDrop, 0L );
|
|
}
|
|
}
|
|
}
|
|
if( p_data ) TSXFree(p_data);
|
|
|
|
} /* WS_EX_ACCEPTFILES */
|
|
|
|
WIN_ReleaseWndPtr(pDropWnd);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* EVENT_DropURLs
|
|
*
|
|
* drop items are separated by \n
|
|
* each item is prefixed by its mime type
|
|
*
|
|
* event->data.l[3], event->data.l[4] contains drop x,y position
|
|
*/
|
|
static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
|
|
{
|
|
WND *pDropWnd;
|
|
WND *pWnd;
|
|
unsigned long data_length;
|
|
unsigned long aux_long, drop_len = 0;
|
|
unsigned char *p_data = NULL; /* property data */
|
|
char *p_drop = NULL;
|
|
char *p, *next;
|
|
int x, y, drop32 = FALSE ;
|
|
union {
|
|
Atom atom_aux;
|
|
int i;
|
|
Window w_aux;
|
|
} u; /* unused */
|
|
union {
|
|
HDROP16 h16;
|
|
HDROP h32;
|
|
} hDrop;
|
|
|
|
pWnd = WIN_FindWndPtr(hWnd);
|
|
drop32 = pWnd->flags & WIN_ISWIN32;
|
|
|
|
if (!(pWnd->dwExStyle & WS_EX_ACCEPTFILES))
|
|
{
|
|
WIN_ReleaseWndPtr(pWnd);
|
|
return;
|
|
}
|
|
WIN_ReleaseWndPtr(pWnd);
|
|
|
|
TSXGetWindowProperty( display, DefaultRootWindow(display),
|
|
dndSelection, 0, 65535, FALSE,
|
|
AnyPropertyType, &u.atom_aux, &u.i,
|
|
&data_length, &aux_long, &p_data);
|
|
if (aux_long)
|
|
WARN_(event)("property too large, truncated!\n");
|
|
TRACE_(event)("urls=%s\n", p_data);
|
|
|
|
if( !aux_long && p_data) { /* don't bother if > 64K */
|
|
/* calculate length */
|
|
p = p_data;
|
|
next = strchr(p, '\n');
|
|
while (p) {
|
|
if (next) *next=0;
|
|
if (strncmp(p,"file:",5) == 0 ) {
|
|
INT len = GetShortPathNameA( p+5, NULL, 0 );
|
|
if (len) drop_len += len + 1;
|
|
}
|
|
if (next) {
|
|
*next = '\n';
|
|
p = next + 1;
|
|
next = strchr(p, '\n');
|
|
} else {
|
|
p = NULL;
|
|
}
|
|
}
|
|
|
|
if( drop_len && drop_len < 65535 ) {
|
|
TSXQueryPointer( display, X11DRV_GetXRootWindow(), &u.w_aux, &u.w_aux,
|
|
&x, &y, &u.i, &u.i, &u.i);
|
|
|
|
pDropWnd = WIN_FindWndPtr( hWnd );
|
|
|
|
if (drop32) {
|
|
LPDROPFILESTRUCT lpDrop;
|
|
drop_len += sizeof(DROPFILESTRUCT) + 1;
|
|
hDrop.h32 = (HDROP)GlobalAlloc( GMEM_SHARE, drop_len );
|
|
lpDrop = (LPDROPFILESTRUCT) GlobalLock( hDrop.h32 );
|
|
|
|
if( lpDrop ) {
|
|
lpDrop->lSize = sizeof(DROPFILESTRUCT);
|
|
lpDrop->ptMousePos.x = (INT)x;
|
|
lpDrop->ptMousePos.y = (INT)y;
|
|
lpDrop->fInNonClientArea = (BOOL)
|
|
( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
|
|
y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
|
|
x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
|
|
y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
|
|
lpDrop->fWideChar = FALSE;
|
|
p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT);
|
|
}
|
|
} else {
|
|
LPDROPFILESTRUCT16 lpDrop;
|
|
drop_len += sizeof(DROPFILESTRUCT16) + 1;
|
|
hDrop.h16 = (HDROP16)GlobalAlloc16( GMEM_SHARE, drop_len );
|
|
lpDrop = (LPDROPFILESTRUCT16) GlobalLock16( hDrop.h16 );
|
|
|
|
if( lpDrop ) {
|
|
lpDrop->wSize = sizeof(DROPFILESTRUCT16);
|
|
lpDrop->ptMousePos.x = (INT16)x;
|
|
lpDrop->ptMousePos.y = (INT16)y;
|
|
lpDrop->fInNonClientArea = (BOOL16)
|
|
( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
|
|
y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
|
|
x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
|
|
y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
|
|
p_drop = ((char*)lpDrop) + sizeof(DROPFILESTRUCT16);
|
|
}
|
|
}
|
|
|
|
/* create message content */
|
|
if (p_drop) {
|
|
p = p_data;
|
|
next = strchr(p, '\n');
|
|
while (p) {
|
|
if (next) *next=0;
|
|
if (strncmp(p,"file:",5) == 0 ) {
|
|
INT len = GetShortPathNameA( p+5, p_drop, 65535 );
|
|
if (len) {
|
|
TRACE_(event)("drop file %s as %s\n", p+5, p_drop);
|
|
p_drop += len+1;
|
|
} else {
|
|
WARN_(event)("can't convert file %s to dos name \n", p+5);
|
|
}
|
|
} else {
|
|
WARN_(event)("unknown mime type %s\n", p);
|
|
}
|
|
if (next) {
|
|
*next = '\n';
|
|
p = next + 1;
|
|
next = strchr(p, '\n');
|
|
} else {
|
|
p = NULL;
|
|
}
|
|
*p_drop = '\0';
|
|
}
|
|
|
|
if (drop32) {
|
|
/* can not use PostMessage32A because it is currently based on
|
|
* PostMessage16 and WPARAM32 would be truncated to WPARAM16
|
|
*/
|
|
GlobalUnlock(hDrop.h32);
|
|
SendMessageA( hWnd, WM_DROPFILES,
|
|
(WPARAM)hDrop.h32, 0L );
|
|
} else {
|
|
GlobalUnlock16(hDrop.h16);
|
|
PostMessage16( hWnd, WM_DROPFILES,
|
|
(WPARAM16)hDrop.h16, 0L );
|
|
}
|
|
}
|
|
WIN_ReleaseWndPtr(pDropWnd);
|
|
}
|
|
if( p_data ) TSXFree(p_data);
|
|
}
|
|
}
|
|
|
|
/**********************************************************************
|
|
* EVENT_ClientMessage
|
|
*/
|
|
static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
|
|
{
|
|
if (event->message_type != None && event->format == 32) {
|
|
if ((event->message_type == wmProtocols) &&
|
|
(((Atom) event->data.l[0]) == wmDeleteWindow))
|
|
{
|
|
/* Ignore the delete window request if the window has been disabled
|
|
* and we are in managed mode. This is to disallow applications from
|
|
* being closed by the window manager while in a modal state.
|
|
*/
|
|
BOOL bIsDisabled;
|
|
bIsDisabled = GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED;
|
|
|
|
if ( !Options.managed || !bIsDisabled )
|
|
PostMessage16( hWnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
|
|
}
|
|
else if ( event->message_type == dndProtocol &&
|
|
(event->data.l[0] == DndFile || event->data.l[0] == DndFiles) )
|
|
EVENT_DropFromOffiX(hWnd, event);
|
|
else if ( event->message_type == dndProtocol &&
|
|
event->data.l[0] == DndURL )
|
|
EVENT_DropURLs(hWnd, event);
|
|
else {
|
|
#if 0
|
|
/* enable this if you want to see the message */
|
|
unsigned char* p_data = NULL;
|
|
union {
|
|
unsigned long l;
|
|
int i;
|
|
Atom atom;
|
|
} u; /* unused */
|
|
TSXGetWindowProperty( display, DefaultRootWindow(display),
|
|
dndSelection, 0, 65535, FALSE,
|
|
AnyPropertyType, &u.atom, &u.i,
|
|
&u.l, &u.l, &p_data);
|
|
TRACE_(event)("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
|
|
event->message_type, event->data.l[0], event->data.l[1],
|
|
event->data.l[2], event->data.l[3], event->data.l[4],
|
|
p_data);
|
|
#endif
|
|
TRACE_(event)("unrecognized ClientMessage\n" );
|
|
}
|
|
}
|
|
}
|
|
|
|
/**********************************************************************
|
|
* EVENT_EnterNotify
|
|
*
|
|
* Install colormap when Wine window is focused in
|
|
* self-managed mode with private colormap
|
|
*/
|
|
#if 0
|
|
void EVENT_EnterNotify( HWND hWnd, XCrossingEvent *event )
|
|
{
|
|
if( !Options.managed && X11DRV_GetXRootWindow() == DefaultRootWindow(display) &&
|
|
(COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus() )
|
|
TSXInstallColormap( display, X11DRV_PALETTE_GetColormap() );
|
|
}
|
|
#endif
|
|
|
|
/**********************************************************************
|
|
* EVENT_MapNotify
|
|
*/
|
|
void EVENT_MapNotify( HWND hWnd, XMapEvent *event )
|
|
{
|
|
HWND hwndFocus = GetFocus();
|
|
WND *wndFocus = WIN_FindWndPtr(hwndFocus);
|
|
WND *pWnd = WIN_FindWndPtr(hWnd);
|
|
if (pWnd->flags & WIN_MANAGED)
|
|
pWnd->dwStyle &= ~WS_MINIMIZE;
|
|
WIN_ReleaseWndPtr(pWnd);
|
|
|
|
if (hwndFocus && IsChild( hWnd, hwndFocus ))
|
|
X11DRV_WND_SetFocus(wndFocus);
|
|
|
|
WIN_ReleaseWndPtr(wndFocus);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* EVENT_MapNotify
|
|
*/
|
|
void EVENT_UnmapNotify( HWND hWnd, XUnmapEvent *event )
|
|
{
|
|
WND *pWnd = WIN_FindWndPtr(hWnd);
|
|
if (pWnd->flags & WIN_MANAGED)
|
|
{
|
|
EndMenu();
|
|
if( pWnd->dwStyle & WS_VISIBLE )
|
|
pWnd->dwStyle |= WS_MINIMIZE;
|
|
}
|
|
WIN_ReleaseWndPtr(pWnd);
|
|
}
|
|
|
|
|
|
#endif /* !defined(X_DISPLAY_MISSING) */
|