From 264b160f0869ea2739e1e2b95ab49b413eb3a2f6 Mon Sep 17 00:00:00 2001 From: "blizzard%redhat.com" Date: Fri, 17 Mar 2000 22:05:00 +0000 Subject: [PATCH] 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 --- mozilla/widget/src/gtk/nsGtkEventHandler.cpp | 198 +++++++++++++++---- mozilla/widget/src/gtk/nsWindow.cpp | 13 ++ mozilla/widget/src/gtk/nsWindow.h | 4 + 3 files changed, 175 insertions(+), 40 deletions(-) diff --git a/mozilla/widget/src/gtk/nsGtkEventHandler.cpp b/mozilla/widget/src/gtk/nsGtkEventHandler.cpp index 2f2edb46377..460cebc57e4 100644 --- a/mozilla/widget/src/gtk/nsGtkEventHandler.cpp +++ b/mozilla/widget/src/gtk/nsGtkEventHandler.cpp @@ -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) diff --git a/mozilla/widget/src/gtk/nsWindow.cpp b/mozilla/widget/src/gtk/nsWindow.cpp index ca6ee1c9981..dee3ba1be74 100644 --- a/mozilla/widget/src/gtk/nsWindow.cpp +++ b/mozilla/widget/src/gtk/nsWindow.cpp @@ -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) { diff --git a/mozilla/widget/src/gtk/nsWindow.h b/mozilla/widget/src/gtk/nsWindow.h index 0f1991766e5..ac1f6597a6d 100644 --- a/mozilla/widget/src/gtk/nsWindow.h +++ b/mozilla/widget/src/gtk/nsWindow.h @@ -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: //////////////////////////////////////////////////////////////////////