diff options
Diffstat (limited to 'layout/xul/nsTitleBarFrame.cpp')
-rw-r--r-- | layout/xul/nsTitleBarFrame.cpp | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/layout/xul/nsTitleBarFrame.cpp b/layout/xul/nsTitleBarFrame.cpp new file mode 100644 index 0000000000..d671741f56 --- /dev/null +++ b/layout/xul/nsTitleBarFrame.cpp @@ -0,0 +1,166 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsCOMPtr.h" +#include "nsTitleBarFrame.h" +#include "nsIContent.h" +#include "mozilla/dom/Document.h" +#include "nsGkAtoms.h" +#include "nsIWidget.h" +#include "nsMenuPopupFrame.h" +#include "nsPresContext.h" +#include "nsIDocShell.h" +#include "nsPIDOMWindow.h" +#include "nsDisplayList.h" +#include "nsContentUtils.h" +#include "mozilla/MouseEvents.h" +#include "mozilla/PresShell.h" +#include "mozilla/dom/MouseEventBinding.h" + +using namespace mozilla; + +// +// NS_NewTitleBarFrame +// +// Creates a new TitleBar frame and returns it +// +nsIFrame* NS_NewTitleBarFrame(PresShell* aPresShell, ComputedStyle* aStyle) { + return new (aPresShell) nsTitleBarFrame(aStyle, aPresShell->GetPresContext()); +} + +NS_IMPL_FRAMEARENA_HELPERS(nsTitleBarFrame) + +nsTitleBarFrame::nsTitleBarFrame(ComputedStyle* aStyle, + nsPresContext* aPresContext, ClassID aID) + : nsBoxFrame(aStyle, aPresContext, aID, false) { + mTrackingMouseMove = false; +} + +void nsTitleBarFrame::BuildDisplayListForChildren( + nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists) { + // override, since we don't want children to get events + if (aBuilder->IsForEventDelivery()) { + if (!mContent->AsElement()->AttrValueIs(kNameSpaceID_None, + nsGkAtoms::allowevents, + nsGkAtoms::_true, eCaseMatters)) + return; + } + nsBoxFrame::BuildDisplayListForChildren(aBuilder, aLists); +} + +nsresult nsTitleBarFrame::HandleEvent(nsPresContext* aPresContext, + WidgetGUIEvent* aEvent, + nsEventStatus* aEventStatus) { + NS_ENSURE_ARG_POINTER(aEventStatus); + if (nsEventStatus_eConsumeNoDefault == *aEventStatus) { + return NS_OK; + } + + bool doDefault = true; + + switch (aEvent->mMessage) { + case eMouseDown: { + if (aEvent->AsMouseEvent()->mButton == MouseButton::ePrimary) { + // titlebar has no effect in non-chrome shells + if (aPresContext->IsChrome()) { + // we're tracking. + mTrackingMouseMove = true; + + // start capture. + PresShell::SetCapturingContent(GetContent(), + CaptureFlags::IgnoreAllowedState); + + // remember current mouse coordinates. + mLastPoint = aEvent->mRefPoint; + } + + *aEventStatus = nsEventStatus_eConsumeNoDefault; + doDefault = false; + } + } break; + + case eMouseUp: { + if (mTrackingMouseMove && + aEvent->AsMouseEvent()->mButton == MouseButton::ePrimary) { + // we're done tracking. + mTrackingMouseMove = false; + + // end capture + PresShell::ReleaseCapturingContent(); + + *aEventStatus = nsEventStatus_eConsumeNoDefault; + doDefault = false; + } + } break; + + case eMouseMove: { + if (mTrackingMouseMove) { + LayoutDeviceIntPoint nsMoveBy = aEvent->mRefPoint - mLastPoint; + + nsIFrame* parent = GetParent(); + while (parent) { + nsMenuPopupFrame* popupFrame = do_QueryFrame(parent); + if (popupFrame) break; + parent = parent->GetParent(); + } + + // if the titlebar is in a popup, move the popup frame, otherwise + // move the widget associated with the window + if (parent) { + nsMenuPopupFrame* menuPopupFrame = + static_cast<nsMenuPopupFrame*>(parent); + nsCOMPtr<nsIWidget> widget = menuPopupFrame->GetWidget(); + LayoutDeviceIntRect bounds = widget->GetScreenBounds(); + + CSSPoint cssPos = (bounds.TopLeft() + nsMoveBy) / + aPresContext->CSSToDevPixelScale(); + menuPopupFrame->MoveTo(RoundedToInt(cssPos), false); + } else { + mozilla::PresShell* presShell = aPresContext->PresShell(); + nsPIDOMWindowOuter* window = presShell->GetDocument()->GetWindow(); + if (window) { + window->MoveBy(nsMoveBy.x, nsMoveBy.y); + } + } + + *aEventStatus = nsEventStatus_eConsumeNoDefault; + + doDefault = false; + } + } break; + + case eMouseClick: { + WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); + if (mouseEvent->IsLeftClickEvent() +#ifdef XP_MACOSX + // On Mac, ctrl-click will send a context menu event from the widget, + // so we don't want to dispatch widget command if it is redispatched + // from the mouse event with ctrl key is pressed. + && !mouseEvent->IsControl() +#endif + ) { + MouseClicked(mouseEvent); + } + break; + } + + default: + break; + } + + if (doDefault) + return nsBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus); + else + return NS_OK; +} + +void nsTitleBarFrame::MouseClicked(WidgetMouseEvent* aEvent) { + // Execute the oncommand event handler. + nsCOMPtr<nsIContent> content = mContent; + nsContentUtils::DispatchXULCommand( + content, false, nullptr, nullptr, aEvent->IsControl(), aEvent->IsAlt(), + aEvent->IsShift(), aEvent->IsMeta(), aEvent->mInputSource); +} |