1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "nsCOMPtr.h"
8 #include "nsTitleBarFrame.h"
9 #include "nsIContent.h"
10 #include "mozilla/dom/Document.h"
11 #include "nsGkAtoms.h"
12 #include "nsIWidget.h"
13 #include "nsMenuPopupFrame.h"
14 #include "nsPresContext.h"
15 #include "nsIDocShell.h"
16 #include "nsPIDOMWindow.h"
17 #include "nsDisplayList.h"
18 #include "nsContentUtils.h"
19 #include "mozilla/MouseEvents.h"
20 #include "mozilla/PresShell.h"
21 #include "mozilla/dom/MouseEventBinding.h"
22
23 using namespace mozilla;
24
25 //
26 // NS_NewTitleBarFrame
27 //
28 // Creates a new TitleBar frame and returns it
29 //
NS_NewTitleBarFrame(PresShell * aPresShell,ComputedStyle * aStyle)30 nsIFrame* NS_NewTitleBarFrame(PresShell* aPresShell, ComputedStyle* aStyle) {
31 return new (aPresShell) nsTitleBarFrame(aStyle, aPresShell->GetPresContext());
32 }
33
NS_IMPL_FRAMEARENA_HELPERS(nsTitleBarFrame)34 NS_IMPL_FRAMEARENA_HELPERS(nsTitleBarFrame)
35
36 nsTitleBarFrame::nsTitleBarFrame(ComputedStyle* aStyle,
37 nsPresContext* aPresContext, ClassID aID)
38 : nsBoxFrame(aStyle, aPresContext, aID, false) {
39 mTrackingMouseMove = false;
40 }
41
BuildDisplayListForChildren(nsDisplayListBuilder * aBuilder,const nsDisplayListSet & aLists)42 void nsTitleBarFrame::BuildDisplayListForChildren(
43 nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists) {
44 // override, since we don't want children to get events
45 if (aBuilder->IsForEventDelivery()) {
46 if (!mContent->AsElement()->AttrValueIs(kNameSpaceID_None,
47 nsGkAtoms::allowevents,
48 nsGkAtoms::_true, eCaseMatters))
49 return;
50 }
51 nsBoxFrame::BuildDisplayListForChildren(aBuilder, aLists);
52 }
53
HandleEvent(nsPresContext * aPresContext,WidgetGUIEvent * aEvent,nsEventStatus * aEventStatus)54 nsresult nsTitleBarFrame::HandleEvent(nsPresContext* aPresContext,
55 WidgetGUIEvent* aEvent,
56 nsEventStatus* aEventStatus) {
57 NS_ENSURE_ARG_POINTER(aEventStatus);
58 if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
59 return NS_OK;
60 }
61
62 bool doDefault = true;
63
64 switch (aEvent->mMessage) {
65 case eMouseDown: {
66 if (aEvent->AsMouseEvent()->mButton == MouseButton::ePrimary) {
67 // titlebar has no effect in non-chrome shells
68 if (aPresContext->IsChrome()) {
69 // we're tracking.
70 mTrackingMouseMove = true;
71
72 // start capture.
73 PresShell::SetCapturingContent(GetContent(),
74 CaptureFlags::IgnoreAllowedState);
75
76 // remember current mouse coordinates.
77 mLastPoint = aEvent->mRefPoint;
78 }
79
80 *aEventStatus = nsEventStatus_eConsumeNoDefault;
81 doDefault = false;
82 }
83 } break;
84
85 case eMouseUp: {
86 if (mTrackingMouseMove &&
87 aEvent->AsMouseEvent()->mButton == MouseButton::ePrimary) {
88 // we're done tracking.
89 mTrackingMouseMove = false;
90
91 // end capture
92 PresShell::ReleaseCapturingContent();
93
94 *aEventStatus = nsEventStatus_eConsumeNoDefault;
95 doDefault = false;
96 }
97 } break;
98
99 case eMouseMove: {
100 if (mTrackingMouseMove) {
101 LayoutDeviceIntPoint nsMoveBy = aEvent->mRefPoint - mLastPoint;
102
103 nsIFrame* parent = GetParent();
104 while (parent) {
105 nsMenuPopupFrame* popupFrame = do_QueryFrame(parent);
106 if (popupFrame) break;
107 parent = parent->GetParent();
108 }
109
110 // if the titlebar is in a popup, move the popup frame, otherwise
111 // move the widget associated with the window
112 if (parent) {
113 nsMenuPopupFrame* menuPopupFrame =
114 static_cast<nsMenuPopupFrame*>(parent);
115 nsCOMPtr<nsIWidget> widget = menuPopupFrame->GetWidget();
116 LayoutDeviceIntRect bounds = widget->GetScreenBounds();
117
118 CSSPoint cssPos = (bounds.TopLeft() + nsMoveBy) /
119 aPresContext->CSSToDevPixelScale();
120 menuPopupFrame->MoveTo(RoundedToInt(cssPos), false);
121 } else {
122 mozilla::PresShell* presShell = aPresContext->PresShell();
123 nsPIDOMWindowOuter* window = presShell->GetDocument()->GetWindow();
124 if (window) {
125 window->MoveBy(nsMoveBy.x, nsMoveBy.y);
126 }
127 }
128
129 *aEventStatus = nsEventStatus_eConsumeNoDefault;
130
131 doDefault = false;
132 }
133 } break;
134
135 case eMouseClick: {
136 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
137 if (mouseEvent->IsLeftClickEvent()) {
138 MouseClicked(mouseEvent);
139 }
140 break;
141 }
142
143 default:
144 break;
145 }
146
147 if (doDefault)
148 return nsBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
149 else
150 return NS_OK;
151 }
152
MouseClicked(WidgetMouseEvent * aEvent)153 void nsTitleBarFrame::MouseClicked(WidgetMouseEvent* aEvent) {
154 // Execute the oncommand event handler.
155 nsCOMPtr<nsIContent> content = mContent;
156 nsContentUtils::DispatchXULCommand(content, false, nullptr, nullptr,
157 aEvent->IsControl(), aEvent->IsAlt(),
158 aEvent->IsShift(), aEvent->IsMeta(),
159 aEvent->mInputSource, aEvent->mButton);
160 }
161