From defac8118211fa0341c0682a40915098c080dad6 Mon Sep 17 00:00:00 2001 From: "blizzard%redhat.com" Date: Sat, 27 Apr 2002 13:50:21 +0000 Subject: [PATCH] Bug #129591. nsWindow::Enabled is a no-op on GTK. Also fixes bug #65521. linux modal dialogs should only freeze parent window (not all windows.) This code is a big cleanup of the event dispatching code, too. r=bryner,sr=jst git-svn-id: svn://10.0.0.236/trunk@120115 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/widget/src/gtk/nsGtkEventHandler.cpp | 78 ++--- mozilla/widget/src/gtk/nsWidget.cpp | 319 ------------------- mozilla/widget/src/gtk/nsWidget.h | 11 +- mozilla/widget/src/gtk/nsWindow.cpp | 238 +++++++++++--- mozilla/widget/src/gtk/nsWindow.h | 13 + 5 files changed, 242 insertions(+), 417 deletions(-) diff --git a/mozilla/widget/src/gtk/nsGtkEventHandler.cpp b/mozilla/widget/src/gtk/nsGtkEventHandler.cpp index 329632820a6..4984ad93bee 100644 --- a/mozilla/widget/src/gtk/nsGtkEventHandler.cpp +++ b/mozilla/widget/src/gtk/nsGtkEventHandler.cpp @@ -50,7 +50,8 @@ #include -#include "gtk/gtk.h" +#include +#include #include "nsGtkEventHandler.h" #include @@ -755,11 +756,21 @@ handle_gdk_event (GdkEvent *event, gpointer data) if (!window) goto end; - // Get the grabbing widget, if there is one. We will need this - // later. - GtkWidget *grabWidget; - grabWidget = gtk_grab_get_current(); - PRBool grabIsRegularWidget = (grabWidget && !GTK_IS_MOZAREA(grabWidget)); + // Find out if there's a grabbing widget. If there is and it's a + // regular gtk widget, and our current event window is not the + // child of that grab widget, we need to rewrite the event to that + // gtk grabbing widget. + PRBool rewriteEvent = PR_FALSE; + GtkWidget *grabWidget = gtk_grab_get_current(); + GtkWidget *owningWidget = window->GetOwningWidget(); + + if (grabWidget && + !GTK_IS_MOZAREA(grabWidget) && + !gdk_window_child_of_gdk_window(owningWidget->window, + grabWidget->window)) { + rewriteEvent = PR_TRUE; + } + // There are a lot of events that are always dispatched to our // internal handler, no matter if there is a grab or not. @@ -790,69 +801,44 @@ handle_gdk_event (GdkEvent *event, gpointer data) case GDK_3BUTTON_PRESS: case GDK_KEY_PRESS: case GDK_KEY_RELEASE: - // Always rewrite the event to the grab widget. If it's a - // MozArea widget, the handler will get called as normal. - if (grabWidget && - !gdk_window_child_of_gdk_window(window->GetOwningWidget()->window, - grabWidget->window)) { + // If we need to rewrite this to the nearest real gtk widget, + // do it here. + if (rewriteEvent) { gdk_window_unref(event->any.window); - event->any.window = grabWidget->window; + event->any.window = owningWidget->window; gdk_window_ref(event->any.window); gtk_main_do_event(event); break; } // Otherwise, just send it to our event handler - dispatch_superwin_event(event, window); + if (GTK_WIDGET_IS_SENSITIVE(owningWidget)) + dispatch_superwin_event(event, window); break; case GDK_MOTION_NOTIFY: case GDK_BUTTON_RELEASE: case GDK_PROXIMITY_IN: case GDK_PROXIMITY_OUT: - // We only rewrite these events if the grab happens on a - // non-mozilla window. Menus get really sad if we don't do it - // this way since they expect to get events on their native - // windows, no matter if there is a grab in effect or not. - if (grabIsRegularWidget && - !gdk_window_child_of_gdk_window(window->GetOwningWidget()->window, - grabWidget->window)) { - // We rewrite the event to the nearest "real" widget so that - // the gtk mainloop doesn't get confuse-ed. + // See above. + if (rewriteEvent) { gdk_window_unref(event->any.window); - event->any.window = window->GetOwningWidget()->window; + event->any.window = owningWidget->window; gdk_window_ref(event->any.window); gtk_propagate_event(grabWidget, event); - - if (event->type == GDK_BUTTON_RELEASE) { - // Always clear the button motion target when sending a - // button release event to a real gtk widget, otherwise - // mozilla will still think it has the grab. This happens - // when there's a native gtk widget popup over a Mozilla - // area. - nsWidget::DropMotionTarget(); - } break; } - dispatch_superwin_event(event, window); + if (GTK_WIDGET_IS_SENSITIVE(owningWidget)) + dispatch_superwin_event(event, window); break; case GDK_ENTER_NOTIFY: case GDK_LEAVE_NOTIFY: - // We rewrite the event to the nearest "real" widget so that - // the gtk mainloop doesn't get confuse-ed. - if (grabWidget && - gdk_window_child_of_gdk_window(window->GetOwningWidget()->window, - grabWidget->window)) { - gdk_window_unref(event->any.window); - event->any.window = window->GetOwningWidget()->window; - gdk_window_ref(event->any.window); - gtk_widget_event(grabWidget, event); - break; - } - - // XXX these should track sensitivity! + // Always dispatch enter and leave notify events to the + // windows that they happened on so that state can be properly + // tracked. The code that handles the enter and leave events + // tracks sensitivity as well. dispatch_superwin_event(event, window); break; diff --git a/mozilla/widget/src/gtk/nsWidget.cpp b/mozilla/widget/src/gtk/nsWidget.cpp index 59215eb57e2..dca3f46776f 100644 --- a/mozilla/widget/src/gtk/nsWidget.cpp +++ b/mozilla/widget/src/gtk/nsWidget.cpp @@ -69,25 +69,6 @@ static NS_DEFINE_CID(kRegionCID, NS_REGION_CID); static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID); static NS_DEFINE_IID(kCDragServiceCID, NS_DRAGSERVICE_CID); -// keeping track of a list of simultaneously modal widgets -class ModalWidgetList { -public: - ModalWidgetList(nsWidget *aWidget); - ~ModalWidgetList(); - - static PRBool Find(nsWidget *aWidget); - static void Append(nsWidget *aWidget); - static void Remove(nsWidget *aWidget); - static void RemoveLast(void); - static void Suppress(PRBool aSuppress); - -private: - nsWidget *mWidget; - ModalWidgetList *mNext, - *mPrev, - *mLast; // valid only for head of list -}; - PRUint32 nsWidget::sWidgetCount = 0; // this is the nsWindow with the focus @@ -301,7 +282,6 @@ nsWidget::~nsWidget() // to be called once Destroy(); - NS_ASSERTION(!ModalWidgetList::Find(this), "destroying widget without first clearing modality."); } @@ -435,13 +415,6 @@ nsWidget::DestroySignal(GtkWidget* aGtkWidget, nsWidget* aWidget) return PR_TRUE; } -void -nsWidget::SuppressModality(PRBool aSuppress) -{ - ModalWidgetList::Suppress(aSuppress); -} - - void nsWidget::OnDestroySignal(GtkWidget* aGtkWidget) { @@ -493,30 +466,6 @@ NS_IMETHODIMP nsWidget::CaptureRollupEvents(nsIRollupListener * aListener, PRBoo return NS_OK; } -NS_IMETHODIMP nsWidget::SetModal(PRBool aModal) -{ - GtkWindow *topWindow; - - topWindow = GetTopLevelWindow(); - - if (!topWindow) { - if (!aModal) { - ModalWidgetList::RemoveLast(); - } - return NS_ERROR_FAILURE; - } - - if (aModal) { - ModalWidgetList::Append(this); - gtk_window_set_modal(topWindow, TRUE); - } else { - ModalWidgetList::Remove(this); - gtk_window_set_modal(topWindow, FALSE); - } - - return NS_OK; -} - NS_IMETHODIMP nsWidget::IsVisible(PRBool &aState) { if (mWidget) @@ -1820,90 +1769,6 @@ nsWidget::OnLeaveNotifySignal(GdkEventCrossing * aGdkCrossingEvent) } -// -// IsMouseInWindow -// -// Check if the mouse x/y is within the given window -// -PRBool -nsWidget :: IsMouseInWindow ( GdkWindow* inWindow, PRInt32 inMouseX, PRInt32 inMouseY ) -{ - gint x, y; - gint w, h; - - // XXX this causes a round trip to the ever lovely X server. fix me. - gdk_window_get_origin(inWindow, &x, &y); - - // this doesn't... it just pokes GdkWindowPrivate :-) - gdk_window_get_size(inWindow, &w, &h); - - if ( inMouseX > x && inMouseX < x + w && - inMouseY > y && inMouseY < y + h ) - return PR_TRUE; - - return PR_FALSE; - -} // IsMouseInWindow - - -// -// HandlePopup -// -// Deal with rollup of popups (xpmenus, etc) -// -PRBool -nsWidget::HandlePopup(PRInt32 inMouseX, PRInt32 inMouseY, PRBool isWheel) -{ - PRBool retVal = PR_FALSE; - nsCOMPtr rollupWidget = do_QueryReferent(gRollupWidget); - if (rollupWidget && gRollupListener) - { - GdkWindow *currentPopup = (GdkWindow *)rollupWidget->GetNativeData(NS_NATIVE_WINDOW); - if ( !IsMouseInWindow(currentPopup, inMouseX, inMouseY) ) { - PRBool rollup = PR_TRUE; - if (isWheel) { - gRollupListener->ShouldRollupOnMouseWheelEvent(&rollup); - retVal = PR_TRUE; - } - // if we're dealing with menus, we probably have submenus and we don't - // want to rollup if the clickis in a parent menu of the current submenu - nsCOMPtr menuRollup ( do_QueryInterface(gRollupListener) ); - if ( menuRollup ) { - nsCOMPtr widgetChain; - menuRollup->GetSubmenuWidgetChain ( getter_AddRefs(widgetChain) ); - if ( widgetChain ) { - PRUint32 count = 0; - widgetChain->Count ( &count ); - for ( PRUint32 i = 0; i < count; ++i ) { - nsCOMPtr genericWidget; - widgetChain->GetElementAt ( i, getter_AddRefs(genericWidget) ); - nsCOMPtr widget ( do_QueryInterface(genericWidget) ); - if ( widget ) { - GdkWindow* currWindow = (GdkWindow*) widget->GetNativeData(NS_NATIVE_WINDOW); - if ( IsMouseInWindow(currWindow, inMouseX, inMouseY) ) { - rollup = PR_FALSE; - break; - } - } - } // foreach parent menu widget - } - } // if rollup listener knows about menus - - // if we've determined that we should still rollup, do it. - if ( rollup ) { - gRollupListener->Rollup(); - retVal = PR_TRUE; - } - } - } else { - gRollupWidget = nsnull; - gRollupListener = nsnull; - } - - return retVal; -} // HandlePopup - - ////////////////////////////////////////////////////////////////////// /* virtual */ void nsWidget::OnButtonPressSignal(GdkEventButton * aGdkButtonEvent) @@ -1912,11 +1777,6 @@ nsWidget::OnButtonPressSignal(GdkEventButton * aGdkButtonEvent) nsMouseScrollEvent scrollEvent; PRUint32 eventType = 0; - PRBool isWheel = (aGdkButtonEvent->button == 4 || - aGdkButtonEvent->button == 5); - if (HandlePopup(aGdkButtonEvent->x_root, aGdkButtonEvent->y_root, isWheel)) - return; - // Switch on single, double, triple click. switch (aGdkButtonEvent->type) { @@ -2197,61 +2057,6 @@ nsWidget::InitMouseEvent(GdkEventButton * aGdkButtonEvent, } } -////////////////////////////////////////////////////////////////// -PRBool -nsWidget::DropEvent(GtkWidget * aWidget, - GdkWindow * aEventWindow) -{ - NS_ASSERTION( nsnull != aWidget, "widget is null"); - NS_ASSERTION( nsnull != aEventWindow, "event window is null"); - -#if 0 - static int count = 0; - - if (GTK_IS_LAYOUT(aWidget)) - { - GtkLayout * layout = GTK_LAYOUT(aWidget); - - printf("%4d DropEvent(this=%p,widget=%p,event_win=%p,wid_win=%p,bin_win=%p)\n", - count++, - this, - aWidget, - aEventWindow, - aWidget->window, - layout->bin_window); - } - else - { - printf("%4d DropEvent(this=%p,widget=%p,event_win=%p,wid_win=%p)\n", - count++, - this, - aWidget, - aEventWindow, - aWidget->window); - } -#endif - - - // For gtklayout widgets, we dont want to handle events - // that occur in the sub windows. Check the window member - // of the GdkEvent, if it is not the gtklayout's bin_window, - // drop the event. - if (GTK_IS_LAYOUT(aWidget)) - { - GtkLayout * layout = GTK_LAYOUT(aWidget); - - if (aEventWindow != layout->bin_window) - { -#ifdef DEBUG_pavlov - printf("dropping event!!!!!!!\n"); -#endif - return PR_TRUE; - } - } - return PR_FALSE; -} -////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////// // @@ -2270,11 +2075,6 @@ nsWidget::MotionNotifySignal(GtkWidget * aWidget, NS_ASSERTION( nsnull != widget, "instance pointer is null"); - if (widget->DropEvent(aWidget, aGdkMotionEvent->window)) - { - return PR_TRUE; - } - widget->OnMotionNotifySignal(aGdkMotionEvent); return PR_TRUE; @@ -2293,11 +2093,6 @@ nsWidget::EnterNotifySignal(GtkWidget * aWidget, NS_ASSERTION( nsnull != widget, "instance pointer is null"); - if (widget->DropEvent(aWidget, aGdkCrossingEvent->window)) - { - return PR_TRUE; - } - widget->OnEnterNotifySignal(aGdkCrossingEvent); return PR_TRUE; @@ -2315,11 +2110,6 @@ nsWidget::LeaveNotifySignal(GtkWidget * aWidget, NS_ASSERTION( nsnull != widget, "instance pointer is null"); - if (widget->DropEvent(aWidget, aGdkCrossingEvent->window)) - { - return PR_TRUE; - } - widget->OnLeaveNotifySignal(aGdkCrossingEvent); return PR_TRUE; @@ -2339,11 +2129,6 @@ nsWidget::ButtonPressSignal(GtkWidget * aWidget, NS_ASSERTION( nsnull != widget, "instance pointer is null"); - if (widget->DropEvent(aWidget, aGdkButtonEvent->window)) - { - return PR_TRUE; - } - widget->OnButtonPressSignal(aGdkButtonEvent); return PR_TRUE; @@ -2363,11 +2148,6 @@ nsWidget::ButtonReleaseSignal(GtkWidget * aWidget, NS_ASSERTION( nsnull != widget, "instance pointer is null"); - if (widget->DropEvent(aWidget, aGdkButtonEvent->window)) - { - return PR_TRUE; - } - widget->OnButtonReleaseSignal(aGdkButtonEvent); return PR_TRUE; @@ -2402,11 +2182,6 @@ nsWidget::FocusInSignal(GtkWidget * aWidget, NS_ASSERTION( nsnull != widget, "instance pointer is null"); -// if (widget->DropEvent(aWidget, aGdkFocusEvent->window)) -// { -// return PR_TRUE; -// } - widget->OnFocusInSignal(aGdkFocusEvent); if (GTK_IS_WINDOW(aWidget)) @@ -2429,11 +2204,6 @@ nsWidget::FocusOutSignal(GtkWidget * aWidget, NS_ASSERTION( nsnull != widget, "instance pointer is null"); -// if (widget->DropEvent(aWidget, aGdkFocusEvent->window)) -// { -// return PR_TRUE; -// } - widget->OnFocusOutSignal(aGdkFocusEvent); if (GTK_IS_WINDOW(aWidget)) @@ -2535,95 +2305,6 @@ NS_IMETHODIMP nsWidget::ResetInputState() return NS_OK; } -/********************** class ModalWidgetList ***********************/ -/* This silly little thing is a linked list of widgets that have been - declared modal, in the order of their declaration. We do this only - so clients can stack modal dialogs on top of each other, as they - are wont to do. Yes, glib keeps its own list, but we need our own copy - so we can temporarily disable them all when a popup control window - makes an appearance within a modal dialog. -*/ -static ModalWidgetList *gModalWidgets = nsnull; - -ModalWidgetList::ModalWidgetList(nsWidget *aWidget) { - mWidget = aWidget; - mNext = 0; - mPrev = 0; - mLast = 0; -} - -ModalWidgetList::~ModalWidgetList() { -} - -PRBool ModalWidgetList::Find(nsWidget *aWidget) { - ModalWidgetList *next; - - for (next = gModalWidgets; next && next->mWidget != aWidget; next = next->mNext) - ; - return next ? PR_TRUE : PR_FALSE; -} - -void ModalWidgetList::Append(nsWidget *aWidget) { - - ModalWidgetList *newElement = new ModalWidgetList(aWidget); - - NS_ASSERTION(newElement, "out of memory in modal widget list creation"); - if (!newElement) - return; - - if (gModalWidgets) { - newElement->mPrev = gModalWidgets->mLast; - gModalWidgets->mLast->mNext = newElement; - gModalWidgets->mLast = newElement; - } else { - newElement->mLast = newElement; - gModalWidgets = newElement; - } -} - -void ModalWidgetList::Remove(nsWidget *aWidget) { - NS_ASSERTION(gModalWidgets && gModalWidgets->mLast->mWidget == aWidget, - "removing modal widgets out of order"); - if (gModalWidgets && gModalWidgets->mLast->mWidget == aWidget) - ModalWidgetList::RemoveLast(); -} - -void ModalWidgetList::RemoveLast() { - NS_ASSERTION(gModalWidgets, "removing modal widgets from empty list"); - if (!gModalWidgets) - return; - - ModalWidgetList *deadElement = gModalWidgets->mLast; - if (deadElement->mPrev) { - deadElement->mPrev->mNext = 0; - gModalWidgets->mLast = deadElement->mPrev; - } else - gModalWidgets = 0; - delete deadElement; -} - -void ModalWidgetList::Suppress(PRBool aSuppress) { - - if (!gModalWidgets) - return; - - GtkWindow *window; - ModalWidgetList *widget; - - if (aSuppress) - for (widget = gModalWidgets->mLast; widget; widget = widget->mPrev) { - window = widget->mWidget->GetTopLevelWindow(); - NS_ASSERTION(window, "non-window in modality suppression list"); - gtk_window_set_modal(window, FALSE); - } - else - for (widget = gModalWidgets; widget; widget = widget->mNext) { - window = widget->mWidget->GetTopLevelWindow(); - NS_ASSERTION(window, "non-window in modality suppression list"); - gtk_window_set_modal(window, TRUE); - } -} - /* virtual */ GtkWindow *nsWidget::GetTopLevelWindow(void) { diff --git a/mozilla/widget/src/gtk/nsWidget.h b/mozilla/widget/src/gtk/nsWidget.h index 04a59a3d9bc..58007c750f3 100644 --- a/mozilla/widget/src/gtk/nsWidget.h +++ b/mozilla/widget/src/gtk/nsWidget.h @@ -108,7 +108,6 @@ public: nsIWidget* GetParent(void); virtual void OnDestroy(); - NS_IMETHOD SetModal(PRBool aModal); NS_IMETHOD Show(PRBool state); NS_IMETHOD CaptureRollupEvents(nsIRollupListener *aListener, PRBool aDoCapture, PRBool aConsumeRollupEvent); NS_IMETHOD IsVisible(PRBool &aState); @@ -311,12 +310,6 @@ protected: static gint DestroySignal(GtkWidget * aGtkWidget, nsWidget* aWidget); - static void SuppressModality(PRBool aSuppress); - - // Deal with rollup for popups - PRBool HandlePopup(PRInt32 inMouseX, PRInt32 inMouseY, PRBool isWheel); - PRBool IsMouseInWindow ( GdkWindow* inWindow, PRInt32 inMouseX, PRInt32 inMouseY ) ; - public: virtual void IMECommitEvent(GdkEventKey *aEvent); @@ -371,9 +364,6 @@ protected: gchar * aSignalName, GtkSignalFunc aSignalFunction); - PRBool DropEvent(GtkWidget * aWidget, - GdkWindow * aEventWindow); - void InitMouseEvent(GdkEventButton * aGdkButtonEvent, nsMouseEvent & anEvent, PRUint32 aEventType); @@ -423,6 +413,7 @@ private: // // Keep track of the last widget being "dragged" // +public: static nsWidget *sButtonMotionTarget; static gint sButtonMotionRootX; static gint sButtonMotionRootY; diff --git a/mozilla/widget/src/gtk/nsWindow.cpp b/mozilla/widget/src/gtk/nsWindow.cpp index 805854f8e4f..a51739bb9f8 100644 --- a/mozilla/widget/src/gtk/nsWindow.cpp +++ b/mozilla/widget/src/gtk/nsWindow.cpp @@ -169,6 +169,26 @@ static void printDepth(int depth) { } #endif + +// This function will check if a button event falls inside of a +// window's bounds. +static PRBool +ButtonEventInsideWindow (GdkWindow *window, GdkEventButton *aGdkButtonEvent) +{ + gint x, y; + gint width, height; + gdk_window_get_position(window, &x, &y); + gdk_window_get_size(window, &width, &height); + + // This event is measured from the origin of the window itself, not + // from the origin of the screen. + if (aGdkButtonEvent->x >= x && aGdkButtonEvent->y >= y && + aGdkButtonEvent->x <= width + x && aGdkButtonEvent->y <= height + y) + return TRUE; + + return FALSE; +} + NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsWidget) //------------------------------------------------------------------------- @@ -222,6 +242,9 @@ nsWindow::nsWindow() } #endif // USE_XIM + mLeavePending = PR_FALSE; + mRestoreFocus = PR_FALSE; + // initialize globals if (!gGlobalsInitialized) { gGlobalsInitialized = PR_TRUE; @@ -858,8 +881,6 @@ NS_IMETHODIMP nsWindow::CaptureRollupEvents(nsIRollupListener * aListener, sIsGrabbing = PR_TRUE; sGrabWindow = this; - - SuppressModality(PR_TRUE); } gRollupConsumeRollupEvent = PR_TRUE; @@ -876,7 +897,6 @@ NS_IMETHODIMP nsWindow::CaptureRollupEvents(nsIRollupListener * aListener, gRollupListener = nsnull; gRollupWidget = nsnull; - SuppressModality(PR_FALSE); } return NS_OK; @@ -1177,6 +1197,48 @@ GdkCursor *nsWindow::GtkCreateCursor(nsCursor aCursorType) return gdkcursor; } +NS_IMETHODIMP +nsWindow::Enable(PRBool aState) +{ + GtkWidget *top_mozarea = GetOwningWidget(); + GtkWindow *top_window = GTK_WINDOW(gtk_widget_get_toplevel(top_mozarea)); + + if (aState) { + gtk_widget_set_sensitive(top_mozarea, TRUE); + // See if now that we're sensitive again check to see if we need + // to reset ourselves the default focus widget for the toplevel + // window. We should only do that if there is no focus widget + // since someone else might have taken the focus while we were + // disabled, and stealing focus is rude! + if (mRestoreFocus && !top_window->focus_widget) { + gtk_window_set_focus(top_window, top_mozarea); + } + mRestoreFocus = PR_FALSE; + } + else { + // Setting the window insensitive below will remove the window + // focus widget so we will have to restore it when we are + // reenabled. Of course, because of embedding, we might not + // actually _be_ the widget with focus, so keep that in mind. + if (top_window->focus_widget == top_mozarea) { + mRestoreFocus = PR_TRUE; + } + gtk_widget_set_sensitive(top_mozarea, FALSE); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsWindow::IsEnabled(PRBool *aState) +{ + NS_ENSURE_ARG_POINTER(aState); + + *aState = !mMozArea || GTK_WIDGET_IS_SENSITIVE(mMozArea); + + return NS_OK; +} + NS_IMETHODIMP nsWindow::SetFocus(PRBool aRaise) { @@ -1401,7 +1463,7 @@ void nsWindow::HandleMozAreaFocusIn(void) // otherwise, dispatch our focus events #ifdef DEBUG_FOCUS printf("nsWindow::HandleMozAreaFocusIn %p\n", NS_STATIC_CAST(void *, this)); -#endif /* DEBUG_FOCUS */ +#endif // we only set the gJustGotActivate signal if we're the toplevel // window. embedding handles activate semantics for us. if (mIsToplevel) @@ -1422,7 +1484,7 @@ void nsWindow::HandleMozAreaFocusOut(void) // otherwise handle our focus out here. #ifdef DEBUG_FOCUS printf("nsWindow::HandleMozAreaFocusOut %p\n", NS_STATIC_CAST(void *, this)); -#endif /* DEBUG_FOCUS */ +#endif // if there's a window with focus, send a focus out event for that // window. if (sFocusWindow) @@ -1464,6 +1526,107 @@ void nsWindow::HandleMozAreaFocusOut(void) } } +////////////////////////////////////////////////////////////////////// +/* virtual */ void +nsWindow::OnMotionNotifySignal(GdkEventMotion *aGdkMotionEvent) +{ + // If there's a rollup widget and this window is not a popup window, + // drop the event. + if (gRollupWidget && GetOwningWindowType() != eWindowType_popup) { + return; + } + + XEvent xevent; + GdkEvent gdk_event; + PRBool synthEvent = PR_FALSE; + while (XCheckWindowEvent(GDK_DISPLAY(), + GDK_WINDOW_XWINDOW(mSuperWin->bin_window), + ButtonMotionMask, &xevent)) { + synthEvent = PR_TRUE; + } + if (synthEvent) { + gdk_event.type = GDK_MOTION_NOTIFY; + gdk_event.motion.window = aGdkMotionEvent->window; + gdk_event.motion.send_event = aGdkMotionEvent->send_event; + gdk_event.motion.time = xevent.xmotion.time; + gdk_event.motion.x = xevent.xmotion.x; + gdk_event.motion.y = xevent.xmotion.y; + gdk_event.motion.pressure = aGdkMotionEvent->pressure; + gdk_event.motion.xtilt = aGdkMotionEvent->xtilt; + gdk_event.motion.ytilt = aGdkMotionEvent->ytilt; + gdk_event.motion.state = aGdkMotionEvent->state; + gdk_event.motion.is_hint = xevent.xmotion.is_hint; + gdk_event.motion.source = aGdkMotionEvent->source; + gdk_event.motion.deviceid = aGdkMotionEvent->deviceid; + gdk_event.motion.x_root = xevent.xmotion.x_root; + gdk_event.motion.y_root = xevent.xmotion.y_root; + nsWidget::OnMotionNotifySignal(&gdk_event.motion); + } + else { + nsWidget::OnMotionNotifySignal(aGdkMotionEvent); + } +} + +////////////////////////////////////////////////////////////////////// +/* virtual */ void +nsWindow::OnEnterNotifySignal(GdkEventCrossing *aGdkCrossingEvent) +{ + if (GTK_WIDGET_SENSITIVE(GetOwningWidget())) { + nsWidget::OnEnterNotifySignal(aGdkCrossingEvent); + if (mMozArea) + GTK_PRIVATE_SET_FLAG(mMozArea, GTK_LEAVE_PENDING); + mLeavePending = PR_TRUE; + } +} + +////////////////////////////////////////////////////////////////////// +/* virtual */ void +nsWindow::OnLeaveNotifySignal(GdkEventCrossing *aGdkCrossingEvent) +{ + if (mLeavePending) { + if (mMozArea) + GTK_PRIVATE_UNSET_FLAG(mMozArea, GTK_LEAVE_PENDING); + mLeavePending = PR_FALSE; + nsWidget::OnLeaveNotifySignal(aGdkCrossingEvent); + } +} + +////////////////////////////////////////////////////////////////////// +/* virtual */ void +nsWindow::OnButtonPressSignal(GdkEventButton *aGdkButtonEvent) +{ + // This widget has gotten a button press event. If there's a rollup + // widget and we're not inside of a popup window we should pop up + // the rollup widget. Also, if the event is our event but it + // happens outside of the bounds of the window we should roll up as + // well. + if (gRollupWidget && ((GetOwningWindowType() != eWindowType_popup) || + (mSuperWin->bin_window == aGdkButtonEvent->window && + !ButtonEventInsideWindow(aGdkButtonEvent->window, + aGdkButtonEvent)))) { + gRollupListener->Rollup(); + gRollupWidget = nsnull; + gRollupListener = nsnull; + return; + } + + nsWidget::OnButtonPressSignal(aGdkButtonEvent); +} + +////////////////////////////////////////////////////////////////////// +/* virtual */ void +nsWindow::OnButtonReleaseSignal(GdkEventButton *aGdkButtonEvent) +{ + // we only dispatch this event if there's a button motion target or + // if it's happening inside of a popup window while there is a + // rollup widget + if (!sButtonMotionTarget && + (gRollupWidget && GetOwningWindowType() != eWindowType_popup)) { + return; + } + nsWidget::OnButtonReleaseSignal(aGdkButtonEvent); +} + ////////////////////////////////////////////////////////////////////// /* virtual */ void nsWindow::OnFocusInSignal(GdkEventFocus * aGdkFocusEvent) @@ -1549,38 +1712,8 @@ nsWindow::HandleGDKEvent(GdkEvent *event) switch (event->any.type) { case GDK_MOTION_NOTIFY: - { - XEvent xevent; - GdkEvent gdk_event; - PRBool synthEvent = PR_FALSE; - while (XCheckWindowEvent(GDK_DISPLAY(), - GDK_WINDOW_XWINDOW(mSuperWin->bin_window), - ButtonMotionMask, &xevent)) { - synthEvent = PR_TRUE; - } - if (synthEvent) { - gdk_event.type = GDK_MOTION_NOTIFY; - gdk_event.motion.window = event->motion.window; - gdk_event.motion.send_event = event->motion.send_event; - gdk_event.motion.time = xevent.xmotion.time; - gdk_event.motion.x = xevent.xmotion.x; - gdk_event.motion.y = xevent.xmotion.y; - gdk_event.motion.pressure = event->motion.pressure; - gdk_event.motion.xtilt = event->motion.xtilt; - gdk_event.motion.ytilt = event->motion.ytilt; - gdk_event.motion.state = event->motion.state; - gdk_event.motion.is_hint = xevent.xmotion.is_hint; - gdk_event.motion.source = event->motion.source; - gdk_event.motion.deviceid = event->motion.deviceid; - gdk_event.motion.x_root = xevent.xmotion.x_root; - gdk_event.motion.y_root = xevent.xmotion.y_root; - OnMotionNotifySignal (&gdk_event.motion); - } - else { - OnMotionNotifySignal (&event->motion); - } - } - break; + OnMotionNotifySignal (&event->motion); + break; case GDK_BUTTON_PRESS: case GDK_2BUTTON_PRESS: case GDK_3BUTTON_PRESS: @@ -1589,12 +1722,13 @@ nsWindow::HandleGDKEvent(GdkEvent *event) case GDK_BUTTON_RELEASE: OnButtonReleaseSignal (&event->button); break; + case GDK_ENTER_NOTIFY: + OnEnterNotifySignal (&event->crossing); + break; case GDK_LEAVE_NOTIFY: OnLeaveNotifySignal (&event->crossing); break; - case GDK_ENTER_NOTIFY: - OnEnterNotifySignal ( &event->crossing ); - break; + default: break; } @@ -1611,6 +1745,13 @@ nsWindow::OnDestroySignal(GtkWidget* aGtkWidget) gint handle_delete_event(GtkWidget *w, GdkEventAny *e, nsWindow *win) { + + PRBool isEnabled; + // If this window is disabled, don't dispatch the delete event + win->IsEnabled(&isEnabled); + if (!isEnabled) + return TRUE; + NS_ADDREF(win); // dispatch an "onclose" event. to delete immediately, call win->Destroy() @@ -2754,6 +2895,21 @@ nsWindow::GetOwningWidget() return (GtkWidget *)mMozAreaClosestParent; } +nsWindowType +nsWindow::GetOwningWindowType(void) +{ + GtkWidget *widget = GetOwningWidget(); + + nsWindow *owningWindow; + owningWindow = (nsWindow *)gtk_object_get_data(GTK_OBJECT(widget), + "nsWindow"); + + nsWindowType retval; + owningWindow->GetWindowType(retval); + + return retval; +} + PRBool nsWindow::GrabInProgress(void) { @@ -2765,9 +2921,7 @@ nsWindow * nsWindow::GetGrabWindow(void) { if (nsWindow::sIsGrabbing) - { return sGrabWindow; - } else return nsnull; } diff --git a/mozilla/widget/src/gtk/nsWindow.h b/mozilla/widget/src/gtk/nsWindow.h index e9e899e6e18..098e881bba0 100644 --- a/mozilla/widget/src/gtk/nsWindow.h +++ b/mozilla/widget/src/gtk/nsWindow.h @@ -108,6 +108,8 @@ public: NS_IMETHOD InvalidateRegion(const nsIRegion* aRegion, PRBool aIsSynchronous); NS_IMETHOD SetBackgroundColor(const nscolor &aColor); NS_IMETHOD SetCursor(nsCursor aCursor); + NS_IMETHOD Enable (PRBool aState); + NS_IMETHOD IsEnabled (PRBool *aState); NS_IMETHOD SetFocus(PRBool aRaise); NS_IMETHOD GetAttention(void); NS_IMETHOD Destroy(); @@ -126,6 +128,11 @@ public: // get the toplevel window for this widget virtual GtkWindow *GetTopLevelWindow(void); NS_IMETHOD Update(void); + virtual void OnMotionNotifySignal(GdkEventMotion *aGdkMotionEvent); + virtual void OnEnterNotifySignal(GdkEventCrossing *aGdkCrossingEvent); + virtual void OnLeaveNotifySignal(GdkEventCrossing *aGdkCrossingEvent); + virtual void OnButtonPressSignal(GdkEventButton *aGdkButtonEvent); + virtual void OnButtonReleaseSignal(GdkEventButton *aGdkButtonEvent); virtual void OnFocusInSignal(GdkEventFocus * aGdkFocusEvent); virtual void OnFocusOutSignal(GdkEventFocus * aGdkFocusEvent); virtual void InstallFocusInSignal(GtkWidget * aWidget); @@ -146,6 +153,10 @@ public: // Return the GtkMozArea that is the nearest parent of this widget virtual GtkWidget *GetOwningWidget(); + // Return the type of the window that is the toplevel mozilla window + // for this (possibly) inner window + nsWindowType GetOwningWindowType(); + // Return the Gdk window used for rendering virtual GdkWindow * GetRenderWindow(GtkObject * aGtkWidget); @@ -366,6 +377,8 @@ private: GtkWindow *mTransientParent; + PRBool mLeavePending; + PRBool mRestoreFocus; }; //