widget/xpwidgets/nsBaseWidget.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "mozilla/ArrayUtils.h"
michael@0 7
michael@0 8 #include "mozilla/layers/CompositorChild.h"
michael@0 9 #include "mozilla/layers/CompositorParent.h"
michael@0 10 #include "mozilla/layers/ImageBridgeChild.h"
michael@0 11 #include "nsBaseWidget.h"
michael@0 12 #include "nsDeviceContext.h"
michael@0 13 #include "nsCOMPtr.h"
michael@0 14 #include "nsGfxCIID.h"
michael@0 15 #include "nsWidgetsCID.h"
michael@0 16 #include "nsServiceManagerUtils.h"
michael@0 17 #include "nsIScreenManager.h"
michael@0 18 #include "nsAppDirectoryServiceDefs.h"
michael@0 19 #include "nsISimpleEnumerator.h"
michael@0 20 #include "nsIContent.h"
michael@0 21 #include "nsIDocument.h"
michael@0 22 #include "nsIPresShell.h"
michael@0 23 #include "nsIServiceManager.h"
michael@0 24 #include "mozilla/Preferences.h"
michael@0 25 #include "BasicLayers.h"
michael@0 26 #include "ClientLayerManager.h"
michael@0 27 #include "mozilla/layers/Compositor.h"
michael@0 28 #include "nsIXULRuntime.h"
michael@0 29 #include "nsIXULWindow.h"
michael@0 30 #include "nsIBaseWindow.h"
michael@0 31 #include "nsXULPopupManager.h"
michael@0 32 #include "nsIWidgetListener.h"
michael@0 33 #include "nsIGfxInfo.h"
michael@0 34 #include "npapi.h"
michael@0 35 #include "base/thread.h"
michael@0 36 #include "prdtoa.h"
michael@0 37 #include "prenv.h"
michael@0 38 #include "mozilla/Attributes.h"
michael@0 39 #include "mozilla/unused.h"
michael@0 40 #include "nsContentUtils.h"
michael@0 41 #include "gfxPrefs.h"
michael@0 42 #include "mozilla/gfx/2D.h"
michael@0 43 #include "mozilla/MouseEvents.h"
michael@0 44 #include "GLConsts.h"
michael@0 45 #include "LayerScope.h"
michael@0 46 #include "mozilla/unused.h"
michael@0 47
michael@0 48 #ifdef ACCESSIBILITY
michael@0 49 #include "nsAccessibilityService.h"
michael@0 50 #endif
michael@0 51
michael@0 52 #ifdef DEBUG
michael@0 53 #include "nsIObserver.h"
michael@0 54
michael@0 55 static void debug_RegisterPrefCallbacks();
michael@0 56
michael@0 57 #endif
michael@0 58
michael@0 59 #ifdef NOISY_WIDGET_LEAKS
michael@0 60 static int32_t gNumWidgets;
michael@0 61 #endif
michael@0 62
michael@0 63 #ifdef XP_MACOSX
michael@0 64 #include "nsCocoaFeatures.h"
michael@0 65 #endif
michael@0 66
michael@0 67 nsIRollupListener* nsBaseWidget::gRollupListener = nullptr;
michael@0 68
michael@0 69 using namespace mozilla::layers;
michael@0 70 using namespace mozilla::ipc;
michael@0 71 using namespace mozilla;
michael@0 72 using base::Thread;
michael@0 73
michael@0 74 nsIContent* nsBaseWidget::mLastRollup = nullptr;
michael@0 75 // Global user preference for disabling native theme. Used
michael@0 76 // in NativeWindowTheme.
michael@0 77 bool gDisableNativeTheme = false;
michael@0 78
michael@0 79 // Async pump timer during injected long touch taps
michael@0 80 #define TOUCH_INJECT_PUMP_TIMER_MSEC 50
michael@0 81 #define TOUCH_INJECT_LONG_TAP_DEFAULT_MSEC 1500
michael@0 82 int32_t nsIWidget::sPointerIdCounter = 0;
michael@0 83
michael@0 84 // nsBaseWidget
michael@0 85 NS_IMPL_ISUPPORTS(nsBaseWidget, nsIWidget)
michael@0 86
michael@0 87
michael@0 88 nsAutoRollup::nsAutoRollup()
michael@0 89 {
michael@0 90 // remember if mLastRollup was null, and only clear it upon destruction
michael@0 91 // if so. This prevents recursive usage of nsAutoRollup from clearing
michael@0 92 // mLastRollup when it shouldn't.
michael@0 93 wasClear = !nsBaseWidget::mLastRollup;
michael@0 94 }
michael@0 95
michael@0 96 nsAutoRollup::~nsAutoRollup()
michael@0 97 {
michael@0 98 if (nsBaseWidget::mLastRollup && wasClear) {
michael@0 99 NS_RELEASE(nsBaseWidget::mLastRollup);
michael@0 100 }
michael@0 101 }
michael@0 102
michael@0 103 //-------------------------------------------------------------------------
michael@0 104 //
michael@0 105 // nsBaseWidget constructor
michael@0 106 //
michael@0 107 //-------------------------------------------------------------------------
michael@0 108
michael@0 109 nsBaseWidget::nsBaseWidget()
michael@0 110 : mWidgetListener(nullptr)
michael@0 111 , mAttachedWidgetListener(nullptr)
michael@0 112 , mContext(nullptr)
michael@0 113 , mCursor(eCursor_standard)
michael@0 114 , mBorderStyle(eBorderStyle_none)
michael@0 115 , mUseLayersAcceleration(false)
michael@0 116 , mForceLayersAcceleration(false)
michael@0 117 , mTemporarilyUseBasicLayerManager(false)
michael@0 118 , mUseAttachedEvents(false)
michael@0 119 , mContextInitialized(false)
michael@0 120 , mBounds(0,0,0,0)
michael@0 121 , mOriginalBounds(nullptr)
michael@0 122 , mClipRectCount(0)
michael@0 123 , mSizeMode(nsSizeMode_Normal)
michael@0 124 , mPopupLevel(ePopupLevelTop)
michael@0 125 , mPopupType(ePopupTypeAny)
michael@0 126 {
michael@0 127 #ifdef NOISY_WIDGET_LEAKS
michael@0 128 gNumWidgets++;
michael@0 129 printf("WIDGETS+ = %d\n", gNumWidgets);
michael@0 130 #endif
michael@0 131
michael@0 132 #ifdef DEBUG
michael@0 133 debug_RegisterPrefCallbacks();
michael@0 134 #endif
michael@0 135
michael@0 136 mShutdownObserver = new WidgetShutdownObserver(this);
michael@0 137 nsContentUtils::RegisterShutdownObserver(mShutdownObserver);
michael@0 138 }
michael@0 139
michael@0 140 NS_IMPL_ISUPPORTS(WidgetShutdownObserver, nsIObserver)
michael@0 141
michael@0 142 NS_IMETHODIMP
michael@0 143 WidgetShutdownObserver::Observe(nsISupports *aSubject,
michael@0 144 const char *aTopic,
michael@0 145 const char16_t *aData)
michael@0 146 {
michael@0 147 if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0 &&
michael@0 148 mWidget) {
michael@0 149 mWidget->Shutdown();
michael@0 150 nsContentUtils::UnregisterShutdownObserver(this);
michael@0 151 }
michael@0 152 return NS_OK;
michael@0 153 }
michael@0 154
michael@0 155 void
michael@0 156 nsBaseWidget::Shutdown()
michael@0 157 {
michael@0 158 DestroyCompositor();
michael@0 159 mShutdownObserver = nullptr;
michael@0 160 }
michael@0 161
michael@0 162 static void DeferredDestroyCompositor(CompositorParent* aCompositorParent,
michael@0 163 CompositorChild* aCompositorChild)
michael@0 164 {
michael@0 165 // Bug 848949 needs to be fixed before
michael@0 166 // we can close the channel properly
michael@0 167 //aCompositorChild->Close();
michael@0 168 aCompositorParent->Release();
michael@0 169 aCompositorChild->Release();
michael@0 170 }
michael@0 171
michael@0 172 void nsBaseWidget::DestroyCompositor()
michael@0 173 {
michael@0 174 LayerScope::DestroyServerSocket();
michael@0 175
michael@0 176 if (mCompositorChild) {
michael@0 177 mCompositorChild->SendWillStop();
michael@0 178 mCompositorChild->Destroy();
michael@0 179
michael@0 180 // The call just made to SendWillStop can result in IPC from the
michael@0 181 // CompositorParent to the CompositorChild (e.g. caused by the destruction
michael@0 182 // of shared memory). We need to ensure this gets processed by the
michael@0 183 // CompositorChild before it gets destroyed. It suffices to ensure that
michael@0 184 // events already in the MessageLoop get processed before the
michael@0 185 // CompositorChild is destroyed, so we add a task to the MessageLoop to
michael@0 186 // handle compositor desctruction.
michael@0 187 MessageLoop::current()->PostTask(FROM_HERE,
michael@0 188 NewRunnableFunction(DeferredDestroyCompositor, mCompositorParent,
michael@0 189 mCompositorChild));
michael@0 190 // The DestroyCompositor task we just added to the MessageLoop will handle
michael@0 191 // releasing mCompositorParent and mCompositorChild.
michael@0 192 unused << mCompositorParent.forget();
michael@0 193 unused << mCompositorChild.forget();
michael@0 194 }
michael@0 195 }
michael@0 196
michael@0 197 //-------------------------------------------------------------------------
michael@0 198 //
michael@0 199 // nsBaseWidget destructor
michael@0 200 //
michael@0 201 //-------------------------------------------------------------------------
michael@0 202 nsBaseWidget::~nsBaseWidget()
michael@0 203 {
michael@0 204 if (mLayerManager &&
michael@0 205 mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC) {
michael@0 206 static_cast<BasicLayerManager*>(mLayerManager.get())->ClearRetainerWidget();
michael@0 207 }
michael@0 208
michael@0 209 if (mLayerManager) {
michael@0 210 mLayerManager->Destroy();
michael@0 211 mLayerManager = nullptr;
michael@0 212 }
michael@0 213
michael@0 214 if (mShutdownObserver) {
michael@0 215 // If the shutdown observer is currently processing observers,
michael@0 216 // then UnregisterShutdownObserver won't stop our Observer
michael@0 217 // function from being called. Make sure we don't try
michael@0 218 // to reference the dead widget.
michael@0 219 mShutdownObserver->mWidget = nullptr;
michael@0 220 nsContentUtils::UnregisterShutdownObserver(mShutdownObserver);
michael@0 221 }
michael@0 222
michael@0 223 DestroyCompositor();
michael@0 224
michael@0 225 #ifdef NOISY_WIDGET_LEAKS
michael@0 226 gNumWidgets--;
michael@0 227 printf("WIDGETS- = %d\n", gNumWidgets);
michael@0 228 #endif
michael@0 229
michael@0 230 NS_IF_RELEASE(mContext);
michael@0 231 delete mOriginalBounds;
michael@0 232 }
michael@0 233
michael@0 234
michael@0 235 //-------------------------------------------------------------------------
michael@0 236 //
michael@0 237 // Basic create.
michael@0 238 //
michael@0 239 //-------------------------------------------------------------------------
michael@0 240 void nsBaseWidget::BaseCreate(nsIWidget *aParent,
michael@0 241 const nsIntRect &aRect,
michael@0 242 nsDeviceContext *aContext,
michael@0 243 nsWidgetInitData *aInitData)
michael@0 244 {
michael@0 245 static bool gDisableNativeThemeCached = false;
michael@0 246 if (!gDisableNativeThemeCached) {
michael@0 247 Preferences::AddBoolVarCache(&gDisableNativeTheme,
michael@0 248 "mozilla.widget.disable-native-theme",
michael@0 249 gDisableNativeTheme);
michael@0 250 gDisableNativeThemeCached = true;
michael@0 251 }
michael@0 252
michael@0 253 // keep a reference to the device context
michael@0 254 if (aContext) {
michael@0 255 mContext = aContext;
michael@0 256 NS_ADDREF(mContext);
michael@0 257 }
michael@0 258 else {
michael@0 259 mContext = new nsDeviceContext();
michael@0 260 NS_ADDREF(mContext);
michael@0 261 mContext->Init(nullptr);
michael@0 262 }
michael@0 263
michael@0 264 if (nullptr != aInitData) {
michael@0 265 mWindowType = aInitData->mWindowType;
michael@0 266 mBorderStyle = aInitData->mBorderStyle;
michael@0 267 mPopupLevel = aInitData->mPopupLevel;
michael@0 268 mPopupType = aInitData->mPopupHint;
michael@0 269 mRequireOffMainThreadCompositing = aInitData->mRequireOffMainThreadCompositing;
michael@0 270 }
michael@0 271
michael@0 272 if (aParent) {
michael@0 273 aParent->AddChild(this);
michael@0 274 }
michael@0 275 }
michael@0 276
michael@0 277 NS_IMETHODIMP nsBaseWidget::CaptureMouse(bool aCapture)
michael@0 278 {
michael@0 279 return NS_OK;
michael@0 280 }
michael@0 281
michael@0 282 //-------------------------------------------------------------------------
michael@0 283 //
michael@0 284 // Accessor functions to get/set the client data
michael@0 285 //
michael@0 286 //-------------------------------------------------------------------------
michael@0 287
michael@0 288 nsIWidgetListener* nsBaseWidget::GetWidgetListener()
michael@0 289 {
michael@0 290 return mWidgetListener;
michael@0 291 }
michael@0 292
michael@0 293 void nsBaseWidget::SetWidgetListener(nsIWidgetListener* aWidgetListener)
michael@0 294 {
michael@0 295 mWidgetListener = aWidgetListener;
michael@0 296 }
michael@0 297
michael@0 298 already_AddRefed<nsIWidget>
michael@0 299 nsBaseWidget::CreateChild(const nsIntRect &aRect,
michael@0 300 nsDeviceContext *aContext,
michael@0 301 nsWidgetInitData *aInitData,
michael@0 302 bool aForceUseIWidgetParent)
michael@0 303 {
michael@0 304 nsIWidget* parent = this;
michael@0 305 nsNativeWidget nativeParent = nullptr;
michael@0 306
michael@0 307 if (!aForceUseIWidgetParent) {
michael@0 308 // Use only either parent or nativeParent, not both, to match
michael@0 309 // existing code. Eventually Create() should be divested of its
michael@0 310 // nativeWidget parameter.
michael@0 311 nativeParent = parent ? parent->GetNativeData(NS_NATIVE_WIDGET) : nullptr;
michael@0 312 parent = nativeParent ? nullptr : parent;
michael@0 313 NS_ABORT_IF_FALSE(!parent || !nativeParent, "messed up logic");
michael@0 314 }
michael@0 315
michael@0 316 nsCOMPtr<nsIWidget> widget;
michael@0 317 if (aInitData && aInitData->mWindowType == eWindowType_popup) {
michael@0 318 widget = AllocateChildPopupWidget();
michael@0 319 } else {
michael@0 320 static NS_DEFINE_IID(kCChildCID, NS_CHILD_CID);
michael@0 321 widget = do_CreateInstance(kCChildCID);
michael@0 322 }
michael@0 323
michael@0 324 if (widget &&
michael@0 325 NS_SUCCEEDED(widget->Create(parent, nativeParent, aRect,
michael@0 326 aContext, aInitData))) {
michael@0 327 return widget.forget();
michael@0 328 }
michael@0 329
michael@0 330 return nullptr;
michael@0 331 }
michael@0 332
michael@0 333 // Attach a view to our widget which we'll send events to.
michael@0 334 NS_IMETHODIMP
michael@0 335 nsBaseWidget::AttachViewToTopLevel(bool aUseAttachedEvents,
michael@0 336 nsDeviceContext *aContext)
michael@0 337 {
michael@0 338 NS_ASSERTION((mWindowType == eWindowType_toplevel ||
michael@0 339 mWindowType == eWindowType_dialog ||
michael@0 340 mWindowType == eWindowType_invisible ||
michael@0 341 mWindowType == eWindowType_child),
michael@0 342 "Can't attach to window of that type");
michael@0 343
michael@0 344 mUseAttachedEvents = aUseAttachedEvents;
michael@0 345
michael@0 346 if (aContext) {
michael@0 347 if (mContext) {
michael@0 348 NS_IF_RELEASE(mContext);
michael@0 349 }
michael@0 350 mContext = aContext;
michael@0 351 NS_ADDREF(mContext);
michael@0 352 }
michael@0 353
michael@0 354 return NS_OK;
michael@0 355 }
michael@0 356
michael@0 357 nsIWidgetListener* nsBaseWidget::GetAttachedWidgetListener()
michael@0 358 {
michael@0 359 return mAttachedWidgetListener;
michael@0 360 }
michael@0 361
michael@0 362 void nsBaseWidget::SetAttachedWidgetListener(nsIWidgetListener* aListener)
michael@0 363 {
michael@0 364 mAttachedWidgetListener = aListener;
michael@0 365 }
michael@0 366
michael@0 367 //-------------------------------------------------------------------------
michael@0 368 //
michael@0 369 // Close this nsBaseWidget
michael@0 370 //
michael@0 371 //-------------------------------------------------------------------------
michael@0 372 NS_METHOD nsBaseWidget::Destroy()
michael@0 373 {
michael@0 374 // Just in case our parent is the only ref to us
michael@0 375 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
michael@0 376 // disconnect from the parent
michael@0 377 nsIWidget *parent = GetParent();
michael@0 378 if (parent) {
michael@0 379 parent->RemoveChild(this);
michael@0 380 }
michael@0 381
michael@0 382 return NS_OK;
michael@0 383 }
michael@0 384
michael@0 385
michael@0 386 //-------------------------------------------------------------------------
michael@0 387 //
michael@0 388 // Set this nsBaseWidget's parent
michael@0 389 //
michael@0 390 //-------------------------------------------------------------------------
michael@0 391 NS_IMETHODIMP nsBaseWidget::SetParent(nsIWidget* aNewParent)
michael@0 392 {
michael@0 393 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 394 }
michael@0 395
michael@0 396
michael@0 397 //-------------------------------------------------------------------------
michael@0 398 //
michael@0 399 // Get this nsBaseWidget parent
michael@0 400 //
michael@0 401 //-------------------------------------------------------------------------
michael@0 402 nsIWidget* nsBaseWidget::GetParent(void)
michael@0 403 {
michael@0 404 return nullptr;
michael@0 405 }
michael@0 406
michael@0 407 //-------------------------------------------------------------------------
michael@0 408 //
michael@0 409 // Get this nsBaseWidget top level widget
michael@0 410 //
michael@0 411 //-------------------------------------------------------------------------
michael@0 412 nsIWidget* nsBaseWidget::GetTopLevelWidget()
michael@0 413 {
michael@0 414 nsIWidget *topLevelWidget = nullptr, *widget = this;
michael@0 415 while (widget) {
michael@0 416 topLevelWidget = widget;
michael@0 417 widget = widget->GetParent();
michael@0 418 }
michael@0 419 return topLevelWidget;
michael@0 420 }
michael@0 421
michael@0 422 //-------------------------------------------------------------------------
michael@0 423 //
michael@0 424 // Get this nsBaseWidget's top (non-sheet) parent (if it's a sheet)
michael@0 425 //
michael@0 426 //-------------------------------------------------------------------------
michael@0 427 nsIWidget* nsBaseWidget::GetSheetWindowParent(void)
michael@0 428 {
michael@0 429 return nullptr;
michael@0 430 }
michael@0 431
michael@0 432 float nsBaseWidget::GetDPI()
michael@0 433 {
michael@0 434 return 96.0f;
michael@0 435 }
michael@0 436
michael@0 437 CSSToLayoutDeviceScale nsIWidget::GetDefaultScale()
michael@0 438 {
michael@0 439 double devPixelsPerCSSPixel = DefaultScaleOverride();
michael@0 440
michael@0 441 if (devPixelsPerCSSPixel <= 0.0) {
michael@0 442 devPixelsPerCSSPixel = GetDefaultScaleInternal();
michael@0 443 }
michael@0 444
michael@0 445 return CSSToLayoutDeviceScale(devPixelsPerCSSPixel);
michael@0 446 }
michael@0 447
michael@0 448 /* static */
michael@0 449 double nsIWidget::DefaultScaleOverride()
michael@0 450 {
michael@0 451 // The number of device pixels per CSS pixel. A value <= 0 means choose
michael@0 452 // automatically based on the DPI. A positive value is used as-is. This effectively
michael@0 453 // controls the size of a CSS "px".
michael@0 454 double devPixelsPerCSSPixel = -1.0;
michael@0 455
michael@0 456 nsAdoptingCString prefString = Preferences::GetCString("layout.css.devPixelsPerPx");
michael@0 457 if (!prefString.IsEmpty()) {
michael@0 458 devPixelsPerCSSPixel = PR_strtod(prefString, nullptr);
michael@0 459 }
michael@0 460
michael@0 461 return devPixelsPerCSSPixel;
michael@0 462 }
michael@0 463
michael@0 464 //-------------------------------------------------------------------------
michael@0 465 //
michael@0 466 // Add a child to the list of children
michael@0 467 //
michael@0 468 //-------------------------------------------------------------------------
michael@0 469 void nsBaseWidget::AddChild(nsIWidget* aChild)
michael@0 470 {
michael@0 471 NS_PRECONDITION(!aChild->GetNextSibling() && !aChild->GetPrevSibling(),
michael@0 472 "aChild not properly removed from its old child list");
michael@0 473
michael@0 474 if (!mFirstChild) {
michael@0 475 mFirstChild = mLastChild = aChild;
michael@0 476 } else {
michael@0 477 // append to the list
michael@0 478 NS_ASSERTION(mLastChild, "Bogus state");
michael@0 479 NS_ASSERTION(!mLastChild->GetNextSibling(), "Bogus state");
michael@0 480 mLastChild->SetNextSibling(aChild);
michael@0 481 aChild->SetPrevSibling(mLastChild);
michael@0 482 mLastChild = aChild;
michael@0 483 }
michael@0 484 }
michael@0 485
michael@0 486
michael@0 487 //-------------------------------------------------------------------------
michael@0 488 //
michael@0 489 // Remove a child from the list of children
michael@0 490 //
michael@0 491 //-------------------------------------------------------------------------
michael@0 492 void nsBaseWidget::RemoveChild(nsIWidget* aChild)
michael@0 493 {
michael@0 494 #ifdef DEBUG
michael@0 495 #ifdef XP_MACOSX
michael@0 496 // nsCocoaWindow doesn't implement GetParent, so in that case parent will be
michael@0 497 // null and we'll just have to do without this assertion.
michael@0 498 nsIWidget* parent = aChild->GetParent();
michael@0 499 NS_ASSERTION(!parent || parent == this, "Not one of our kids!");
michael@0 500 #else
michael@0 501 NS_ASSERTION(aChild->GetParent() == this, "Not one of our kids!");
michael@0 502 #endif
michael@0 503 #endif
michael@0 504
michael@0 505 if (mLastChild == aChild) {
michael@0 506 mLastChild = mLastChild->GetPrevSibling();
michael@0 507 }
michael@0 508 if (mFirstChild == aChild) {
michael@0 509 mFirstChild = mFirstChild->GetNextSibling();
michael@0 510 }
michael@0 511
michael@0 512 // Now remove from the list. Make sure that we pass ownership of the tail
michael@0 513 // of the list correctly before we have aChild let go of it.
michael@0 514 nsIWidget* prev = aChild->GetPrevSibling();
michael@0 515 nsIWidget* next = aChild->GetNextSibling();
michael@0 516 if (prev) {
michael@0 517 prev->SetNextSibling(next);
michael@0 518 }
michael@0 519 if (next) {
michael@0 520 next->SetPrevSibling(prev);
michael@0 521 }
michael@0 522
michael@0 523 aChild->SetNextSibling(nullptr);
michael@0 524 aChild->SetPrevSibling(nullptr);
michael@0 525 }
michael@0 526
michael@0 527
michael@0 528 //-------------------------------------------------------------------------
michael@0 529 //
michael@0 530 // Sets widget's position within its parent's child list.
michael@0 531 //
michael@0 532 //-------------------------------------------------------------------------
michael@0 533 void nsBaseWidget::SetZIndex(int32_t aZIndex)
michael@0 534 {
michael@0 535 // Hold a ref to ourselves just in case, since we're going to remove
michael@0 536 // from our parent.
michael@0 537 nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
michael@0 538
michael@0 539 mZIndex = aZIndex;
michael@0 540
michael@0 541 // reorder this child in its parent's list.
michael@0 542 nsBaseWidget* parent = static_cast<nsBaseWidget*>(GetParent());
michael@0 543 if (parent) {
michael@0 544 parent->RemoveChild(this);
michael@0 545 // Scope sib outside the for loop so we can check it afterward
michael@0 546 nsIWidget* sib = parent->GetFirstChild();
michael@0 547 for ( ; sib; sib = sib->GetNextSibling()) {
michael@0 548 int32_t childZIndex = GetZIndex();
michael@0 549 if (aZIndex < childZIndex) {
michael@0 550 // Insert ourselves before sib
michael@0 551 nsIWidget* prev = sib->GetPrevSibling();
michael@0 552 mNextSibling = sib;
michael@0 553 mPrevSibling = prev;
michael@0 554 sib->SetPrevSibling(this);
michael@0 555 if (prev) {
michael@0 556 prev->SetNextSibling(this);
michael@0 557 } else {
michael@0 558 NS_ASSERTION(sib == parent->mFirstChild, "Broken child list");
michael@0 559 // We've taken ownership of sib, so it's safe to have parent let
michael@0 560 // go of it
michael@0 561 parent->mFirstChild = this;
michael@0 562 }
michael@0 563 PlaceBehind(eZPlacementBelow, sib, false);
michael@0 564 break;
michael@0 565 }
michael@0 566 }
michael@0 567 // were we added to the list?
michael@0 568 if (!sib) {
michael@0 569 parent->AddChild(this);
michael@0 570 }
michael@0 571 }
michael@0 572 }
michael@0 573
michael@0 574 //-------------------------------------------------------------------------
michael@0 575 //
michael@0 576 // Places widget behind the given widget (platforms must override)
michael@0 577 //
michael@0 578 //-------------------------------------------------------------------------
michael@0 579 NS_IMETHODIMP nsBaseWidget::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
michael@0 580 nsIWidget *aWidget, bool aActivate)
michael@0 581 {
michael@0 582 return NS_OK;
michael@0 583 }
michael@0 584
michael@0 585 //-------------------------------------------------------------------------
michael@0 586 //
michael@0 587 // Maximize, minimize or restore the window. The BaseWidget implementation
michael@0 588 // merely stores the state.
michael@0 589 //
michael@0 590 //-------------------------------------------------------------------------
michael@0 591 NS_IMETHODIMP nsBaseWidget::SetSizeMode(int32_t aMode)
michael@0 592 {
michael@0 593 if (aMode == nsSizeMode_Normal ||
michael@0 594 aMode == nsSizeMode_Minimized ||
michael@0 595 aMode == nsSizeMode_Maximized ||
michael@0 596 aMode == nsSizeMode_Fullscreen) {
michael@0 597
michael@0 598 mSizeMode = (nsSizeMode) aMode;
michael@0 599 return NS_OK;
michael@0 600 }
michael@0 601 return NS_ERROR_ILLEGAL_VALUE;
michael@0 602 }
michael@0 603
michael@0 604 //-------------------------------------------------------------------------
michael@0 605 //
michael@0 606 // Get this component cursor
michael@0 607 //
michael@0 608 //-------------------------------------------------------------------------
michael@0 609 nsCursor nsBaseWidget::GetCursor()
michael@0 610 {
michael@0 611 return mCursor;
michael@0 612 }
michael@0 613
michael@0 614 NS_METHOD nsBaseWidget::SetCursor(nsCursor aCursor)
michael@0 615 {
michael@0 616 mCursor = aCursor;
michael@0 617 return NS_OK;
michael@0 618 }
michael@0 619
michael@0 620 NS_IMETHODIMP nsBaseWidget::SetCursor(imgIContainer* aCursor,
michael@0 621 uint32_t aHotspotX, uint32_t aHotspotY)
michael@0 622 {
michael@0 623 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 624 }
michael@0 625
michael@0 626 //-------------------------------------------------------------------------
michael@0 627 //
michael@0 628 // Window transparency methods
michael@0 629 //
michael@0 630 //-------------------------------------------------------------------------
michael@0 631
michael@0 632 void nsBaseWidget::SetTransparencyMode(nsTransparencyMode aMode) {
michael@0 633 }
michael@0 634
michael@0 635 nsTransparencyMode nsBaseWidget::GetTransparencyMode() {
michael@0 636 return eTransparencyOpaque;
michael@0 637 }
michael@0 638
michael@0 639 bool
michael@0 640 nsBaseWidget::StoreWindowClipRegion(const nsTArray<nsIntRect>& aRects)
michael@0 641 {
michael@0 642 if (mClipRects && mClipRectCount == aRects.Length() &&
michael@0 643 memcmp(mClipRects, aRects.Elements(), sizeof(nsIntRect)*mClipRectCount) == 0)
michael@0 644 return false;
michael@0 645
michael@0 646 mClipRectCount = aRects.Length();
michael@0 647 mClipRects = new nsIntRect[mClipRectCount];
michael@0 648 if (mClipRects) {
michael@0 649 memcpy(mClipRects, aRects.Elements(), sizeof(nsIntRect)*mClipRectCount);
michael@0 650 }
michael@0 651 return true;
michael@0 652 }
michael@0 653
michael@0 654 void
michael@0 655 nsBaseWidget::GetWindowClipRegion(nsTArray<nsIntRect>* aRects)
michael@0 656 {
michael@0 657 if (mClipRects) {
michael@0 658 aRects->AppendElements(mClipRects.get(), mClipRectCount);
michael@0 659 } else {
michael@0 660 aRects->AppendElement(nsIntRect(0, 0, mBounds.width, mBounds.height));
michael@0 661 }
michael@0 662 }
michael@0 663
michael@0 664 //-------------------------------------------------------------------------
michael@0 665 //
michael@0 666 // Set window shadow style
michael@0 667 //
michael@0 668 //-------------------------------------------------------------------------
michael@0 669
michael@0 670 NS_IMETHODIMP nsBaseWidget::SetWindowShadowStyle(int32_t aMode)
michael@0 671 {
michael@0 672 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 673 }
michael@0 674
michael@0 675 //-------------------------------------------------------------------------
michael@0 676 //
michael@0 677 // Hide window borders/decorations for this widget
michael@0 678 //
michael@0 679 //-------------------------------------------------------------------------
michael@0 680 NS_IMETHODIMP nsBaseWidget::HideWindowChrome(bool aShouldHide)
michael@0 681 {
michael@0 682 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 683 }
michael@0 684
michael@0 685 //-------------------------------------------------------------------------
michael@0 686 //
michael@0 687 // Put the window into full-screen mode
michael@0 688 //
michael@0 689 //-------------------------------------------------------------------------
michael@0 690 NS_IMETHODIMP nsBaseWidget::MakeFullScreen(bool aFullScreen)
michael@0 691 {
michael@0 692 HideWindowChrome(aFullScreen);
michael@0 693
michael@0 694 if (aFullScreen) {
michael@0 695 if (!mOriginalBounds)
michael@0 696 mOriginalBounds = new nsIntRect();
michael@0 697 GetScreenBounds(*mOriginalBounds);
michael@0 698 // convert dev pix to display pix for window manipulation
michael@0 699 CSSToLayoutDeviceScale scale = GetDefaultScale();
michael@0 700 mOriginalBounds->x = NSToIntRound(mOriginalBounds->x / scale.scale);
michael@0 701 mOriginalBounds->y = NSToIntRound(mOriginalBounds->y / scale.scale);
michael@0 702 mOriginalBounds->width = NSToIntRound(mOriginalBounds->width / scale.scale);
michael@0 703 mOriginalBounds->height = NSToIntRound(mOriginalBounds->height / scale.scale);
michael@0 704
michael@0 705 // Move to top-left corner of screen and size to the screen dimensions
michael@0 706 nsCOMPtr<nsIScreenManager> screenManager;
michael@0 707 screenManager = do_GetService("@mozilla.org/gfx/screenmanager;1");
michael@0 708 NS_ASSERTION(screenManager, "Unable to grab screenManager.");
michael@0 709 if (screenManager) {
michael@0 710 nsCOMPtr<nsIScreen> screen;
michael@0 711 screenManager->ScreenForRect(mOriginalBounds->x,
michael@0 712 mOriginalBounds->y,
michael@0 713 mOriginalBounds->width,
michael@0 714 mOriginalBounds->height,
michael@0 715 getter_AddRefs(screen));
michael@0 716 if (screen) {
michael@0 717 int32_t left, top, width, height;
michael@0 718 if (NS_SUCCEEDED(screen->GetRectDisplayPix(&left, &top, &width, &height))) {
michael@0 719 Resize(left, top, width, height, true);
michael@0 720 }
michael@0 721 }
michael@0 722 }
michael@0 723
michael@0 724 } else if (mOriginalBounds) {
michael@0 725 Resize(mOriginalBounds->x, mOriginalBounds->y, mOriginalBounds->width,
michael@0 726 mOriginalBounds->height, true);
michael@0 727 }
michael@0 728
michael@0 729 return NS_OK;
michael@0 730 }
michael@0 731
michael@0 732 nsBaseWidget::AutoLayerManagerSetup::AutoLayerManagerSetup(
michael@0 733 nsBaseWidget* aWidget, gfxContext* aTarget,
michael@0 734 BufferMode aDoubleBuffering, ScreenRotation aRotation)
michael@0 735 : mWidget(aWidget)
michael@0 736 {
michael@0 737 mLayerManager = static_cast<BasicLayerManager*>(mWidget->GetLayerManager());
michael@0 738 if (mLayerManager) {
michael@0 739 NS_ASSERTION(mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC,
michael@0 740 "AutoLayerManagerSetup instantiated for non-basic layer backend!");
michael@0 741 mLayerManager->SetDefaultTarget(aTarget);
michael@0 742 mLayerManager->SetDefaultTargetConfiguration(aDoubleBuffering, aRotation);
michael@0 743 }
michael@0 744 }
michael@0 745
michael@0 746 nsBaseWidget::AutoLayerManagerSetup::~AutoLayerManagerSetup()
michael@0 747 {
michael@0 748 if (mLayerManager) {
michael@0 749 NS_ASSERTION(mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC,
michael@0 750 "AutoLayerManagerSetup instantiated for non-basic layer backend!");
michael@0 751 mLayerManager->SetDefaultTarget(nullptr);
michael@0 752 mLayerManager->SetDefaultTargetConfiguration(mozilla::layers::BufferMode::BUFFER_NONE, ROTATION_0);
michael@0 753 }
michael@0 754 }
michael@0 755
michael@0 756 nsBaseWidget::AutoUseBasicLayerManager::AutoUseBasicLayerManager(nsBaseWidget* aWidget)
michael@0 757 : mWidget(aWidget)
michael@0 758 {
michael@0 759 mPreviousTemporarilyUseBasicLayerManager =
michael@0 760 mWidget->mTemporarilyUseBasicLayerManager;
michael@0 761 mWidget->mTemporarilyUseBasicLayerManager = true;
michael@0 762 }
michael@0 763
michael@0 764 nsBaseWidget::AutoUseBasicLayerManager::~AutoUseBasicLayerManager()
michael@0 765 {
michael@0 766 mWidget->mTemporarilyUseBasicLayerManager =
michael@0 767 mPreviousTemporarilyUseBasicLayerManager;
michael@0 768 }
michael@0 769
michael@0 770 bool
michael@0 771 nsBaseWidget::ComputeShouldAccelerate(bool aDefault)
michael@0 772 {
michael@0 773 #if defined(XP_WIN) || defined(ANDROID) || \
michael@0 774 defined(MOZ_GL_PROVIDER) || defined(XP_MACOSX) || defined(MOZ_WIDGET_QT)
michael@0 775 bool accelerateByDefault = true;
michael@0 776 #else
michael@0 777 bool accelerateByDefault = false;
michael@0 778 #endif
michael@0 779
michael@0 780 #ifdef XP_MACOSX
michael@0 781 // 10.6.2 and lower have a bug involving textures and pixel buffer objects
michael@0 782 // that caused bug 629016, so we don't allow OpenGL-accelerated layers on
michael@0 783 // those versions of the OS.
michael@0 784 // This will still let full-screen video be accelerated on OpenGL, because
michael@0 785 // that XUL widget opts in to acceleration, but that's probably OK.
michael@0 786 SInt32 major = nsCocoaFeatures::OSXVersionMajor();
michael@0 787 SInt32 minor = nsCocoaFeatures::OSXVersionMinor();
michael@0 788 SInt32 bugfix = nsCocoaFeatures::OSXVersionBugFix();
michael@0 789 if (major == 10 && minor == 6 && bugfix <= 2) {
michael@0 790 accelerateByDefault = false;
michael@0 791 }
michael@0 792 #endif
michael@0 793
michael@0 794 // we should use AddBoolPrefVarCache
michael@0 795 bool disableAcceleration = gfxPrefs::LayersAccelerationDisabled();
michael@0 796 mForceLayersAcceleration = gfxPrefs::LayersAccelerationForceEnabled();
michael@0 797
michael@0 798 const char *acceleratedEnv = PR_GetEnv("MOZ_ACCELERATED");
michael@0 799 accelerateByDefault = accelerateByDefault ||
michael@0 800 (acceleratedEnv && (*acceleratedEnv != '0'));
michael@0 801
michael@0 802 nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
michael@0 803 bool safeMode = false;
michael@0 804 if (xr)
michael@0 805 xr->GetInSafeMode(&safeMode);
michael@0 806
michael@0 807 bool whitelisted = false;
michael@0 808
michael@0 809 nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
michael@0 810 if (gfxInfo) {
michael@0 811 // bug 655578: on X11 at least, we must always call GetData (even if we don't need that information)
michael@0 812 // as that's what causes GfxInfo initialization which kills the zombie 'glxtest' process.
michael@0 813 // initially we relied on the fact that GetFeatureStatus calls GetData for us, but bug 681026 showed
michael@0 814 // that assumption to be unsafe.
michael@0 815 gfxInfo->GetData();
michael@0 816
michael@0 817 int32_t status;
michael@0 818 if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &status))) {
michael@0 819 if (status == nsIGfxInfo::FEATURE_NO_INFO) {
michael@0 820 whitelisted = true;
michael@0 821 }
michael@0 822 }
michael@0 823 }
michael@0 824
michael@0 825 if (disableAcceleration || safeMode)
michael@0 826 return false;
michael@0 827
michael@0 828 if (mForceLayersAcceleration)
michael@0 829 return true;
michael@0 830
michael@0 831 if (!whitelisted) {
michael@0 832 static int tell_me_once = 0;
michael@0 833 if (!tell_me_once) {
michael@0 834 NS_WARNING("OpenGL-accelerated layers are not supported on this system");
michael@0 835 tell_me_once = 1;
michael@0 836 }
michael@0 837 #ifdef MOZ_ANDROID_OMTC
michael@0 838 NS_RUNTIMEABORT("OpenGL-accelerated layers are a hard requirement on this platform. "
michael@0 839 "Cannot continue without support for them");
michael@0 840 #endif
michael@0 841 return false;
michael@0 842 }
michael@0 843
michael@0 844 if (accelerateByDefault)
michael@0 845 return true;
michael@0 846
michael@0 847 /* use the window acceleration flag */
michael@0 848 return aDefault;
michael@0 849 }
michael@0 850
michael@0 851 CompositorParent* nsBaseWidget::NewCompositorParent(int aSurfaceWidth,
michael@0 852 int aSurfaceHeight)
michael@0 853 {
michael@0 854 return new CompositorParent(this, false, aSurfaceWidth, aSurfaceHeight);
michael@0 855 }
michael@0 856
michael@0 857 void nsBaseWidget::CreateCompositor()
michael@0 858 {
michael@0 859 nsIntRect rect;
michael@0 860 GetBounds(rect);
michael@0 861 CreateCompositor(rect.width, rect.height);
michael@0 862 }
michael@0 863
michael@0 864 void
michael@0 865 nsBaseWidget::GetPreferredCompositorBackends(nsTArray<LayersBackend>& aHints)
michael@0 866 {
michael@0 867 if (mUseLayersAcceleration) {
michael@0 868 aHints.AppendElement(LayersBackend::LAYERS_OPENGL);
michael@0 869 }
michael@0 870
michael@0 871 aHints.AppendElement(LayersBackend::LAYERS_BASIC);
michael@0 872 }
michael@0 873
michael@0 874 static void
michael@0 875 CheckForBasicBackends(nsTArray<LayersBackend>& aHints)
michael@0 876 {
michael@0 877 for (size_t i = 0; i < aHints.Length(); ++i) {
michael@0 878 if (aHints[i] == LayersBackend::LAYERS_BASIC &&
michael@0 879 !Preferences::GetBool("layers.offmainthreadcomposition.force-basic", false)) {
michael@0 880 // basic compositor is not stable enough for regular use
michael@0 881 aHints[i] = LayersBackend::LAYERS_NONE;
michael@0 882 }
michael@0 883 }
michael@0 884 }
michael@0 885
michael@0 886 void nsBaseWidget::CreateCompositor(int aWidth, int aHeight)
michael@0 887 {
michael@0 888 // Recreating this is tricky, as we may still have an old and we need
michael@0 889 // to make sure it's properly destroyed by calling DestroyCompositor!
michael@0 890
michael@0 891 // If we've already received a shutdown notification, don't try
michael@0 892 // create a new compositor.
michael@0 893 if (!mShutdownObserver) {
michael@0 894 return;
michael@0 895 }
michael@0 896
michael@0 897 // The server socket has to be created on the main thread.
michael@0 898 LayerScope::CreateServerSocket();
michael@0 899
michael@0 900 mCompositorParent = NewCompositorParent(aWidth, aHeight);
michael@0 901 MessageChannel *parentChannel = mCompositorParent->GetIPCChannel();
michael@0 902 ClientLayerManager* lm = new ClientLayerManager(this);
michael@0 903 MessageLoop *childMessageLoop = CompositorParent::CompositorLoop();
michael@0 904 mCompositorChild = new CompositorChild(lm);
michael@0 905 mCompositorChild->Open(parentChannel, childMessageLoop, ipc::ChildSide);
michael@0 906
michael@0 907 TextureFactoryIdentifier textureFactoryIdentifier;
michael@0 908 PLayerTransactionChild* shadowManager = nullptr;
michael@0 909 nsTArray<LayersBackend> backendHints;
michael@0 910 GetPreferredCompositorBackends(backendHints);
michael@0 911
michael@0 912 if (!mRequireOffMainThreadCompositing) {
michael@0 913 CheckForBasicBackends(backendHints);
michael@0 914 }
michael@0 915
michael@0 916 bool success = false;
michael@0 917 if (!backendHints.IsEmpty()) {
michael@0 918 shadowManager = mCompositorChild->SendPLayerTransactionConstructor(
michael@0 919 backendHints, 0, &textureFactoryIdentifier, &success);
michael@0 920 }
michael@0 921
michael@0 922 if (success) {
michael@0 923 ShadowLayerForwarder* lf = lm->AsShadowForwarder();
michael@0 924 if (!lf) {
michael@0 925 delete lm;
michael@0 926 mCompositorChild = nullptr;
michael@0 927 return;
michael@0 928 }
michael@0 929 lf->SetShadowManager(shadowManager);
michael@0 930 lf->IdentifyTextureHost(textureFactoryIdentifier);
michael@0 931 ImageBridgeChild::IdentifyCompositorTextureHost(textureFactoryIdentifier);
michael@0 932 WindowUsesOMTC();
michael@0 933
michael@0 934 mLayerManager = lm;
michael@0 935 return;
michael@0 936 }
michael@0 937
michael@0 938 NS_WARNING("Failed to create an OMT compositor.");
michael@0 939 DestroyCompositor();
michael@0 940 // Compositor child had the only reference to LayerManager and will have
michael@0 941 // deallocated it when being freed.
michael@0 942 }
michael@0 943
michael@0 944 bool nsBaseWidget::ShouldUseOffMainThreadCompositing()
michael@0 945 {
michael@0 946 return CompositorParent::CompositorLoop();
michael@0 947 }
michael@0 948
michael@0 949 LayerManager* nsBaseWidget::GetLayerManager(PLayerTransactionChild* aShadowManager,
michael@0 950 LayersBackend aBackendHint,
michael@0 951 LayerManagerPersistence aPersistence,
michael@0 952 bool* aAllowRetaining)
michael@0 953 {
michael@0 954 if (!mLayerManager) {
michael@0 955
michael@0 956 mUseLayersAcceleration = ComputeShouldAccelerate(mUseLayersAcceleration);
michael@0 957
michael@0 958 // Try to use an async compositor first, if possible
michael@0 959 if (ShouldUseOffMainThreadCompositing()) {
michael@0 960 // e10s uses the parameter to pass in the shadow manager from the TabChild
michael@0 961 // so we don't expect to see it there since this doesn't support e10s.
michael@0 962 NS_ASSERTION(aShadowManager == nullptr, "Async Compositor not supported with e10s");
michael@0 963 CreateCompositor();
michael@0 964 }
michael@0 965
michael@0 966 if (!mLayerManager) {
michael@0 967 mLayerManager = CreateBasicLayerManager();
michael@0 968 }
michael@0 969 }
michael@0 970 if (mTemporarilyUseBasicLayerManager && !mBasicLayerManager) {
michael@0 971 mBasicLayerManager = CreateBasicLayerManager();
michael@0 972 }
michael@0 973 LayerManager* usedLayerManager = mTemporarilyUseBasicLayerManager ?
michael@0 974 mBasicLayerManager : mLayerManager;
michael@0 975 if (aAllowRetaining) {
michael@0 976 *aAllowRetaining = (usedLayerManager == mLayerManager);
michael@0 977 }
michael@0 978 return usedLayerManager;
michael@0 979 }
michael@0 980
michael@0 981 LayerManager* nsBaseWidget::CreateBasicLayerManager()
michael@0 982 {
michael@0 983 return new BasicLayerManager(this);
michael@0 984 }
michael@0 985
michael@0 986 CompositorChild* nsBaseWidget::GetRemoteRenderer()
michael@0 987 {
michael@0 988 return mCompositorChild;
michael@0 989 }
michael@0 990
michael@0 991 TemporaryRef<mozilla::gfx::DrawTarget> nsBaseWidget::StartRemoteDrawing()
michael@0 992 {
michael@0 993 return nullptr;
michael@0 994 }
michael@0 995
michael@0 996 //-------------------------------------------------------------------------
michael@0 997 //
michael@0 998 // Return the used device context
michael@0 999 //
michael@0 1000 //-------------------------------------------------------------------------
michael@0 1001 nsDeviceContext* nsBaseWidget::GetDeviceContext()
michael@0 1002 {
michael@0 1003 if (!mContextInitialized) {
michael@0 1004 mContext->Init(this);
michael@0 1005 mContextInitialized = true;
michael@0 1006 }
michael@0 1007 return mContext;
michael@0 1008 }
michael@0 1009
michael@0 1010 //-------------------------------------------------------------------------
michael@0 1011 //
michael@0 1012 // Get the thebes surface
michael@0 1013 //
michael@0 1014 //-------------------------------------------------------------------------
michael@0 1015 gfxASurface *nsBaseWidget::GetThebesSurface()
michael@0 1016 {
michael@0 1017 // in theory we should get our parent's surface,
michael@0 1018 // clone it, and set a device offset before returning
michael@0 1019 return nullptr;
michael@0 1020 }
michael@0 1021
michael@0 1022
michael@0 1023 //-------------------------------------------------------------------------
michael@0 1024 //
michael@0 1025 // Destroy the window
michael@0 1026 //
michael@0 1027 //-------------------------------------------------------------------------
michael@0 1028 void nsBaseWidget::OnDestroy()
michael@0 1029 {
michael@0 1030 // release references to device context and app shell
michael@0 1031 NS_IF_RELEASE(mContext);
michael@0 1032 }
michael@0 1033
michael@0 1034 NS_METHOD nsBaseWidget::SetWindowClass(const nsAString& xulWinType)
michael@0 1035 {
michael@0 1036 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 1037 }
michael@0 1038
michael@0 1039 NS_METHOD nsBaseWidget::MoveClient(double aX, double aY)
michael@0 1040 {
michael@0 1041 nsIntPoint clientOffset(GetClientOffset());
michael@0 1042
michael@0 1043 // GetClientOffset returns device pixels; scale back to display pixels
michael@0 1044 // if that's what this widget uses for the Move/Resize APIs
michael@0 1045 CSSToLayoutDeviceScale scale = BoundsUseDisplayPixels()
michael@0 1046 ? GetDefaultScale()
michael@0 1047 : CSSToLayoutDeviceScale(1.0);
michael@0 1048 aX -= clientOffset.x * 1.0 / scale.scale;
michael@0 1049 aY -= clientOffset.y * 1.0 / scale.scale;
michael@0 1050
michael@0 1051 return Move(aX, aY);
michael@0 1052 }
michael@0 1053
michael@0 1054 NS_METHOD nsBaseWidget::ResizeClient(double aWidth,
michael@0 1055 double aHeight,
michael@0 1056 bool aRepaint)
michael@0 1057 {
michael@0 1058 NS_ASSERTION((aWidth >=0) , "Negative width passed to ResizeClient");
michael@0 1059 NS_ASSERTION((aHeight >=0), "Negative height passed to ResizeClient");
michael@0 1060
michael@0 1061 nsIntRect clientBounds;
michael@0 1062 GetClientBounds(clientBounds);
michael@0 1063
michael@0 1064 // GetClientBounds and mBounds are device pixels; scale back to display pixels
michael@0 1065 // if that's what this widget uses for the Move/Resize APIs
michael@0 1066 CSSToLayoutDeviceScale scale = BoundsUseDisplayPixels()
michael@0 1067 ? GetDefaultScale()
michael@0 1068 : CSSToLayoutDeviceScale(1.0);
michael@0 1069 double invScale = 1.0 / scale.scale;
michael@0 1070 aWidth = mBounds.width * invScale + (aWidth - clientBounds.width * invScale);
michael@0 1071 aHeight = mBounds.height * invScale + (aHeight - clientBounds.height * invScale);
michael@0 1072
michael@0 1073 return Resize(aWidth, aHeight, aRepaint);
michael@0 1074 }
michael@0 1075
michael@0 1076 NS_METHOD nsBaseWidget::ResizeClient(double aX,
michael@0 1077 double aY,
michael@0 1078 double aWidth,
michael@0 1079 double aHeight,
michael@0 1080 bool aRepaint)
michael@0 1081 {
michael@0 1082 NS_ASSERTION((aWidth >=0) , "Negative width passed to ResizeClient");
michael@0 1083 NS_ASSERTION((aHeight >=0), "Negative height passed to ResizeClient");
michael@0 1084
michael@0 1085 nsIntRect clientBounds;
michael@0 1086 GetClientBounds(clientBounds);
michael@0 1087
michael@0 1088 double scale = BoundsUseDisplayPixels() ? 1.0 / GetDefaultScale().scale : 1.0;
michael@0 1089 aWidth = mBounds.width * scale + (aWidth - clientBounds.width * scale);
michael@0 1090 aHeight = mBounds.height * scale + (aHeight - clientBounds.height * scale);
michael@0 1091
michael@0 1092 nsIntPoint clientOffset(GetClientOffset());
michael@0 1093 aX -= clientOffset.x * scale;
michael@0 1094 aY -= clientOffset.y * scale;
michael@0 1095
michael@0 1096 return Resize(aX, aY, aWidth, aHeight, aRepaint);
michael@0 1097 }
michael@0 1098
michael@0 1099 //-------------------------------------------------------------------------
michael@0 1100 //
michael@0 1101 // Bounds
michael@0 1102 //
michael@0 1103 //-------------------------------------------------------------------------
michael@0 1104
michael@0 1105 /**
michael@0 1106 * If the implementation of nsWindow supports borders this method MUST be overridden
michael@0 1107 *
michael@0 1108 **/
michael@0 1109 NS_METHOD nsBaseWidget::GetClientBounds(nsIntRect &aRect)
michael@0 1110 {
michael@0 1111 return GetBounds(aRect);
michael@0 1112 }
michael@0 1113
michael@0 1114 /**
michael@0 1115 * If the implementation of nsWindow supports borders this method MUST be overridden
michael@0 1116 *
michael@0 1117 **/
michael@0 1118 NS_METHOD nsBaseWidget::GetBounds(nsIntRect &aRect)
michael@0 1119 {
michael@0 1120 aRect = mBounds;
michael@0 1121 return NS_OK;
michael@0 1122 }
michael@0 1123
michael@0 1124 /**
michael@0 1125 * If the implementation of nsWindow uses a local coordinate system within the window,
michael@0 1126 * this method must be overridden
michael@0 1127 *
michael@0 1128 **/
michael@0 1129 NS_METHOD nsBaseWidget::GetScreenBounds(nsIntRect &aRect)
michael@0 1130 {
michael@0 1131 return GetBounds(aRect);
michael@0 1132 }
michael@0 1133
michael@0 1134 nsIntPoint nsBaseWidget::GetClientOffset()
michael@0 1135 {
michael@0 1136 return nsIntPoint(0, 0);
michael@0 1137 }
michael@0 1138
michael@0 1139 NS_IMETHODIMP
michael@0 1140 nsBaseWidget::GetNonClientMargins(nsIntMargin &margins)
michael@0 1141 {
michael@0 1142 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 1143 }
michael@0 1144
michael@0 1145 NS_IMETHODIMP
michael@0 1146 nsBaseWidget::SetNonClientMargins(nsIntMargin &margins)
michael@0 1147 {
michael@0 1148 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 1149 }
michael@0 1150
michael@0 1151 NS_METHOD nsBaseWidget::EnableDragDrop(bool aEnable)
michael@0 1152 {
michael@0 1153 return NS_OK;
michael@0 1154 }
michael@0 1155
michael@0 1156 uint32_t nsBaseWidget::GetMaxTouchPoints() const
michael@0 1157 {
michael@0 1158 return 0;
michael@0 1159 }
michael@0 1160
michael@0 1161 NS_METHOD nsBaseWidget::SetModal(bool aModal)
michael@0 1162 {
michael@0 1163 return NS_ERROR_FAILURE;
michael@0 1164 }
michael@0 1165
michael@0 1166 NS_IMETHODIMP
michael@0 1167 nsBaseWidget::GetAttention(int32_t aCycleCount) {
michael@0 1168 return NS_OK;
michael@0 1169 }
michael@0 1170
michael@0 1171 bool
michael@0 1172 nsBaseWidget::HasPendingInputEvent()
michael@0 1173 {
michael@0 1174 return false;
michael@0 1175 }
michael@0 1176
michael@0 1177 NS_IMETHODIMP
michael@0 1178 nsBaseWidget::SetIcon(const nsAString&)
michael@0 1179 {
michael@0 1180 return NS_OK;
michael@0 1181 }
michael@0 1182
michael@0 1183 NS_IMETHODIMP
michael@0 1184 nsBaseWidget::SetWindowTitlebarColor(nscolor aColor, bool aActive)
michael@0 1185 {
michael@0 1186 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 1187 }
michael@0 1188
michael@0 1189 bool
michael@0 1190 nsBaseWidget::ShowsResizeIndicator(nsIntRect* aResizerRect)
michael@0 1191 {
michael@0 1192 return false;
michael@0 1193 }
michael@0 1194
michael@0 1195 NS_IMETHODIMP
michael@0 1196 nsBaseWidget::SetLayersAcceleration(bool aEnabled)
michael@0 1197 {
michael@0 1198 if (mUseLayersAcceleration == aEnabled) {
michael@0 1199 return NS_OK;
michael@0 1200 }
michael@0 1201
michael@0 1202 bool usedAcceleration = mUseLayersAcceleration;
michael@0 1203
michael@0 1204 mUseLayersAcceleration = ComputeShouldAccelerate(aEnabled);
michael@0 1205 // ComputeShouldAccelerate may have set mUseLayersAcceleration to a value
michael@0 1206 // different from aEnabled.
michael@0 1207 if (usedAcceleration == mUseLayersAcceleration) {
michael@0 1208 return NS_OK;
michael@0 1209 }
michael@0 1210 if (mLayerManager) {
michael@0 1211 mLayerManager->Destroy();
michael@0 1212 }
michael@0 1213 mLayerManager = nullptr;
michael@0 1214 return NS_OK;
michael@0 1215 }
michael@0 1216
michael@0 1217 NS_METHOD nsBaseWidget::RegisterTouchWindow()
michael@0 1218 {
michael@0 1219 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 1220 }
michael@0 1221
michael@0 1222 NS_METHOD nsBaseWidget::UnregisterTouchWindow()
michael@0 1223 {
michael@0 1224 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 1225 }
michael@0 1226
michael@0 1227 NS_IMETHODIMP
michael@0 1228 nsBaseWidget::OverrideSystemMouseScrollSpeed(double aOriginalDeltaX,
michael@0 1229 double aOriginalDeltaY,
michael@0 1230 double& aOverriddenDeltaX,
michael@0 1231 double& aOverriddenDeltaY)
michael@0 1232 {
michael@0 1233 aOverriddenDeltaX = aOriginalDeltaX;
michael@0 1234 aOverriddenDeltaY = aOriginalDeltaY;
michael@0 1235
michael@0 1236 static bool sInitialized = false;
michael@0 1237 static bool sIsOverrideEnabled = false;
michael@0 1238 static int32_t sIntFactorX = 0;
michael@0 1239 static int32_t sIntFactorY = 0;
michael@0 1240
michael@0 1241 if (!sInitialized) {
michael@0 1242 Preferences::AddBoolVarCache(&sIsOverrideEnabled,
michael@0 1243 "mousewheel.system_scroll_override_on_root_content.enabled", false);
michael@0 1244 Preferences::AddIntVarCache(&sIntFactorX,
michael@0 1245 "mousewheel.system_scroll_override_on_root_content.horizontal.factor", 0);
michael@0 1246 Preferences::AddIntVarCache(&sIntFactorY,
michael@0 1247 "mousewheel.system_scroll_override_on_root_content.vertical.factor", 0);
michael@0 1248 sIntFactorX = std::max(sIntFactorX, 0);
michael@0 1249 sIntFactorY = std::max(sIntFactorY, 0);
michael@0 1250 sInitialized = true;
michael@0 1251 }
michael@0 1252
michael@0 1253 if (!sIsOverrideEnabled) {
michael@0 1254 return NS_OK;
michael@0 1255 }
michael@0 1256
michael@0 1257 // The pref value must be larger than 100, otherwise, we don't override the
michael@0 1258 // delta value.
michael@0 1259 if (sIntFactorX > 100) {
michael@0 1260 double factor = static_cast<double>(sIntFactorX) / 100;
michael@0 1261 aOverriddenDeltaX *= factor;
michael@0 1262 }
michael@0 1263 if (sIntFactorY > 100) {
michael@0 1264 double factor = static_cast<double>(sIntFactorY) / 100;
michael@0 1265 aOverriddenDeltaY *= factor;
michael@0 1266 }
michael@0 1267
michael@0 1268 return NS_OK;
michael@0 1269 }
michael@0 1270
michael@0 1271
michael@0 1272 /**
michael@0 1273 * Modifies aFile to point at an icon file with the given name and suffix. The
michael@0 1274 * suffix may correspond to a file extension with leading '.' if appropriate.
michael@0 1275 * Returns true if the icon file exists and can be read.
michael@0 1276 */
michael@0 1277 static bool
michael@0 1278 ResolveIconNameHelper(nsIFile *aFile,
michael@0 1279 const nsAString &aIconName,
michael@0 1280 const nsAString &aIconSuffix)
michael@0 1281 {
michael@0 1282 aFile->Append(NS_LITERAL_STRING("icons"));
michael@0 1283 aFile->Append(NS_LITERAL_STRING("default"));
michael@0 1284 aFile->Append(aIconName + aIconSuffix);
michael@0 1285
michael@0 1286 bool readable;
michael@0 1287 return NS_SUCCEEDED(aFile->IsReadable(&readable)) && readable;
michael@0 1288 }
michael@0 1289
michael@0 1290 /**
michael@0 1291 * Resolve the given icon name into a local file object. This method is
michael@0 1292 * intended to be called by subclasses of nsBaseWidget. aIconSuffix is a
michael@0 1293 * platform specific icon file suffix (e.g., ".ico" under Win32).
michael@0 1294 *
michael@0 1295 * If no file is found matching the given parameters, then null is returned.
michael@0 1296 */
michael@0 1297 void
michael@0 1298 nsBaseWidget::ResolveIconName(const nsAString &aIconName,
michael@0 1299 const nsAString &aIconSuffix,
michael@0 1300 nsIFile **aResult)
michael@0 1301 {
michael@0 1302 *aResult = nullptr;
michael@0 1303
michael@0 1304 nsCOMPtr<nsIProperties> dirSvc = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
michael@0 1305 if (!dirSvc)
michael@0 1306 return;
michael@0 1307
michael@0 1308 // first check auxilary chrome directories
michael@0 1309
michael@0 1310 nsCOMPtr<nsISimpleEnumerator> dirs;
michael@0 1311 dirSvc->Get(NS_APP_CHROME_DIR_LIST, NS_GET_IID(nsISimpleEnumerator),
michael@0 1312 getter_AddRefs(dirs));
michael@0 1313 if (dirs) {
michael@0 1314 bool hasMore;
michael@0 1315 while (NS_SUCCEEDED(dirs->HasMoreElements(&hasMore)) && hasMore) {
michael@0 1316 nsCOMPtr<nsISupports> element;
michael@0 1317 dirs->GetNext(getter_AddRefs(element));
michael@0 1318 if (!element)
michael@0 1319 continue;
michael@0 1320 nsCOMPtr<nsIFile> file = do_QueryInterface(element);
michael@0 1321 if (!file)
michael@0 1322 continue;
michael@0 1323 if (ResolveIconNameHelper(file, aIconName, aIconSuffix)) {
michael@0 1324 NS_ADDREF(*aResult = file);
michael@0 1325 return;
michael@0 1326 }
michael@0 1327 }
michael@0 1328 }
michael@0 1329
michael@0 1330 // then check the main app chrome directory
michael@0 1331
michael@0 1332 nsCOMPtr<nsIFile> file;
michael@0 1333 dirSvc->Get(NS_APP_CHROME_DIR, NS_GET_IID(nsIFile),
michael@0 1334 getter_AddRefs(file));
michael@0 1335 if (file && ResolveIconNameHelper(file, aIconName, aIconSuffix))
michael@0 1336 NS_ADDREF(*aResult = file);
michael@0 1337 }
michael@0 1338
michael@0 1339 NS_IMETHODIMP
michael@0 1340 nsBaseWidget::BeginResizeDrag(WidgetGUIEvent* aEvent,
michael@0 1341 int32_t aHorizontal,
michael@0 1342 int32_t aVertical)
michael@0 1343 {
michael@0 1344 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 1345 }
michael@0 1346
michael@0 1347 NS_IMETHODIMP
michael@0 1348 nsBaseWidget::BeginMoveDrag(WidgetMouseEvent* aEvent)
michael@0 1349 {
michael@0 1350 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 1351 }
michael@0 1352
michael@0 1353 uint32_t
michael@0 1354 nsBaseWidget::GetGLFrameBufferFormat()
michael@0 1355 {
michael@0 1356 return LOCAL_GL_RGBA;
michael@0 1357 }
michael@0 1358
michael@0 1359 void nsBaseWidget::SetSizeConstraints(const SizeConstraints& aConstraints)
michael@0 1360 {
michael@0 1361 mSizeConstraints = aConstraints;
michael@0 1362 // We can't ensure that the size is honored at this point because we're
michael@0 1363 // probably in the middle of a reflow.
michael@0 1364 }
michael@0 1365
michael@0 1366 const widget::SizeConstraints& nsBaseWidget::GetSizeConstraints() const
michael@0 1367 {
michael@0 1368 return mSizeConstraints;
michael@0 1369 }
michael@0 1370
michael@0 1371 // static
michael@0 1372 nsIRollupListener*
michael@0 1373 nsBaseWidget::GetActiveRollupListener()
michael@0 1374 {
michael@0 1375 // If set, then this is likely an <html:select> dropdown.
michael@0 1376 if (gRollupListener)
michael@0 1377 return gRollupListener;
michael@0 1378
michael@0 1379 return nsXULPopupManager::GetInstance();
michael@0 1380 }
michael@0 1381
michael@0 1382 void
michael@0 1383 nsBaseWidget::NotifyWindowDestroyed()
michael@0 1384 {
michael@0 1385 if (!mWidgetListener)
michael@0 1386 return;
michael@0 1387
michael@0 1388 nsCOMPtr<nsIXULWindow> window = mWidgetListener->GetXULWindow();
michael@0 1389 nsCOMPtr<nsIBaseWindow> xulWindow(do_QueryInterface(window));
michael@0 1390 if (xulWindow) {
michael@0 1391 xulWindow->Destroy();
michael@0 1392 }
michael@0 1393 }
michael@0 1394
michael@0 1395 void
michael@0 1396 nsBaseWidget::NotifySizeMoveDone()
michael@0 1397 {
michael@0 1398 if (!mWidgetListener || mWidgetListener->GetXULWindow())
michael@0 1399 return;
michael@0 1400
michael@0 1401 nsIPresShell* presShell = mWidgetListener->GetPresShell();
michael@0 1402 if (presShell) {
michael@0 1403 presShell->WindowSizeMoveDone();
michael@0 1404 }
michael@0 1405 }
michael@0 1406
michael@0 1407 void
michael@0 1408 nsBaseWidget::NotifyWindowMoved(int32_t aX, int32_t aY)
michael@0 1409 {
michael@0 1410 if (mWidgetListener) {
michael@0 1411 mWidgetListener->WindowMoved(this, aX, aY);
michael@0 1412 }
michael@0 1413
michael@0 1414 if (GetIMEUpdatePreference().WantPositionChanged()) {
michael@0 1415 NotifyIME(IMENotification(IMEMessage::NOTIFY_IME_OF_POSITION_CHANGE));
michael@0 1416 }
michael@0 1417 }
michael@0 1418
michael@0 1419 void
michael@0 1420 nsBaseWidget::NotifySysColorChanged()
michael@0 1421 {
michael@0 1422 if (!mWidgetListener || mWidgetListener->GetXULWindow())
michael@0 1423 return;
michael@0 1424
michael@0 1425 nsIPresShell* presShell = mWidgetListener->GetPresShell();
michael@0 1426 if (presShell) {
michael@0 1427 presShell->SysColorChanged();
michael@0 1428 }
michael@0 1429 }
michael@0 1430
michael@0 1431 void
michael@0 1432 nsBaseWidget::NotifyThemeChanged()
michael@0 1433 {
michael@0 1434 if (!mWidgetListener || mWidgetListener->GetXULWindow())
michael@0 1435 return;
michael@0 1436
michael@0 1437 nsIPresShell* presShell = mWidgetListener->GetPresShell();
michael@0 1438 if (presShell) {
michael@0 1439 presShell->ThemeChanged();
michael@0 1440 }
michael@0 1441 }
michael@0 1442
michael@0 1443 void
michael@0 1444 nsBaseWidget::NotifyUIStateChanged(UIStateChangeType aShowAccelerators,
michael@0 1445 UIStateChangeType aShowFocusRings)
michael@0 1446 {
michael@0 1447 if (!mWidgetListener)
michael@0 1448 return;
michael@0 1449
michael@0 1450 nsIPresShell* presShell = mWidgetListener->GetPresShell();
michael@0 1451 if (!presShell)
michael@0 1452 return;
michael@0 1453
michael@0 1454 nsIDocument* doc = presShell->GetDocument();
michael@0 1455 if (doc) {
michael@0 1456 nsPIDOMWindow* win = doc->GetWindow();
michael@0 1457 if (win) {
michael@0 1458 win->SetKeyboardIndicators(aShowAccelerators, aShowFocusRings);
michael@0 1459 }
michael@0 1460 }
michael@0 1461 }
michael@0 1462
michael@0 1463 #ifdef ACCESSIBILITY
michael@0 1464
michael@0 1465 a11y::Accessible*
michael@0 1466 nsBaseWidget::GetRootAccessible()
michael@0 1467 {
michael@0 1468 NS_ENSURE_TRUE(mWidgetListener, nullptr);
michael@0 1469
michael@0 1470 nsIPresShell* presShell = mWidgetListener->GetPresShell();
michael@0 1471 NS_ENSURE_TRUE(presShell, nullptr);
michael@0 1472
michael@0 1473 // If container is null then the presshell is not active. This often happens
michael@0 1474 // when a preshell is being held onto for fastback.
michael@0 1475 nsPresContext* presContext = presShell->GetPresContext();
michael@0 1476 NS_ENSURE_TRUE(presContext->GetContainerWeak(), nullptr);
michael@0 1477
michael@0 1478 // Accessible creation might be not safe so use IsSafeToRunScript to
michael@0 1479 // make sure it's not created at unsafe times.
michael@0 1480 nsCOMPtr<nsIAccessibilityService> accService =
michael@0 1481 services::GetAccessibilityService();
michael@0 1482 if (accService) {
michael@0 1483 return accService->GetRootDocumentAccessible(presShell, nsContentUtils::IsSafeToRunScript());
michael@0 1484 }
michael@0 1485
michael@0 1486 return nullptr;
michael@0 1487 }
michael@0 1488
michael@0 1489 #endif // ACCESSIBILITY
michael@0 1490
michael@0 1491 nsresult
michael@0 1492 nsIWidget::SynthesizeNativeTouchTap(nsIntPoint aPointerScreenPoint, bool aLongTap)
michael@0 1493 {
michael@0 1494 if (sPointerIdCounter > TOUCH_INJECT_MAX_POINTS) {
michael@0 1495 sPointerIdCounter = 0;
michael@0 1496 }
michael@0 1497 int pointerId = sPointerIdCounter;
michael@0 1498 sPointerIdCounter++;
michael@0 1499 nsresult rv = SynthesizeNativeTouchPoint(pointerId, TOUCH_CONTACT,
michael@0 1500 aPointerScreenPoint, 1.0, 90);
michael@0 1501 if (NS_FAILED(rv)) {
michael@0 1502 return rv;
michael@0 1503 }
michael@0 1504
michael@0 1505 if (!aLongTap) {
michael@0 1506 nsresult rv = SynthesizeNativeTouchPoint(pointerId, TOUCH_REMOVE,
michael@0 1507 aPointerScreenPoint, 0, 0);
michael@0 1508 return rv;
michael@0 1509 }
michael@0 1510
michael@0 1511 // initiate a long tap
michael@0 1512 int elapse = Preferences::GetInt("ui.click_hold_context_menus.delay",
michael@0 1513 TOUCH_INJECT_LONG_TAP_DEFAULT_MSEC);
michael@0 1514 if (!mLongTapTimer) {
michael@0 1515 mLongTapTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
michael@0 1516 if (NS_FAILED(rv)) {
michael@0 1517 SynthesizeNativeTouchPoint(pointerId, TOUCH_CANCEL,
michael@0 1518 aPointerScreenPoint, 0, 0);
michael@0 1519 return NS_ERROR_UNEXPECTED;
michael@0 1520 }
michael@0 1521 // Windows requires recuring events, so we set this to a smaller window
michael@0 1522 // than the pref value.
michael@0 1523 int timeout = elapse;
michael@0 1524 if (timeout > TOUCH_INJECT_PUMP_TIMER_MSEC) {
michael@0 1525 timeout = TOUCH_INJECT_PUMP_TIMER_MSEC;
michael@0 1526 }
michael@0 1527 mLongTapTimer->InitWithFuncCallback(OnLongTapTimerCallback, this,
michael@0 1528 timeout,
michael@0 1529 nsITimer::TYPE_REPEATING_SLACK);
michael@0 1530 }
michael@0 1531
michael@0 1532 // If we already have a long tap pending, cancel it. We only allow one long
michael@0 1533 // tap to be active at a time.
michael@0 1534 if (mLongTapTouchPoint) {
michael@0 1535 SynthesizeNativeTouchPoint(mLongTapTouchPoint->mPointerId, TOUCH_CANCEL,
michael@0 1536 mLongTapTouchPoint->mPosition, 0, 0);
michael@0 1537 }
michael@0 1538
michael@0 1539 mLongTapTouchPoint = new LongTapInfo(pointerId, aPointerScreenPoint,
michael@0 1540 TimeDuration::FromMilliseconds(elapse));
michael@0 1541 return NS_OK;
michael@0 1542 }
michael@0 1543
michael@0 1544 // static
michael@0 1545 void
michael@0 1546 nsIWidget::OnLongTapTimerCallback(nsITimer* aTimer, void* aClosure)
michael@0 1547 {
michael@0 1548 nsIWidget *self = static_cast<nsIWidget *>(aClosure);
michael@0 1549
michael@0 1550 if ((self->mLongTapTouchPoint->mStamp + self->mLongTapTouchPoint->mDuration) >
michael@0 1551 TimeStamp::Now()) {
michael@0 1552 #ifdef XP_WIN
michael@0 1553 // Windows needs us to keep pumping feedback to the digitizer, so update
michael@0 1554 // the pointer id with the same position.
michael@0 1555 self->SynthesizeNativeTouchPoint(self->mLongTapTouchPoint->mPointerId,
michael@0 1556 TOUCH_CONTACT,
michael@0 1557 self->mLongTapTouchPoint->mPosition,
michael@0 1558 1.0, 90);
michael@0 1559 #endif
michael@0 1560 return;
michael@0 1561 }
michael@0 1562
michael@0 1563 // finished, remove the touch point
michael@0 1564 self->mLongTapTimer->Cancel();
michael@0 1565 self->mLongTapTimer = nullptr;
michael@0 1566 self->SynthesizeNativeTouchPoint(self->mLongTapTouchPoint->mPointerId,
michael@0 1567 TOUCH_REMOVE,
michael@0 1568 self->mLongTapTouchPoint->mPosition,
michael@0 1569 0, 0);
michael@0 1570 self->mLongTapTouchPoint = nullptr;
michael@0 1571 }
michael@0 1572
michael@0 1573 nsresult
michael@0 1574 nsIWidget::ClearNativeTouchSequence()
michael@0 1575 {
michael@0 1576 if (!mLongTapTimer) {
michael@0 1577 return NS_OK;
michael@0 1578 }
michael@0 1579 mLongTapTimer->Cancel();
michael@0 1580 mLongTapTimer = nullptr;
michael@0 1581 SynthesizeNativeTouchPoint(mLongTapTouchPoint->mPointerId, TOUCH_CANCEL,
michael@0 1582 mLongTapTouchPoint->mPosition, 0, 0);
michael@0 1583 mLongTapTouchPoint = nullptr;
michael@0 1584 return NS_OK;
michael@0 1585 }
michael@0 1586
michael@0 1587 #ifdef DEBUG
michael@0 1588 //////////////////////////////////////////////////////////////
michael@0 1589 //
michael@0 1590 // Convert a GUI event message code to a string.
michael@0 1591 // Makes it a lot easier to debug events.
michael@0 1592 //
michael@0 1593 // See gtk/nsWidget.cpp and windows/nsWindow.cpp
michael@0 1594 // for a DebugPrintEvent() function that uses
michael@0 1595 // this.
michael@0 1596 //
michael@0 1597 //////////////////////////////////////////////////////////////
michael@0 1598 /* static */ nsAutoString
michael@0 1599 nsBaseWidget::debug_GuiEventToString(WidgetGUIEvent* aGuiEvent)
michael@0 1600 {
michael@0 1601 NS_ASSERTION(nullptr != aGuiEvent,"cmon, null gui event.");
michael@0 1602
michael@0 1603 nsAutoString eventName(NS_LITERAL_STRING("UNKNOWN"));
michael@0 1604
michael@0 1605 #define _ASSIGN_eventName(_value,_name)\
michael@0 1606 case _value: eventName.AssignLiteral(_name) ; break
michael@0 1607
michael@0 1608 switch(aGuiEvent->message)
michael@0 1609 {
michael@0 1610 _ASSIGN_eventName(NS_BLUR_CONTENT,"NS_BLUR_CONTENT");
michael@0 1611 _ASSIGN_eventName(NS_DRAGDROP_GESTURE,"NS_DND_GESTURE");
michael@0 1612 _ASSIGN_eventName(NS_DRAGDROP_DROP,"NS_DND_DROP");
michael@0 1613 _ASSIGN_eventName(NS_DRAGDROP_ENTER,"NS_DND_ENTER");
michael@0 1614 _ASSIGN_eventName(NS_DRAGDROP_EXIT,"NS_DND_EXIT");
michael@0 1615 _ASSIGN_eventName(NS_DRAGDROP_OVER,"NS_DND_OVER");
michael@0 1616 _ASSIGN_eventName(NS_EDITOR_INPUT,"NS_EDITOR_INPUT");
michael@0 1617 _ASSIGN_eventName(NS_FOCUS_CONTENT,"NS_FOCUS_CONTENT");
michael@0 1618 _ASSIGN_eventName(NS_FORM_SELECTED,"NS_FORM_SELECTED");
michael@0 1619 _ASSIGN_eventName(NS_FORM_CHANGE,"NS_FORM_CHANGE");
michael@0 1620 _ASSIGN_eventName(NS_FORM_RESET,"NS_FORM_RESET");
michael@0 1621 _ASSIGN_eventName(NS_FORM_SUBMIT,"NS_FORM_SUBMIT");
michael@0 1622 _ASSIGN_eventName(NS_IMAGE_ABORT,"NS_IMAGE_ABORT");
michael@0 1623 _ASSIGN_eventName(NS_LOAD_ERROR,"NS_LOAD_ERROR");
michael@0 1624 _ASSIGN_eventName(NS_KEY_DOWN,"NS_KEY_DOWN");
michael@0 1625 _ASSIGN_eventName(NS_KEY_PRESS,"NS_KEY_PRESS");
michael@0 1626 _ASSIGN_eventName(NS_KEY_UP,"NS_KEY_UP");
michael@0 1627 _ASSIGN_eventName(NS_MOUSE_ENTER,"NS_MOUSE_ENTER");
michael@0 1628 _ASSIGN_eventName(NS_MOUSE_EXIT,"NS_MOUSE_EXIT");
michael@0 1629 _ASSIGN_eventName(NS_MOUSE_BUTTON_DOWN,"NS_MOUSE_BUTTON_DOWN");
michael@0 1630 _ASSIGN_eventName(NS_MOUSE_BUTTON_UP,"NS_MOUSE_BUTTON_UP");
michael@0 1631 _ASSIGN_eventName(NS_MOUSE_CLICK,"NS_MOUSE_CLICK");
michael@0 1632 _ASSIGN_eventName(NS_MOUSE_DOUBLECLICK,"NS_MOUSE_DBLCLICK");
michael@0 1633 _ASSIGN_eventName(NS_MOUSE_MOVE,"NS_MOUSE_MOVE");
michael@0 1634 _ASSIGN_eventName(NS_LOAD,"NS_LOAD");
michael@0 1635 _ASSIGN_eventName(NS_POPSTATE,"NS_POPSTATE");
michael@0 1636 _ASSIGN_eventName(NS_BEFORE_SCRIPT_EXECUTE,"NS_BEFORE_SCRIPT_EXECUTE");
michael@0 1637 _ASSIGN_eventName(NS_AFTER_SCRIPT_EXECUTE,"NS_AFTER_SCRIPT_EXECUTE");
michael@0 1638 _ASSIGN_eventName(NS_PAGE_UNLOAD,"NS_PAGE_UNLOAD");
michael@0 1639 _ASSIGN_eventName(NS_HASHCHANGE,"NS_HASHCHANGE");
michael@0 1640 _ASSIGN_eventName(NS_READYSTATECHANGE,"NS_READYSTATECHANGE");
michael@0 1641 _ASSIGN_eventName(NS_XUL_BROADCAST, "NS_XUL_BROADCAST");
michael@0 1642 _ASSIGN_eventName(NS_XUL_COMMAND_UPDATE, "NS_XUL_COMMAND_UPDATE");
michael@0 1643
michael@0 1644 #undef _ASSIGN_eventName
michael@0 1645
michael@0 1646 default:
michael@0 1647 {
michael@0 1648 char buf[32];
michael@0 1649
michael@0 1650 sprintf(buf,"UNKNOWN: %d",aGuiEvent->message);
michael@0 1651
michael@0 1652 CopyASCIItoUTF16(buf, eventName);
michael@0 1653 }
michael@0 1654 break;
michael@0 1655 }
michael@0 1656
michael@0 1657 return nsAutoString(eventName);
michael@0 1658 }
michael@0 1659 //////////////////////////////////////////////////////////////
michael@0 1660 //
michael@0 1661 // Code to deal with paint and event debug prefs.
michael@0 1662 //
michael@0 1663 //////////////////////////////////////////////////////////////
michael@0 1664 struct PrefPair
michael@0 1665 {
michael@0 1666 const char * name;
michael@0 1667 bool value;
michael@0 1668 };
michael@0 1669
michael@0 1670 static PrefPair debug_PrefValues[] =
michael@0 1671 {
michael@0 1672 { "nglayout.debug.crossing_event_dumping", false },
michael@0 1673 { "nglayout.debug.event_dumping", false },
michael@0 1674 { "nglayout.debug.invalidate_dumping", false },
michael@0 1675 { "nglayout.debug.motion_event_dumping", false },
michael@0 1676 { "nglayout.debug.paint_dumping", false },
michael@0 1677 { "nglayout.debug.paint_flashing", false }
michael@0 1678 };
michael@0 1679
michael@0 1680 //////////////////////////////////////////////////////////////
michael@0 1681 bool
michael@0 1682 nsBaseWidget::debug_GetCachedBoolPref(const char * aPrefName)
michael@0 1683 {
michael@0 1684 NS_ASSERTION(nullptr != aPrefName,"cmon, pref name is null.");
michael@0 1685
michael@0 1686 for (uint32_t i = 0; i < ArrayLength(debug_PrefValues); i++)
michael@0 1687 {
michael@0 1688 if (strcmp(debug_PrefValues[i].name, aPrefName) == 0)
michael@0 1689 {
michael@0 1690 return debug_PrefValues[i].value;
michael@0 1691 }
michael@0 1692 }
michael@0 1693
michael@0 1694 return false;
michael@0 1695 }
michael@0 1696 //////////////////////////////////////////////////////////////
michael@0 1697 static void debug_SetCachedBoolPref(const char * aPrefName,bool aValue)
michael@0 1698 {
michael@0 1699 NS_ASSERTION(nullptr != aPrefName,"cmon, pref name is null.");
michael@0 1700
michael@0 1701 for (uint32_t i = 0; i < ArrayLength(debug_PrefValues); i++)
michael@0 1702 {
michael@0 1703 if (strcmp(debug_PrefValues[i].name, aPrefName) == 0)
michael@0 1704 {
michael@0 1705 debug_PrefValues[i].value = aValue;
michael@0 1706
michael@0 1707 return;
michael@0 1708 }
michael@0 1709 }
michael@0 1710
michael@0 1711 NS_ASSERTION(false, "cmon, this code is not reached dude.");
michael@0 1712 }
michael@0 1713
michael@0 1714 //////////////////////////////////////////////////////////////
michael@0 1715 class Debug_PrefObserver MOZ_FINAL : public nsIObserver {
michael@0 1716 public:
michael@0 1717 NS_DECL_ISUPPORTS
michael@0 1718 NS_DECL_NSIOBSERVER
michael@0 1719 };
michael@0 1720
michael@0 1721 NS_IMPL_ISUPPORTS(Debug_PrefObserver, nsIObserver)
michael@0 1722
michael@0 1723 NS_IMETHODIMP
michael@0 1724 Debug_PrefObserver::Observe(nsISupports* subject, const char* topic,
michael@0 1725 const char16_t* data)
michael@0 1726 {
michael@0 1727 NS_ConvertUTF16toUTF8 prefName(data);
michael@0 1728
michael@0 1729 bool value = Preferences::GetBool(prefName.get(), false);
michael@0 1730 debug_SetCachedBoolPref(prefName.get(), value);
michael@0 1731 return NS_OK;
michael@0 1732 }
michael@0 1733
michael@0 1734 //////////////////////////////////////////////////////////////
michael@0 1735 /* static */ void
michael@0 1736 debug_RegisterPrefCallbacks()
michael@0 1737 {
michael@0 1738 static bool once = true;
michael@0 1739
michael@0 1740 if (!once) {
michael@0 1741 return;
michael@0 1742 }
michael@0 1743
michael@0 1744 once = false;
michael@0 1745
michael@0 1746 nsCOMPtr<nsIObserver> obs(new Debug_PrefObserver());
michael@0 1747 for (uint32_t i = 0; i < ArrayLength(debug_PrefValues); i++) {
michael@0 1748 // Initialize the pref values
michael@0 1749 debug_PrefValues[i].value =
michael@0 1750 Preferences::GetBool(debug_PrefValues[i].name, false);
michael@0 1751
michael@0 1752 if (obs) {
michael@0 1753 // Register callbacks for when these change
michael@0 1754 Preferences::AddStrongObserver(obs, debug_PrefValues[i].name);
michael@0 1755 }
michael@0 1756 }
michael@0 1757 }
michael@0 1758 //////////////////////////////////////////////////////////////
michael@0 1759 static int32_t
michael@0 1760 _GetPrintCount()
michael@0 1761 {
michael@0 1762 static int32_t sCount = 0;
michael@0 1763
michael@0 1764 return ++sCount;
michael@0 1765 }
michael@0 1766 //////////////////////////////////////////////////////////////
michael@0 1767 /* static */ bool
michael@0 1768 nsBaseWidget::debug_WantPaintFlashing()
michael@0 1769 {
michael@0 1770 return debug_GetCachedBoolPref("nglayout.debug.paint_flashing");
michael@0 1771 }
michael@0 1772 //////////////////////////////////////////////////////////////
michael@0 1773 /* static */ void
michael@0 1774 nsBaseWidget::debug_DumpEvent(FILE * aFileOut,
michael@0 1775 nsIWidget * aWidget,
michael@0 1776 WidgetGUIEvent* aGuiEvent,
michael@0 1777 const nsAutoCString & aWidgetName,
michael@0 1778 int32_t aWindowID)
michael@0 1779 {
michael@0 1780 if (aGuiEvent->message == NS_MOUSE_MOVE)
michael@0 1781 {
michael@0 1782 if (!debug_GetCachedBoolPref("nglayout.debug.motion_event_dumping"))
michael@0 1783 return;
michael@0 1784 }
michael@0 1785
michael@0 1786 if (aGuiEvent->message == NS_MOUSE_ENTER ||
michael@0 1787 aGuiEvent->message == NS_MOUSE_EXIT)
michael@0 1788 {
michael@0 1789 if (!debug_GetCachedBoolPref("nglayout.debug.crossing_event_dumping"))
michael@0 1790 return;
michael@0 1791 }
michael@0 1792
michael@0 1793 if (!debug_GetCachedBoolPref("nglayout.debug.event_dumping"))
michael@0 1794 return;
michael@0 1795
michael@0 1796 NS_LossyConvertUTF16toASCII tempString(debug_GuiEventToString(aGuiEvent).get());
michael@0 1797
michael@0 1798 fprintf(aFileOut,
michael@0 1799 "%4d %-26s widget=%-8p name=%-12s id=0x%-6x refpt=%d,%d\n",
michael@0 1800 _GetPrintCount(),
michael@0 1801 tempString.get(),
michael@0 1802 (void *) aWidget,
michael@0 1803 aWidgetName.get(),
michael@0 1804 aWindowID,
michael@0 1805 aGuiEvent->refPoint.x,
michael@0 1806 aGuiEvent->refPoint.y);
michael@0 1807 }
michael@0 1808 //////////////////////////////////////////////////////////////
michael@0 1809 /* static */ void
michael@0 1810 nsBaseWidget::debug_DumpPaintEvent(FILE * aFileOut,
michael@0 1811 nsIWidget * aWidget,
michael@0 1812 const nsIntRegion & aRegion,
michael@0 1813 const nsAutoCString & aWidgetName,
michael@0 1814 int32_t aWindowID)
michael@0 1815 {
michael@0 1816 NS_ASSERTION(nullptr != aFileOut,"cmon, null output FILE");
michael@0 1817 NS_ASSERTION(nullptr != aWidget,"cmon, the widget is null");
michael@0 1818
michael@0 1819 if (!debug_GetCachedBoolPref("nglayout.debug.paint_dumping"))
michael@0 1820 return;
michael@0 1821
michael@0 1822 nsIntRect rect = aRegion.GetBounds();
michael@0 1823 fprintf(aFileOut,
michael@0 1824 "%4d PAINT widget=%p name=%-12s id=0x%-6x bounds-rect=%3d,%-3d %3d,%-3d",
michael@0 1825 _GetPrintCount(),
michael@0 1826 (void *) aWidget,
michael@0 1827 aWidgetName.get(),
michael@0 1828 aWindowID,
michael@0 1829 rect.x, rect.y, rect.width, rect.height
michael@0 1830 );
michael@0 1831
michael@0 1832 fprintf(aFileOut,"\n");
michael@0 1833 }
michael@0 1834 //////////////////////////////////////////////////////////////
michael@0 1835 /* static */ void
michael@0 1836 nsBaseWidget::debug_DumpInvalidate(FILE * aFileOut,
michael@0 1837 nsIWidget * aWidget,
michael@0 1838 const nsIntRect * aRect,
michael@0 1839 const nsAutoCString & aWidgetName,
michael@0 1840 int32_t aWindowID)
michael@0 1841 {
michael@0 1842 if (!debug_GetCachedBoolPref("nglayout.debug.invalidate_dumping"))
michael@0 1843 return;
michael@0 1844
michael@0 1845 NS_ASSERTION(nullptr != aFileOut,"cmon, null output FILE");
michael@0 1846 NS_ASSERTION(nullptr != aWidget,"cmon, the widget is null");
michael@0 1847
michael@0 1848 fprintf(aFileOut,
michael@0 1849 "%4d Invalidate widget=%p name=%-12s id=0x%-6x",
michael@0 1850 _GetPrintCount(),
michael@0 1851 (void *) aWidget,
michael@0 1852 aWidgetName.get(),
michael@0 1853 aWindowID);
michael@0 1854
michael@0 1855 if (aRect)
michael@0 1856 {
michael@0 1857 fprintf(aFileOut,
michael@0 1858 " rect=%3d,%-3d %3d,%-3d",
michael@0 1859 aRect->x,
michael@0 1860 aRect->y,
michael@0 1861 aRect->width,
michael@0 1862 aRect->height);
michael@0 1863 }
michael@0 1864 else
michael@0 1865 {
michael@0 1866 fprintf(aFileOut,
michael@0 1867 " rect=%-15s",
michael@0 1868 "none");
michael@0 1869 }
michael@0 1870
michael@0 1871 fprintf(aFileOut,"\n");
michael@0 1872 }
michael@0 1873 //////////////////////////////////////////////////////////////
michael@0 1874
michael@0 1875 #endif // DEBUG
michael@0 1876

mercurial