Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 : #include "HeadlessWidget.h"
6 : #include "Layers.h"
7 : #include "BasicLayers.h"
8 : #include "BasicEvents.h"
9 :
10 : using namespace mozilla::layers;
11 :
12 : /*static*/ already_AddRefed<nsIWidget>
13 0 : nsIWidget::CreateHeadlessWidget()
14 : {
15 0 : nsCOMPtr<nsIWidget> widget = new mozilla::widget::HeadlessWidget();
16 0 : return widget.forget();
17 : }
18 :
19 : namespace mozilla {
20 : namespace widget {
21 :
22 0 : NS_IMPL_ISUPPORTS_INHERITED0(HeadlessWidget, nsBaseWidget)
23 :
24 : nsresult
25 0 : HeadlessWidget::Create(nsIWidget* aParent,
26 : nsNativeWidget aNativeParent,
27 : const LayoutDeviceIntRect& aRect,
28 : nsWidgetInitData* aInitData)
29 : {
30 0 : MOZ_ASSERT(!aNativeParent, "No native parents for headless widgets.");
31 :
32 0 : BaseCreate(nullptr, aInitData);
33 0 : mBounds = aRect;
34 0 : mRestoreBounds = aRect;
35 0 : mVisible = true;
36 0 : mEnabled = true;
37 0 : return NS_OK;
38 : }
39 :
40 : already_AddRefed<nsIWidget>
41 0 : HeadlessWidget::CreateChild(const LayoutDeviceIntRect& aRect,
42 : nsWidgetInitData* aInitData,
43 : bool aForceUseIWidgetParent)
44 : {
45 0 : nsCOMPtr<nsIWidget> widget = nsIWidget::CreateHeadlessWidget();
46 0 : if (!widget) {
47 0 : return nullptr;
48 : }
49 0 : if (NS_FAILED(widget->Create(nullptr, nullptr, aRect, aInitData))) {
50 0 : return nullptr;
51 : }
52 0 : return widget.forget();
53 : }
54 :
55 : void
56 0 : HeadlessWidget::SendSetZLevelEvent()
57 : {
58 0 : nsWindowZ placement = nsWindowZTop;
59 0 : nsCOMPtr<nsIWidget> actualBelow;
60 0 : if (mWidgetListener)
61 0 : mWidgetListener->ZLevelChanged(true, &placement, nullptr, getter_AddRefs(actualBelow));
62 0 : }
63 :
64 : void
65 0 : HeadlessWidget::Show(bool aState)
66 : {
67 0 : mVisible = aState;
68 0 : if (aState) {
69 0 : SendSetZLevelEvent();
70 : }
71 0 : }
72 :
73 : bool
74 0 : HeadlessWidget::IsVisible() const
75 : {
76 0 : return mVisible;
77 : }
78 :
79 : nsresult
80 0 : HeadlessWidget::SetFocus(bool aRaise)
81 : {
82 0 : if (aRaise && mVisible) {
83 0 : SendSetZLevelEvent();
84 : }
85 0 : return NS_OK;
86 : }
87 :
88 : void
89 0 : HeadlessWidget::Enable(bool aState)
90 : {
91 0 : mEnabled = aState;
92 0 : }
93 :
94 : bool
95 0 : HeadlessWidget::IsEnabled() const
96 : {
97 0 : return mEnabled;
98 : }
99 :
100 : void
101 0 : HeadlessWidget::Move(double aX, double aY)
102 : {
103 0 : double scale = BoundsUseDesktopPixels() ? GetDesktopToDeviceScale().scale : 1.0;
104 0 : int32_t x = NSToIntRound(aX * scale);
105 0 : int32_t y = NSToIntRound(aY * scale);
106 :
107 0 : if (mWindowType == eWindowType_toplevel ||
108 0 : mWindowType == eWindowType_dialog) {
109 0 : SetSizeMode(nsSizeMode_Normal);
110 : }
111 :
112 : // Since a popup window's x/y coordinates are in relation to
113 : // the parent, the parent might have moved so we always move a
114 : // popup window.
115 0 : if (x == mBounds.x && y == mBounds.y &&
116 0 : mWindowType != eWindowType_popup) {
117 0 : return;
118 : }
119 :
120 0 : mBounds.x = x;
121 0 : mBounds.y = y;
122 0 : NotifyRollupGeometryChange();
123 : }
124 :
125 : LayoutDeviceIntPoint
126 0 : HeadlessWidget::WidgetToScreenOffset()
127 : {
128 0 : return LayoutDeviceIntPoint(mBounds.x, mBounds.y);
129 : }
130 :
131 : LayerManager*
132 0 : HeadlessWidget::GetLayerManager(PLayerTransactionChild* aShadowManager,
133 : LayersBackend aBackendHint,
134 : LayerManagerPersistence aPersistence)
135 : {
136 0 : if (!mLayerManager) {
137 0 : mLayerManager = new BasicLayerManager(this);
138 : }
139 :
140 0 : return mLayerManager;
141 : }
142 :
143 : void
144 0 : HeadlessWidget::Resize(double aWidth,
145 : double aHeight,
146 : bool aRepaint)
147 : {
148 0 : mBounds.SizeTo(LayoutDeviceIntSize(NSToIntRound(aWidth),
149 0 : NSToIntRound(aHeight)));
150 0 : if (mWidgetListener) {
151 0 : mWidgetListener->WindowResized(this, mBounds.width, mBounds.height);
152 : }
153 0 : if (mAttachedWidgetListener) {
154 0 : mAttachedWidgetListener->WindowResized(this, mBounds.width, mBounds.height);
155 : }
156 0 : }
157 :
158 : void
159 0 : HeadlessWidget::Resize(double aX,
160 : double aY,
161 : double aWidth,
162 : double aHeight,
163 : bool aRepaint)
164 : {
165 0 : if (mBounds.x != aX || mBounds.y != aY) {
166 0 : NotifyWindowMoved(aX, aY);
167 : }
168 0 : return Resize(aWidth, aHeight, aRepaint);
169 : }
170 :
171 : void
172 0 : HeadlessWidget::SetSizeMode(nsSizeMode aMode)
173 : {
174 0 : if (aMode == mSizeMode) {
175 0 : return;
176 : }
177 0 : if (mSizeMode == nsSizeMode_Normal) {
178 : // Store the last normal size bounds so it can be restored when entering
179 : // normal mode again.
180 0 : mRestoreBounds = mBounds;
181 : }
182 :
183 0 : nsBaseWidget::SetSizeMode(aMode);
184 :
185 : // Normally in real widget backends a window event would be triggered that
186 : // would cause the window manager to handle resizing the window. In headless
187 : // the window must manually be resized.
188 0 : switch(aMode) {
189 : case nsSizeMode_Normal: {
190 0 : Resize(mRestoreBounds.x, mRestoreBounds.y, mRestoreBounds.width, mRestoreBounds.height, false);
191 0 : break;
192 : }
193 : case nsSizeMode_Minimized:
194 0 : break;
195 : case nsSizeMode_Maximized: {
196 0 : nsCOMPtr<nsIScreen> screen = GetWidgetScreen();
197 0 : if (screen) {
198 : int32_t left, top, width, height;
199 0 : if (NS_SUCCEEDED(screen->GetRectDisplayPix(&left, &top, &width, &height))) {
200 0 : Resize(0, 0, width, height, true);
201 : }
202 : }
203 0 : break;
204 : }
205 : case nsSizeMode_Fullscreen:
206 : // This will take care of resizing the window.
207 0 : nsBaseWidget::InfallibleMakeFullScreen(true);
208 0 : break;
209 : default:
210 0 : break;
211 : }
212 : }
213 :
214 : nsresult
215 0 : HeadlessWidget::MakeFullScreen(bool aFullScreen, nsIScreen* aTargetScreen)
216 : {
217 : // Directly update the size mode here so a later call SetSizeMode does
218 : // nothing.
219 0 : if (aFullScreen) {
220 0 : if (mSizeMode != nsSizeMode_Fullscreen) {
221 0 : mLastSizeMode = mSizeMode;
222 : }
223 0 : mSizeMode = nsSizeMode_Fullscreen;
224 : } else {
225 0 : mSizeMode = mLastSizeMode;
226 : }
227 :
228 0 : nsBaseWidget::InfallibleMakeFullScreen(aFullScreen, aTargetScreen);
229 :
230 0 : if (mWidgetListener) {
231 0 : mWidgetListener->SizeModeChanged(mSizeMode);
232 0 : mWidgetListener->FullscreenChanged(aFullScreen);
233 : }
234 :
235 0 : return NS_OK;
236 : }
237 :
238 : nsresult
239 0 : HeadlessWidget::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus)
240 : {
241 : #ifdef DEBUG
242 0 : debug_DumpEvent(stdout, aEvent->mWidget, aEvent, "HeadlessWidget", 0);
243 : #endif
244 :
245 0 : aStatus = nsEventStatus_eIgnore;
246 :
247 0 : if (mAttachedWidgetListener) {
248 0 : aStatus = mAttachedWidgetListener->HandleEvent(aEvent, mUseAttachedEvents);
249 0 : } else if (mWidgetListener) {
250 0 : aStatus = mWidgetListener->HandleEvent(aEvent, mUseAttachedEvents);
251 : }
252 :
253 0 : return NS_OK;
254 : }
255 :
256 : } // namespace widget
257 : } // namespace mozilla
|