зеркало из https://github.com/mozilla/gecko-dev.git
Bug #191072. Fixing focus for plugins. Patch from robin.lu@sun.com r=me
This commit is contained in:
Родитель
78eed0300d
Коммит
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
|
||||
|
@ -978,7 +994,7 @@ nsWindow::SetIcon(const nsAString& aIconSpec)
|
|||
PRInt32 n = iconSpec.Find(key) + key.Length();
|
||||
|
||||
// Append that to icon resource path.
|
||||
iconPath.Append(iconSpec.get() + n - 1 );
|
||||
iconPath.Append(iconSpec.get() + n - 1);
|
||||
|
||||
nsCOMPtr<nsILocalFile> pathConverter;
|
||||
rv = NS_NewLocalFile(iconPath, PR_TRUE,
|
||||
|
@ -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)
|
||||
|
@ -1488,7 +1487,7 @@ nsWindow::OnContainerFocusOutEvent(GtkWidget *aWidget, GdkEventFocus *aEvent)
|
|||
|
||||
while (tmpWindow && tmpnsWindow) {
|
||||
// found it!
|
||||
if(tmpnsWindow == gFocusWindow)
|
||||
if (tmpnsWindow == gFocusWindow)
|
||||
goto foundit;
|
||||
|
||||
tmpWindow = gdk_window_get_parent(tmpWindow);
|
||||
|
@ -1575,7 +1574,7 @@ nsWindow::OnKeyPressEvent(GtkWidget *aWidget, GdkEventKey *aEvent)
|
|||
// if none of the other modifier keys are pressed then we need to
|
||||
// clear isShift so the character can be inserted in the editor
|
||||
|
||||
if ( event.isControl || event.isAlt || event.isMeta ) {
|
||||
if (event.isControl || event.isAlt || event.isMeta) {
|
||||
// make Ctrl+uppercase functional as same as Ctrl+lowercase
|
||||
// when Ctrl+uppercase(eg.Ctrl+C) is pressed,convert the charCode
|
||||
// from uppercase to lowercase(eg.Ctrl+c),so do Alt and Meta Key
|
||||
|
@ -1583,9 +1582,9 @@ nsWindow::OnKeyPressEvent(GtkWidget *aWidget, GdkEventKey *aEvent)
|
|||
// Windows platform in widget/src/windows/nsWindow.cpp: See bug 16486
|
||||
// Note: if Shift is pressed at the same time, do not to_lower()
|
||||
// Because Ctrl+Shift has different function with Ctrl
|
||||
if ( !event.isShift &&
|
||||
event.charCode >= GDK_A &&
|
||||
event.charCode <= GDK_Z )
|
||||
if (!event.isShift &&
|
||||
event.charCode >= GDK_A &&
|
||||
event.charCode <= GDK_Z)
|
||||
event.charCode = gdk_keyval_to_lower(event.charCode);
|
||||
}
|
||||
}
|
||||
|
@ -2111,11 +2110,12 @@ nsWindow::NativeCreate(nsIWidget *aParent,
|
|||
}
|
||||
else if (mWindowType == eWindowType_popup) {
|
||||
mShell = gtk_window_new(GTK_WINDOW_POPUP);
|
||||
if(topLevelParent) {
|
||||
if (topLevelParent) {
|
||||
gtk_window_set_transient_for(GTK_WINDOW(mShell),
|
||||
topLevelParent);
|
||||
mTransientParent = topLevelParent;
|
||||
if(topLevelParent->group) {
|
||||
|
||||
if (topLevelParent->group) {
|
||||
gtk_window_group_add_window(topLevelParent->group,
|
||||
GTK_WINDOW(mShell));
|
||||
mWindowGroup = topLevelParent->group;
|
||||
|
@ -2167,7 +2167,7 @@ nsWindow::NativeCreate(nsIWidget *aParent,
|
|||
}
|
||||
// Disable the double buffer because it will make the caret crazy
|
||||
// For bug#153805 (Gtk2 double buffer makes carets misbehave)
|
||||
if( mContainer )
|
||||
if (mContainer)
|
||||
gtk_widget_set_double_buffered (GTK_WIDGET(mContainer),FALSE);
|
||||
|
||||
// label the drawing area with this object so we can find our way
|
||||
|
@ -2529,7 +2529,7 @@ nsWindow::SetupPluginPort(void)
|
|||
XSelectInput (GDK_DISPLAY (),
|
||||
GDK_WINDOW_XWINDOW(mDrawingarea->inner_window),
|
||||
xattrs.your_event_mask |
|
||||
SubstructureNotifyMask );
|
||||
SubstructureNotifyMask);
|
||||
|
||||
gdk_window_add_filter(mDrawingarea->inner_window,
|
||||
plugin_window_filter_func,
|
||||
|
@ -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)
|
||||
|
@ -2688,8 +2783,8 @@ is_mouse_in_window (GdkWindow* aWindow, gdouble aMouseX, gdouble aMouseY)
|
|||
|
||||
gdk_window_get_size(aWindow, &w, &h);
|
||||
|
||||
if ( aMouseX > x && aMouseX < x + w &&
|
||||
aMouseY > y && aMouseY < y + h )
|
||||
if (aMouseX > x && aMouseX < x + w &&
|
||||
aMouseY > y && aMouseY < y + h)
|
||||
return PR_TRUE;
|
||||
|
||||
return PR_FALSE;
|
||||
|
@ -3055,31 +3150,83 @@ plugin_window_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data
|
|||
{
|
||||
case CreateNotify:
|
||||
case ReparentNotify:
|
||||
if(xevent->type==CreateNotify) {
|
||||
if (xevent->type==CreateNotify) {
|
||||
plugin_window = gdk_window_lookup(xevent->xcreatewindow.window);
|
||||
}
|
||||
else {
|
||||
if(xevent->xreparent.event != xevent->xreparent.parent)
|
||||
if (xevent->xreparent.event != xevent->xreparent.parent)
|
||||
break;
|
||||
plugin_window = gdk_window_lookup (xevent->xreparent.window);
|
||||
}
|
||||
if(plugin_window) {
|
||||
if (plugin_window) {
|
||||
user_data = nsnull;
|
||||
gdk_window_get_user_data(plugin_window, &user_data);
|
||||
widget = GTK_WIDGET(user_data);
|
||||
if(GTK_IS_SOCKET(widget)){
|
||||
|
||||
if (GTK_IS_SOCKET(widget)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
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)
|
||||
|
@ -3410,8 +3557,8 @@ get_inner_gdk_window (GdkWindow *aWindow,
|
|||
if (child) {
|
||||
GdkWindow * childWindow = (GdkWindow *) child->data;
|
||||
gdk_window_get_geometry (childWindow, &cx, &cy, &cw, &ch, &cd);
|
||||
if (( cx < x ) && (x < (cx + cw)) &&
|
||||
( cy < y ) && (y < (cy + ch)) &&
|
||||
if ((cx < x) && (x < (cx + cw)) &&
|
||||
(cy < y) && (y < (cy + ch)) &&
|
||||
gdk_window_is_visible (childWindow)) {
|
||||
return get_inner_gdk_window (childWindow,
|
||||
x - cx, y - cy,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче