fix for bug #26508. rewrite the main event hander for gtk to properly handle all the possible grab combinations properly. this should fix problems with scrollbars on popups and on modal dialogs.
git-svn-id: svn://10.0.0.236/trunk@63318 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -49,6 +49,15 @@
|
||||
//#define DEBUG_EVENTS 1
|
||||
#endif
|
||||
|
||||
static void
|
||||
dispatch_superwin_event(GdkEvent *event, nsWindow *window);
|
||||
|
||||
static PRBool
|
||||
superwin_child_of_gtk_widget(nsWindow *window, GtkWidget *widget);
|
||||
|
||||
static PRBool
|
||||
gtk_widget_child_of_gdk_window(GtkWidget *widget, GdkWindow *window);
|
||||
|
||||
struct EventInfo {
|
||||
nsWidget *widget; // the widget
|
||||
nsRect *rect; // the rect
|
||||
@@ -759,74 +768,183 @@ handle_gdk_event (GdkEvent *event, gpointer data)
|
||||
{
|
||||
GtkObject *object = nsnull;
|
||||
|
||||
// set the last time that we got an event. we need this for drag
|
||||
// and drop if you can believe that.
|
||||
guint32 event_time = gdk_event_get_time(event);
|
||||
if (event_time)
|
||||
nsWidget::SetLastEventTime(event_time);
|
||||
|
||||
// try to get the user data for the event window.
|
||||
if (event->any.window)
|
||||
gdk_window_get_user_data (event->any.window, (void **)&object);
|
||||
|
||||
if (object != nsnull &&
|
||||
GDK_IS_SUPERWIN (object))
|
||||
// check to see if this is an event on a superwin window. if it is,
|
||||
// we have to handle it because if it gets down to the standard gtk
|
||||
// event handler it will cause all sorts of mischief.
|
||||
|
||||
if (object != nsnull && GDK_IS_SUPERWIN (object))
|
||||
{
|
||||
|
||||
// It was an event on one of our superwindows
|
||||
|
||||
// try to find the nsWindow object associated with this superwin
|
||||
nsWindow *window = (nsWindow *)gtk_object_get_data (object, "nsWindow");
|
||||
|
||||
// if we don't have a window here anymore, we are probably in the process of being or have been destroyed
|
||||
// if we don't have a window here anymore, we are probably in
|
||||
// the process of being or have been destroyed. give up now.
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
// there are three possibilities here.
|
||||
// o there's a gtk grab in effect but no superwin grab
|
||||
//
|
||||
// if this is the case then we need to see if the superwin is a
|
||||
// child of the grabbed widget. if it is, then let the event
|
||||
// pass to the nsWindow associated with the superwin, as normal.
|
||||
//
|
||||
// if not, then rewrite the event widget window to the nearest
|
||||
// MozArea widget and let it pass to the default gtk event
|
||||
// handler.
|
||||
//
|
||||
// o there's a superwin grab in effect but no gtk grab
|
||||
//
|
||||
// easy. let the nsWindow associated with the superwin handle
|
||||
// the event.
|
||||
//
|
||||
// o there's both a gtk and superwin grab in effect
|
||||
//
|
||||
// this is where things get messy. we need to see if the
|
||||
// superwin is a child of the grabbing gtk widget. if it is,
|
||||
// pass it to the nsWindow to be handled
|
||||
//
|
||||
// if it in't then rewrite the event to the nearest MozArea
|
||||
// widget since it will get rewritten again in gtk.
|
||||
|
||||
// find out what grabs are in effect
|
||||
GtkWidget *current_grab = gtk_grab_get_current();
|
||||
PRBool superwin_grab = window->GrabInProgress();
|
||||
|
||||
// if there's a grab in progress, make sure to send it right to that widget.
|
||||
if (window->GrabInProgress()) {
|
||||
goto handle_as_superwin;
|
||||
// check to see if there are no grabs in effect
|
||||
if (!current_grab && !superwin_grab)
|
||||
{
|
||||
dispatch_superwin_event(event, window);
|
||||
return;
|
||||
}
|
||||
|
||||
if (current_grab) {
|
||||
// walk up the list of our parents looking for the widget.
|
||||
// if it's there, then don't rewrite the event
|
||||
GtkWidget *this_widget = GTK_WIDGET(window->GetMozArea());
|
||||
while (this_widget) {
|
||||
// if this widget is the grab widget then let the event pass
|
||||
// through as a superwin. this takes care of
|
||||
// superwin windows inside of a modal window.
|
||||
if (this_widget == current_grab)
|
||||
goto handle_as_superwin;
|
||||
this_widget = this_widget->parent;
|
||||
// o there's a gtk grab in effect but no superwin grab
|
||||
else if (current_grab && !superwin_grab)
|
||||
{
|
||||
//
|
||||
// if this is the case then we need to see if the superwin is a
|
||||
// child of the grabbed widget. if it is, then let the event
|
||||
// pass to the nsWindow associated with the superwin, as normal.
|
||||
if (superwin_child_of_gtk_widget(window, current_grab))
|
||||
{
|
||||
dispatch_superwin_event(event, window);
|
||||
return;
|
||||
}
|
||||
// A GTK+ grab is in effect. Rewrite the event to point to
|
||||
// our toplevel, and pass it through.
|
||||
// XXX: We should actually translate the coordinates
|
||||
|
||||
//
|
||||
// if not, then rewrite the event widget window to the nearest
|
||||
// MozArea widget and let it pass to the default gtk event
|
||||
// handler.
|
||||
gdk_window_unref (event->any.window);
|
||||
event->any.window = GTK_WIDGET (window->GetMozArea())->window;
|
||||
gdk_window_ref (event->any.window);
|
||||
// dispatch it.
|
||||
gtk_main_do_event(event);
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
// o there's a superwin grab in effect but no gtk grab
|
||||
else if (!current_grab && superwin_grab)
|
||||
{
|
||||
// easy. let the nsWindow associated with the superwin handle
|
||||
// the event.
|
||||
dispatch_superwin_event(event, window);
|
||||
return;
|
||||
}
|
||||
|
||||
// o there's both a gtk and superwin grab in effect
|
||||
else if (current_grab && superwin_grab)
|
||||
{
|
||||
// this is where things get messy. we need to see if the
|
||||
// superwin is a child of the grabbing gtk widget. if it is,
|
||||
// pass it to the nsWindow to be handled
|
||||
//
|
||||
nsWindow *grabbingWindow = window->GetGrabWindow();
|
||||
GdkWindow *grabbingGdkWindow = (GdkWindow *)grabbingWindow->GetNativeData(NS_NATIVE_WINDOW);
|
||||
GtkWidget *grabbingMozArea = grabbingWindow->GetMozArea();
|
||||
NS_RELEASE(grabbingWindow);
|
||||
if (gtk_widget_child_of_gdk_window(current_grab, grabbingGdkWindow))
|
||||
{
|
||||
// Handle it ourselves.
|
||||
handle_as_superwin:
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_KEY_PRESS:
|
||||
handle_key_press_event (NULL, &event->key, window);
|
||||
break;
|
||||
case GDK_KEY_RELEASE:
|
||||
handle_key_release_event (NULL, &event->key, window);
|
||||
break;
|
||||
default:
|
||||
window->HandleGDKEvent (event);
|
||||
}
|
||||
gdk_window_unref (event->any.window);
|
||||
event->any.window = grabbingMozArea->window;
|
||||
gdk_window_ref (event->any.window);
|
||||
// dispatch it.
|
||||
gtk_main_do_event(event);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// if it in't then rewrite the event to the nearest MozArea
|
||||
// widget since it will get rewritten again in gtk.
|
||||
else
|
||||
{
|
||||
dispatch_superwin_event(event, window);
|
||||
return;
|
||||
|
||||
gtk_main_do_event (event);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_main_do_event (event);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dispatch_superwin_event(GdkEvent *event, nsWindow *window)
|
||||
{
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_KEY_PRESS:
|
||||
handle_key_press_event (NULL, &event->key, window);
|
||||
break;
|
||||
case GDK_KEY_RELEASE:
|
||||
handle_key_release_event (NULL, &event->key, window);
|
||||
break;
|
||||
default:
|
||||
window->HandleGDKEvent (event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
superwin_child_of_gtk_widget(nsWindow *window, GtkWidget *widget)
|
||||
{
|
||||
GtkWidget *this_widget = GTK_WIDGET(window->GetMozArea());
|
||||
while (this_widget)
|
||||
{
|
||||
if (this_widget == widget)
|
||||
{
|
||||
return PR_TRUE;
|
||||
}
|
||||
this_widget = this_widget->parent;
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
gtk_widget_child_of_gdk_window(GtkWidget *widget, GdkWindow *window)
|
||||
{
|
||||
GdkWindow *gdk_window = widget->window;
|
||||
|
||||
GdkWindow *this_window = gdk_window;
|
||||
while (this_window)
|
||||
{
|
||||
if (this_window == window)
|
||||
return PR_TRUE;
|
||||
this_window = gdk_window_get_parent(this_window);
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
//==============================================================
|
||||
void
|
||||
handle_xlib_shell_event(GdkSuperWin *superwin, XEvent *event, gpointer p)
|
||||
|
||||
@@ -2797,6 +2797,19 @@ nsWindow::GrabInProgress(void)
|
||||
return nsWindow::mIsGrabbing;
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsWindow *
|
||||
nsWindow::GetGrabWindow(void)
|
||||
{
|
||||
if (nsWindow::mIsGrabbing)
|
||||
{
|
||||
NS_ADDREF(mGrabWindow);
|
||||
return mGrabWindow;
|
||||
}
|
||||
else
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
/* virtual */ GdkWindow *
|
||||
nsWindow::GetRenderWindow(GtkObject * aGtkObject)
|
||||
{
|
||||
|
||||
@@ -191,6 +191,10 @@ public:
|
||||
// virtual void OnButtonPressSignal(GdkEventButton * aGdkButtonEvent);
|
||||
void ShowCrossAtLocation(guint x, guint y);
|
||||
|
||||
// this will get the nsWindow with the grab. this will AddRef()
|
||||
// before returning.
|
||||
static nsWindow *GetGrabWindow(void);
|
||||
|
||||
protected:
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
Reference in New Issue
Block a user