Added support for the take focus protocol.

This commit is contained in:
Alexandre Julliard 2002-09-18 23:09:50 +00:00
parent 876fecf382
commit 1a80921903
5 changed files with 151 additions and 80 deletions

View File

@ -48,7 +48,6 @@
#include "shellapi.h"
WINE_DEFAULT_DEBUG_CHANNEL(event);
WINE_DECLARE_DEBUG_CHANNEL(win);
/* X context to associate a hwnd to an X window */
extern XContext winContext;
@ -72,9 +71,6 @@ extern Atom dndSelection;
#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",
@ -89,7 +85,6 @@ static const char * const event_names[] =
static void EVENT_ProcessEvent( XEvent *event );
static BOOL X11DRV_CheckFocus(void);
/* Event handlers */
static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event );
@ -368,92 +363,166 @@ static void EVENT_ProcessEvent( XEvent *event )
/**********************************************************************
* EVENT_FocusIn
* set_focus_error_handler
*
* Handler for X errors happening during XSetInputFocus call.
*/
static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event )
static int set_focus_error_handler( Display *display, XErrorEvent *event, void *arg )
{
WND *pWndLastFocus;
XWindowAttributes win_attr;
BOOL bIsDisabled;
return (event->error_code == BadValue);
}
if (!hWnd) return;
bIsDisabled = GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED;
/**********************************************************************
* set_focus
*/
static void set_focus( HWND hwnd, Time time )
{
HWND focus = GetFocus();
Window win;
/* If the window has been disabled, 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 (bIsDisabled && glastXFocusWin)
if (hwnd != focus && !IsChild( hwnd, focus ))
{
/* Change focus only if saved focus window is registered and viewable */
wine_tsx11_lock();
if (XFindContext( event->display, glastXFocusWin, winContext,
(char **)&pWndLastFocus ) == 0 )
{
if (XGetWindowAttributes( event->display, glastXFocusWin, &win_attr ) &&
(win_attr.map_state == IsViewable) )
{
XSetInputFocus( event->display, glastXFocusWin, RevertToParent, CurrentTime );
wine_tsx11_unlock();
return;
}
}
wine_tsx11_unlock();
TRACE( "changing window focus to %x\n", hwnd );
SetFocus( hwnd );
}
if (event->detail != NotifyPointer && hWnd != GetForegroundWindow())
SetForegroundWindow( hWnd );
/* focus window might be changed by the above SetFocus() call */
focus = GetFocus();
win = X11DRV_get_whole_window(focus);
if (win)
{
Display *display = thread_display();
TRACE( "setting focus to %x (%lx) time=%ld\n", focus, win, time );
X11DRV_expect_error( display, set_focus_error_handler, NULL );
XSetInputFocus( display, win, RevertToParent, time );
if (X11DRV_check_error()) ERR("got BadMatch, ignoring\n" );
}
}
/**********************************************************************
* handle_wm_protocols_message
*/
static void handle_wm_protocols_message( HWND hwnd, XClientMessageEvent *event )
{
Atom protocol = (Atom)event->data.l[0];
if (!protocol) return;
if (protocol == 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.
*/
if (IsWindowEnabled(hwnd)) PostMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
}
else if (protocol == wmTakeFocus)
{
Time event_time = (Time)event->data.l[1];
HWND last_focus = x11drv_thread_data()->last_focus;
TRACE( "got take focus msg for %x, enabled=%d, focus=%x, active=%x, fg=%x, last=%x\n",
hwnd, IsWindowEnabled(hwnd), GetFocus(), GetActiveWindow(),
GetForegroundWindow(), last_focus );
if (IsWindowEnabled(hwnd))
{
/* simulate a mouse click on the caption to find out
* whether the window wants to be activated */
LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
GetAncestor( hwnd, GA_ROOT ),
MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE) set_focus( hwnd, event_time );
else TRACE( "not setting focus to %x (%lx), ma=%ld\n", hwnd, event->window, ma );
}
else
{
hwnd = GetFocus();
if (!hwnd) hwnd = GetActiveWindow();
if (!hwnd) hwnd = last_focus;
if (hwnd && IsWindowEnabled(hwnd)) set_focus( hwnd, event_time );
}
}
}
static const char * const focus_details[] =
{
"NotifyAncestor",
"NotifyVirtual",
"NotifyInferior",
"NotifyNonlinear",
"NotifyNonlinearVirtual",
"NotifyPointer",
"NotifyPointerRoot",
"NotifyDetailNone"
};
/**********************************************************************
* EVENT_FocusIn
*/
static void EVENT_FocusIn( HWND hwnd, XFocusChangeEvent *event )
{
if (!hwnd) return;
TRACE( "win %x xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
if (wmTakeFocus) return; /* ignore FocusIn if we are using take focus */
if (event->detail == NotifyPointer) return;
if (!IsWindowEnabled(hwnd))
{
HWND hwnd = GetFocus();
if (!hwnd) hwnd = GetActiveWindow();
if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
if (hwnd && IsWindowEnabled(hwnd)) set_focus( hwnd, CurrentTime );
}
else if (hwnd != GetForegroundWindow())
{
SetForegroundWindow( hwnd );
}
}
/**********************************************************************
* EVENT_FocusOut
*
* Note: only top-level override-redirect windows get FocusOut events.
* Note: only top-level windows get FocusOut events.
*/
static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event )
static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event )
{
/* Save the last window which had the focus */
glastXFocusWin = event->window;
if (!hWnd) return;
if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED) glastXFocusWin = 0;
HWND hwnd_tmp;
Window focus_win;
int revert;
if (event->detail != NotifyPointer && hWnd == GetForegroundWindow())
TRACE( "win %x xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
if (event->detail == NotifyPointer) return;
if (hwnd != GetForegroundWindow()) return;
SendMessageA( hwnd, WM_CANCELMODE, 0, 0 );
/* don't reset the foreground window, if the window which is
getting the focus is a Wine window */
TSXGetInputFocus( thread_display(), &focus_win, &revert );
if (!focus_win || TSXFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ))
{
/* don't reset the foreground window, if the window which is
getting the focus is a Wine window */
if (!X11DRV_CheckFocus())
/* Abey : 6-Oct-99. Check again if the focus out window is the
Foreground window, because in most cases the messages sent
above must have already changed the foreground window, in which
case we don't have to change the foreground window to 0 */
if (hwnd == GetForegroundWindow())
{
SendMessageA( hWnd, WM_CANCELMODE, 0, 0 );
/* Abey : 6-Oct-99. Check again if the focus out window is the
Foreground window, because in most cases the messages sent
above must have already changed the foreground window, in which
case we don't have to change the foreground window to 0 */
if (hWnd == GetForegroundWindow())
SetForegroundWindow( 0 );
TRACE( "lost focus, setting fg to 0\n" );
x11drv_thread_data()->last_focus = hwnd;
SetForegroundWindow( 0 );
}
}
}
/**********************************************************************
* CheckFocus (X11DRV.@)
*/
static BOOL X11DRV_CheckFocus(void)
{
Display *display = thread_display();
HWND hWnd;
Window xW;
int state;
TSXGetInputFocus(display, &xW, &state);
if( xW == None ||
TSXFindContext(display, xW, winContext, (char **)&hWnd) )
return FALSE;
return TRUE;
}
/***********************************************************************
* EVENT_SelectionRequest_TARGETS
@ -1257,13 +1326,8 @@ static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
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 */
if (!(GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED))
PostMessageA( hWnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
}
if (event->message_type == wmProtocols)
handle_wm_protocols_message( hWnd, event );
else if (event->message_type == dndProtocol)
{
/* query window (drag&drop event contains only drag window) */

View File

@ -404,9 +404,7 @@ void X11DRV_set_wm_hints( Display *display, WND *win )
if ((wm_hints = TSXAllocWMHints()))
{
wm_hints->flags = InputHint | StateHint | WindowGroupHint;
/* use globally active model if take focus is supported,
* passive model otherwise (cf. ICCCM) */
wm_hints->input = !wmTakeFocus;
wm_hints->input = !(win->dwStyle & WS_DISABLED);
set_icon_hints( display, win, wm_hints );
@ -621,8 +619,7 @@ static void create_desktop( Display *display, WND *wndPtr, CREATESTRUCTA *cs )
winContext = XUniqueContext();
wmProtocols = XInternAtom( display, "WM_PROTOCOLS", False );
wmDeleteWindow = XInternAtom( display, "WM_DELETE_WINDOW", False );
/* wmTakeFocus = XInternAtom( display, "WM_TAKE_FOCUS", False );*/
wmTakeFocus = 0; /* not yet */
if (use_take_focus) wmTakeFocus = XInternAtom( display, "WM_TAKE_FOCUS", False );
dndProtocol = XInternAtom( display, "DndProtocol" , False );
dndSelection = XInternAtom( display, "DndSelection" , False );
wmChangeState = XInternAtom( display, "WM_CHANGE_STATE", False );
@ -825,6 +822,7 @@ BOOL X11DRV_DestroyWindow( HWND hwnd )
{
TRACE( "win %x xwin %lx/%lx\n", hwnd, data->whole_window, data->client_window );
if (thread_data->cursor_window == data->whole_window) thread_data->cursor_window = None;
if (thread_data->last_focus == hwnd) thread_data->last_focus = 0;
wine_tsx11_lock();
XSync( gdi_display, False ); /* flush any reference to this drawable in GDI queue */
XDeleteContext( display, data->whole_window, winContext );

View File

@ -64,6 +64,7 @@ unsigned int screen_height;
unsigned int screen_depth;
Window root_window;
int dxgrab, usedga, usexvidmode;
int use_take_focus = 1;
int managed_mode = 1;
unsigned int X11DRV_server_startticks;
@ -247,6 +248,9 @@ static void setup_options(void)
if (!get_config_key( hkey, appkey, "UseXVidMode", buffer, sizeof(buffer) ))
usexvidmode = IS_OPTION_TRUE( buffer[0] );
if (!get_config_key( hkey, appkey, "UseTakeFocus", buffer, sizeof(buffer) ))
use_take_focus = IS_OPTION_TRUE( buffer[0] );
screen_depth = 0;
if (!get_config_key( hkey, appkey, "ScreenDepth", buffer, sizeof(buffer) ))
screen_depth = atoi(buffer);
@ -461,6 +465,7 @@ struct x11drv_thread_data *x11drv_init_thread_data(void)
data->process_event_count = 0;
data->cursor = None;
data->cursor_window = None;
data->last_focus = 0;
NtCurrentTeb()->driver_data = data;
return data;
}

View File

@ -141,6 +141,8 @@ WINE REGISTRY Version 2
"UseXShm" = "Y"
; Use XVidMode extension if present
"UseXVidMode" = "Y"
; Use the take focus protocol
"UseTakeFocus" = "Y"
; Enable DirectX mouse grab
"DXGrab" = "N"
; Create the desktop window with a double-buffered visual

View File

@ -329,6 +329,7 @@ struct x11drv_thread_data
int process_event_count; /* recursion count for event processing */
Cursor cursor; /* current cursor */
Window cursor_window; /* current window that contains the cursor */
HWND last_focus; /* last window that had focus */
};
extern struct x11drv_thread_data *x11drv_init_thread_data(void);
@ -348,6 +349,7 @@ extern unsigned int screen_width;
extern unsigned int screen_height;
extern unsigned int screen_depth;
extern unsigned int text_caps;
extern int use_take_focus;
extern int managed_mode;
extern Atom wmProtocols;