mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-11 12:25:53 +00:00
Bug #191072. Fixing focus for plugins. Patch from robin.lu@sun.com r=me
This commit is contained in:
parent
78eed0300d
commit
a8f66c1626
@ -119,9 +119,19 @@ static gboolean window_state_event_cb (GtkWidget *widget,
|
||||
GdkEventWindowState *event);
|
||||
static gboolean property_notify_event_cb (GtkWidget *widget,
|
||||
GdkEventProperty *event);
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
static GdkFilterReturn plugin_window_filter_func (GdkXEvent *gdk_xevent,
|
||||
GdkEvent *event,
|
||||
gpointer data);
|
||||
static GdkFilterReturn plugin_client_message_filter (GdkXEvent *xevent,
|
||||
GdkEvent *event,
|
||||
gpointer data);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
static gboolean drag_motion_event_cb (GtkWidget *aWidget,
|
||||
GdkDragContext *aDragContext,
|
||||
gint aX,
|
||||
@ -159,6 +169,7 @@ static NS_DEFINE_IID(kCDragServiceCID, NS_DRAGSERVICE_CID);
|
||||
static nsWindow *gFocusWindow = NULL;
|
||||
static PRBool gGlobalsInitialized = PR_FALSE;
|
||||
static PRBool gRaiseWindows = PR_TRUE;
|
||||
static nsWindow *gPluginFocusWindow = NULL;
|
||||
|
||||
nsCOMPtr <nsIRollupListener> gRollupListener;
|
||||
nsWeakPtr gRollupWindow;
|
||||
@ -406,6 +417,11 @@ nsWindow::Destroy(void)
|
||||
gFocusWindow = nsnull;
|
||||
}
|
||||
|
||||
// make sure that we remove ourself as the plugin focus window
|
||||
if (gPluginFocusWindow == this) {
|
||||
gPluginFocusWindow->LoseNonXEmbedPluginFocus();
|
||||
}
|
||||
|
||||
// Remove our reference to the window group. If there was a window
|
||||
// group destroying the widget will have automatically unreferenced
|
||||
// the group, destroying it if necessary. And, if we're a child
|
||||
@ -1282,24 +1298,6 @@ nsWindow::OnEnterNotifyEvent(GtkWidget *aWidget, GdkEventCrossing *aEvent)
|
||||
|
||||
LOG(("OnEnterNotify: %p\n", (void *)this));
|
||||
|
||||
// if we have a non-xembed plugin (java, basically) dispatch focus
|
||||
// to it because it's too dumb not to know how to do it itself.
|
||||
if( mHasNonXembedPlugin ) {
|
||||
Window curFocusWindow;
|
||||
int focusState;
|
||||
XGetInputFocus(GDK_WINDOW_XDISPLAY (aEvent->window),
|
||||
&curFocusWindow,
|
||||
&focusState);
|
||||
if(curFocusWindow != GDK_WINDOW_XWINDOW(aEvent->window)) {
|
||||
mOldFocusWindow = curFocusWindow;
|
||||
XSetInputFocus(GDK_WINDOW_XDISPLAY (aEvent->window),
|
||||
GDK_WINDOW_XWINDOW(aEvent->window),
|
||||
RevertToParent,
|
||||
gtk_get_current_event_time ());
|
||||
}
|
||||
gdk_flush();
|
||||
}
|
||||
|
||||
nsEventStatus status;
|
||||
DispatchEvent(&event, status);
|
||||
}
|
||||
@ -1315,16 +1313,6 @@ nsWindow::OnLeaveNotifyEvent(GtkWidget *aWidget, GdkEventCrossing *aEvent)
|
||||
|
||||
LOG(("OnLeaveNotify: %p\n", (void *)this));
|
||||
|
||||
// if we have a non-xembed plugin (java, basically) take focus
|
||||
// back since it's not going to give it up by itself.
|
||||
if( mHasNonXembedPlugin ) {
|
||||
XSetInputFocus(GDK_WINDOW_XDISPLAY (aEvent->window),
|
||||
mOldFocusWindow,
|
||||
RevertToParent,
|
||||
gtk_get_current_event_time ());
|
||||
gdk_flush();
|
||||
}
|
||||
|
||||
nsEventStatus status;
|
||||
DispatchEvent(&event, status);
|
||||
}
|
||||
@ -1341,6 +1329,11 @@ nsWindow::OnMotionNotifyEvent(GtkWidget *aWidget, GdkEventMotion *aEvent)
|
||||
synthEvent = PR_TRUE;
|
||||
}
|
||||
|
||||
// if plugins still keeps the focus, get it back
|
||||
if (gPluginFocusWindow && gPluginFocusWindow != this) {
|
||||
gPluginFocusWindow->LoseNonXEmbedPluginFocus();
|
||||
}
|
||||
|
||||
nsMouseEvent event;
|
||||
InitMouseEvent(event, NS_MOUSE_MOVE);
|
||||
|
||||
@ -1477,6 +1470,12 @@ void
|
||||
nsWindow::OnContainerFocusOutEvent(GtkWidget *aWidget, GdkEventFocus *aEvent)
|
||||
{
|
||||
LOGFOCUS(("OnContainerFocusOutEvent [%p]\n", (void *)this));
|
||||
|
||||
// plugin lose focus
|
||||
if (gPluginFocusWindow) {
|
||||
gPluginFocusWindow->LoseNonXEmbedPluginFocus();
|
||||
}
|
||||
|
||||
// Figure out if the focus widget is the child of this window. If
|
||||
// it is, send a focus out and deactivate event for it.
|
||||
if (!gFocusWindow)
|
||||
@ -2115,6 +2114,7 @@ nsWindow::NativeCreate(nsIWidget *aParent,
|
||||
gtk_window_set_transient_for(GTK_WINDOW(mShell),
|
||||
topLevelParent);
|
||||
mTransientParent = topLevelParent;
|
||||
|
||||
if (topLevelParent->group) {
|
||||
gtk_window_group_add_window(topLevelParent->group,
|
||||
GTK_WINDOW(mShell));
|
||||
@ -2592,6 +2592,101 @@ nsWindow::SetPluginType(PRBool aIsXembed)
|
||||
mHasNonXembedPlugin = !aIsXembed;
|
||||
}
|
||||
|
||||
void
|
||||
nsWindow::SetNonXEmbedPluginFocus()
|
||||
{
|
||||
if (gPluginFocusWindow == this) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gPluginFocusWindow) {
|
||||
gPluginFocusWindow->LoseNonXEmbedPluginFocus();
|
||||
}
|
||||
|
||||
LOGFOCUS(("nsWindow::SetNonXEmbedPluginFocus\n"));
|
||||
|
||||
Window curFocusWindow;
|
||||
int focusState;
|
||||
|
||||
XGetInputFocus(GDK_WINDOW_XDISPLAY(mDrawingarea->inner_window),
|
||||
&curFocusWindow,
|
||||
&focusState);
|
||||
|
||||
LOGFOCUS(("\t curFocusWindow=%p\n", curFocusWindow));
|
||||
|
||||
GdkWindow* toplevel = gdk_window_get_toplevel
|
||||
(mDrawingarea->inner_window);
|
||||
GdkWindow *gdkfocuswin = gdk_window_lookup(curFocusWindow);
|
||||
|
||||
// lookup with the focus proxy window is supposed to get the
|
||||
// same GdkWindow as toplevel. If the current focused window
|
||||
// is not the focus proxy, we return without any change.
|
||||
if (gdkfocuswin != toplevel) {
|
||||
return;
|
||||
}
|
||||
|
||||
// switch the focus from the focus proxy to the plugin window
|
||||
mOldFocusWindow = curFocusWindow;
|
||||
XRaiseWindow(GDK_WINDOW_XDISPLAY(mDrawingarea->inner_window),
|
||||
GDK_WINDOW_XWINDOW(mDrawingarea->inner_window));
|
||||
gdk_error_trap_push();
|
||||
XSetInputFocus(GDK_WINDOW_XDISPLAY(mDrawingarea->inner_window),
|
||||
GDK_WINDOW_XWINDOW(mDrawingarea->inner_window),
|
||||
RevertToNone,
|
||||
CurrentTime);
|
||||
gdk_flush();
|
||||
gdk_error_trap_pop();
|
||||
gPluginFocusWindow = this;
|
||||
gdk_window_add_filter(NULL, plugin_client_message_filter, this);
|
||||
|
||||
LOGFOCUS(("nsWindow::SetNonXEmbedPluginFocus oldfocus=%p new=%p\n",
|
||||
mOldFocusWindow,
|
||||
GDK_WINDOW_XWINDOW(mDrawingarea->inner_window)));
|
||||
}
|
||||
|
||||
void
|
||||
nsWindow::LoseNonXEmbedPluginFocus()
|
||||
{
|
||||
LOGFOCUS(("nsWindow::LoseNonXEmbedPluginFocus\n"));
|
||||
|
||||
// This method is only for the nsWindow which contains a
|
||||
// Non-XEmbed plugin, for example, JAVA plugin.
|
||||
if (gPluginFocusWindow != this) {
|
||||
return;
|
||||
}
|
||||
|
||||
Window curFocusWindow;
|
||||
int focusState;
|
||||
|
||||
XGetInputFocus(GDK_WINDOW_XDISPLAY(mDrawingarea->inner_window),
|
||||
&curFocusWindow,
|
||||
&focusState);
|
||||
|
||||
// we only switch focus between plugin window and focus proxy. If the
|
||||
// current focused window is not the plugin window, just removing the
|
||||
// event filter that blocks the WM_TAKE_FOCUS is enough. WM and gtk2
|
||||
// will take care of the focus later.
|
||||
if (!curFocusWindow ||
|
||||
curFocusWindow == GDK_WINDOW_XWINDOW(mDrawingarea->inner_window)) {
|
||||
|
||||
gdk_error_trap_push();
|
||||
XRaiseWindow(GDK_WINDOW_XDISPLAY(mDrawingarea->inner_window),
|
||||
mOldFocusWindow);
|
||||
XSetInputFocus(GDK_WINDOW_XDISPLAY(mDrawingarea->inner_window),
|
||||
mOldFocusWindow,
|
||||
RevertToParent,
|
||||
CurrentTime);
|
||||
gdk_flush();
|
||||
gdk_error_trap_pop();
|
||||
}
|
||||
gPluginFocusWindow = NULL;
|
||||
mOldFocusWindow = 0;
|
||||
gdk_window_remove_filter(NULL, plugin_client_message_filter, this);
|
||||
|
||||
LOGFOCUS(("nsWindow::LoseNonXEmbedPluginFocus end\n"));
|
||||
}
|
||||
|
||||
|
||||
PRBool
|
||||
check_for_rollup(GdkWindow *aWindow, gdouble aMouseX, gdouble aMouseY,
|
||||
PRBool aIsWheel)
|
||||
@ -3067,6 +3162,7 @@ plugin_window_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data
|
||||
user_data = nsnull;
|
||||
gdk_window_get_user_data(plugin_window, &user_data);
|
||||
widget = GTK_WIDGET(user_data);
|
||||
|
||||
if (GTK_IS_SOCKET(widget)) {
|
||||
break;
|
||||
}
|
||||
@ -3074,12 +3170,63 @@ plugin_window_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data
|
||||
nswindow->SetPluginType(PR_FALSE);
|
||||
return_val = GDK_FILTER_REMOVE;
|
||||
break;
|
||||
case EnterNotify:
|
||||
// Currently we consider all plugins are non-xembed and calls
|
||||
// SetNonXEmbedPluginFocus without any checking.
|
||||
nswindow->SetNonXEmbedPluginFocus();
|
||||
break;
|
||||
case DestroyNotify:
|
||||
gdk_window_remove_filter
|
||||
((GdkWindow*)(nswindow->GetNativeData(NS_NATIVE_WINDOW)),
|
||||
plugin_window_filter_func,
|
||||
nswindow);
|
||||
// Currently we consider all plugins are non-xembed and calls
|
||||
// LoseNonXEmbedPluginFocus without any checking.
|
||||
nswindow->LoseNonXEmbedPluginFocus();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return return_val;
|
||||
}
|
||||
|
||||
/* static */
|
||||
GdkFilterReturn
|
||||
plugin_client_message_filter (GdkXEvent *gdk_xevent,
|
||||
GdkEvent *event,
|
||||
gpointer data)
|
||||
{
|
||||
XEvent *xevent;
|
||||
xevent = (XEvent *)gdk_xevent;
|
||||
|
||||
GdkFilterReturn return_val;
|
||||
return_val = GDK_FILTER_CONTINUE;
|
||||
|
||||
if (!gPluginFocusWindow || xevent->type!=ClientMessage) {
|
||||
return return_val;
|
||||
}
|
||||
|
||||
// When WM sends out WM_TAKE_FOCUS, gtk2 will use XSetInputFocus
|
||||
// to set the focus to the focus proxy. To prevent this happen
|
||||
// while the focus is on the plugin, we filter the WM_TAKE_FOCUS
|
||||
// out.
|
||||
Display *dpy ;
|
||||
dpy = GDK_WINDOW_XDISPLAY((GdkWindow*)(gPluginFocusWindow->
|
||||
GetNativeData(NS_NATIVE_WINDOW)));
|
||||
if (gdk_x11_get_xatom_by_name("WM_PROTOCOLS")
|
||||
!= xevent->xclient.message_type) {
|
||||
return return_val;
|
||||
}
|
||||
|
||||
if ((Atom) xevent->xclient.data.l[0] ==
|
||||
gdk_x11_get_xatom_by_name("WM_TAKE_FOCUS")) {
|
||||
// block it from gtk2.0 focus proxy
|
||||
return_val = GDK_FILTER_REMOVE;
|
||||
}
|
||||
|
||||
return return_val;
|
||||
}
|
||||
|
||||
/* static */
|
||||
gboolean
|
||||
key_press_event_cb (GtkWidget *widget, GdkEventKey *event)
|
||||
|
@ -229,7 +229,10 @@ public:
|
||||
void GrabPointer (void);
|
||||
void GrabKeyboard (void);
|
||||
void ReleaseGrabs (void);
|
||||
|
||||
void SetPluginType(PRBool aIsXembed);
|
||||
void SetNonXEmbedPluginFocus(void);
|
||||
void LoseNonXEmbedPluginFocus(void);
|
||||
|
||||
Window mOldFocusWindow;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user