Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim:set ts=2 sts=2 sw=2 et cin: */
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
/*
8
* nsWindow - Native window management and event handling.
9
*
10
* nsWindow is organized into a set of major blocks and
11
* block subsections. The layout is as follows:
12
*
13
* Includes
14
* Variables
15
* nsIWidget impl.
16
* nsIWidget methods and utilities
17
* nsSwitchToUIThread impl.
18
* nsSwitchToUIThread methods and utilities
19
* Moz events
20
* Event initialization
21
* Event dispatching
22
* Native events
23
* Wndproc(s)
24
* Event processing
25
* OnEvent event handlers
26
* IME management and accessibility
27
* Transparency
28
* Popup hook handling
29
* Misc. utilities
30
* Child window impl.
31
*
32
* Search for "BLOCK:" to find major blocks.
33
* Search for "SECTION:" to find specific sections.
34
*
35
* Blocks should be split out into separate files if they
36
* become unmanageable.
37
*
38
* Related source:
39
*
40
* nsWindowDefs.h - Definitions, macros, structs, enums
41
* and general setup.
42
* nsWindowDbg.h/.cpp - Debug related code and directives.
43
* nsWindowGfx.h/.cpp - Graphics and painting.
44
*
45
*/
46
47
/**************************************************************
48
**************************************************************
49
**
50
** BLOCK: Includes
51
**
52
** Include headers.
53
**
54
**************************************************************
55
**************************************************************/
56
57
#include "gfx2DGlue.h"
58
#include "gfxEnv.h"
59
#include "gfxPlatform.h"
60
61
#include "mozilla/AutoRestore.h"
62
#include "mozilla/Logging.h"
63
#include "mozilla/MathAlgorithms.h"
64
#include "mozilla/MiscEvents.h"
65
#include "mozilla/MouseEvents.h"
66
#include "mozilla/TouchEvents.h"
67
68
#include "mozilla/ipc/MessageChannel.h"
69
#include <algorithm>
70
#include <limits>
71
72
#include "nsWindow.h"
73
#include "nsAppRunner.h"
74
75
#include <shellapi.h>
76
#include <windows.h>
77
#include <wtsapi32.h>
78
#include <process.h>
79
#include <commctrl.h>
80
#include <dbt.h>
81
#include <unknwn.h>
82
#include <psapi.h>
83
84
#include "mozilla/Logging.h"
85
#include "prtime.h"
86
#include "prenv.h"
87
88
#include "mozilla/WidgetTraceEvent.h"
89
#include "nsISupportsPrimitives.h"
90
#include "nsIKeyEventInPluginCallback.h"
91
#include "nsITheme.h"
92
#include "nsIObserverService.h"
93
#include "nsIScreenManager.h"
94
#include "imgIContainer.h"
95
#include "nsIFile.h"
96
#include "nsIRollupListener.h"
97
#include "nsIClipboard.h"
98
#include "WinMouseScrollHandler.h"
99
#include "nsFontMetrics.h"
100
#include "nsIFontEnumerator.h"
101
#include "nsFont.h"
102
#include "nsRect.h"
103
#include "nsThreadUtils.h"
104
#include "nsNativeCharsetUtils.h"
105
#include "nsGkAtoms.h"
106
#include "nsCRT.h"
107
#include "nsAppDirectoryServiceDefs.h"
108
#include "nsWidgetsCID.h"
109
#include "nsTHashtable.h"
110
#include "nsHashKeys.h"
111
#include "nsString.h"
112
#include "mozilla/Services.h"
113
#include "nsNativeThemeWin.h"
114
#include "nsWindowsDllInterceptor.h"
115
#include "nsLayoutUtils.h"
116
#include "nsView.h"
117
#include "nsWindowGfx.h"
118
#include "gfxWindowsPlatform.h"
119
#include "gfxDWriteFonts.h"
120
#include "Layers.h"
121
#include "nsPrintfCString.h"
122
#include "mozilla/Preferences.h"
123
#include "SystemTimeConverter.h"
124
#include "WinTaskbar.h"
125
#include "WidgetUtils.h"
126
#include "nsIWidgetListener.h"
127
#include "mozilla/dom/MouseEventBinding.h"
128
#include "mozilla/dom/Touch.h"
129
#include "mozilla/gfx/2D.h"
130
#include "mozilla/gfx/GPUProcessManager.h"
131
#include "mozilla/WindowsVersion.h"
132
#include "mozilla/TextEvents.h" // For WidgetKeyboardEvent
133
#include "mozilla/TextEventDispatcherListener.h"
134
#include "mozilla/widget/nsAutoRollup.h"
135
#include "mozilla/widget/WinNativeEventData.h"
136
#include "mozilla/widget/PlatformWidgetTypes.h"
137
#include "nsStyleConsts.h"
138
#include "nsBidiKeyboard.h"
139
#include "nsStyleConsts.h"
140
#include "gfxConfig.h"
141
#include "InProcessWinCompositorWidget.h"
142
#include "InputDeviceUtils.h"
143
#include "ScreenHelperWin.h"
144
#include "mozilla/StaticPrefs_layout.h"
145
146
#include "nsIGfxInfo.h"
147
#include "nsUXThemeConstants.h"
148
#include "KeyboardLayout.h"
149
#include "nsNativeDragTarget.h"
150
#include <mmsystem.h> // needed for WIN32_LEAN_AND_MEAN
151
#include <zmouse.h>
152
#include <richedit.h>
153
154
#if defined(ACCESSIBILITY)
155
156
# ifdef DEBUG
157
# include "mozilla/a11y/Logging.h"
158
# endif
159
160
# include "oleidl.h"
161
# include <winuser.h>
162
# include "nsAccessibilityService.h"
163
# include "mozilla/PresShell.h"
164
# include "mozilla/a11y/DocAccessible.h"
165
# include "mozilla/a11y/LazyInstantiator.h"
166
# include "mozilla/a11y/Platform.h"
167
# if !defined(WINABLEAPI)
168
# include <winable.h>
169
# endif // !defined(WINABLEAPI)
170
#endif // defined(ACCESSIBILITY)
171
172
#include "nsIWinTaskbar.h"
173
#define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
174
175
#include "nsIWindowsUIUtils.h"
176
177
#include "nsWindowDefs.h"
178
179
#include "nsCrashOnException.h"
180
181
#include "nsIContent.h"
182
183
#include "mozilla/BackgroundHangMonitor.h"
184
#include "WinIMEHandler.h"
185
186
#include "npapi.h"
187
188
#include <d3d11.h>
189
190
#include "InkCollector.h"
191
192
// ERROR from wingdi.h (below) gets undefined by some code.
193
// #define ERROR 0
194
// #define RGN_ERROR ERROR
195
#define ERROR 0
196
197
#if !defined(SM_CONVERTIBLESLATEMODE)
198
# define SM_CONVERTIBLESLATEMODE 0x2003
199
#endif
200
201
#if !defined(WM_DPICHANGED)
202
# define WM_DPICHANGED 0x02E0
203
#endif
204
205
#include "mozilla/gfx/DeviceManagerDx.h"
206
#include "mozilla/layers/InputAPZContext.h"
207
#include "mozilla/layers/KnowsCompositor.h"
208
#include "InputData.h"
209
210
#include "mozilla/Telemetry.h"
211
#include "mozilla/plugins/PluginProcessParent.h"
212
#include "mozilla/webrender/WebRenderAPI.h"
213
214
using namespace mozilla;
215
using namespace mozilla::dom;
216
using namespace mozilla::gfx;
217
using namespace mozilla::layers;
218
using namespace mozilla::widget;
219
using namespace mozilla::plugins;
220
221
/**************************************************************
222
**************************************************************
223
**
224
** BLOCK: Variables
225
**
226
** nsWindow Class static initializations and global variables.
227
**
228
**************************************************************
229
**************************************************************/
230
231
/**************************************************************
232
*
233
* SECTION: nsWindow statics
234
*
235
**************************************************************/
236
237
bool nsWindow::sDropShadowEnabled = true;
238
uint32_t nsWindow::sInstanceCount = 0;
239
bool nsWindow::sSwitchKeyboardLayout = false;
240
BOOL nsWindow::sIsOleInitialized = FALSE;
241
HCURSOR nsWindow::sHCursor = nullptr;
242
imgIContainer* nsWindow::sCursorImgContainer = nullptr;
243
nsWindow* nsWindow::sCurrentWindow = nullptr;
244
bool nsWindow::sJustGotDeactivate = false;
245
bool nsWindow::sJustGotActivate = false;
246
bool nsWindow::sIsInMouseCapture = false;
247
248
// imported in nsWidgetFactory.cpp
249
TriStateBool nsWindow::sCanQuit = TRI_UNKNOWN;
250
251
// Hook Data Memebers for Dropdowns. sProcessHook Tells the
252
// hook methods whether they should be processing the hook
253
// messages.
254
HHOOK nsWindow::sMsgFilterHook = nullptr;
255
HHOOK nsWindow::sCallProcHook = nullptr;
256
HHOOK nsWindow::sCallMouseHook = nullptr;
257
bool nsWindow::sProcessHook = false;
258
UINT nsWindow::sRollupMsgId = 0;
259
HWND nsWindow::sRollupMsgWnd = nullptr;
260
UINT nsWindow::sHookTimerId = 0;
261
262
// Mouse Clicks - static variable definitions for figuring
263
// out 1 - 3 Clicks.
264
POINT nsWindow::sLastMousePoint = {0};
265
POINT nsWindow::sLastMouseMovePoint = {0};
266
LONG nsWindow::sLastMouseDownTime = 0L;
267
LONG nsWindow::sLastClickCount = 0L;
268
BYTE nsWindow::sLastMouseButton = 0;
269
270
bool nsWindow::sHaveInitializedPrefs = false;
271
272
TriStateBool nsWindow::sHasBogusPopupsDropShadowOnMultiMonitor = TRI_UNKNOWN;
273
274
static SystemTimeConverter<DWORD>& TimeConverter() {
275
static SystemTimeConverter<DWORD> timeConverterSingleton;
276
return timeConverterSingleton;
277
}
278
279
namespace mozilla {
280
281
class CurrentWindowsTimeGetter {
282
public:
283
explicit CurrentWindowsTimeGetter(HWND aWnd) : mWnd(aWnd) {}
284
285
DWORD GetCurrentTime() const { return ::GetTickCount(); }
286
287
void GetTimeAsyncForPossibleBackwardsSkew(const TimeStamp& aNow) {
288
DWORD currentTime = GetCurrentTime();
289
if (sBackwardsSkewStamp && currentTime == sLastPostTime) {
290
// There's already one inflight with this timestamp. Don't
291
// send a duplicate.
292
return;
293
}
294
sBackwardsSkewStamp = Some(aNow);
295
sLastPostTime = currentTime;
296
static_assert(sizeof(WPARAM) >= sizeof(DWORD),
297
"Can't fit a DWORD in a WPARAM");
298
::PostMessage(mWnd, MOZ_WM_SKEWFIX, sLastPostTime, 0);
299
}
300
301
static bool GetAndClearBackwardsSkewStamp(DWORD aPostTime,
302
TimeStamp* aOutSkewStamp) {
303
if (aPostTime != sLastPostTime) {
304
// The SKEWFIX message is stale; we've sent a new one since then.
305
// Ignore this one.
306
return false;
307
}
308
MOZ_ASSERT(sBackwardsSkewStamp);
309
*aOutSkewStamp = sBackwardsSkewStamp.value();
310
sBackwardsSkewStamp = Nothing();
311
return true;
312
}
313
314
private:
315
static Maybe<TimeStamp> sBackwardsSkewStamp;
316
static DWORD sLastPostTime;
317
HWND mWnd;
318
};
319
320
Maybe<TimeStamp> CurrentWindowsTimeGetter::sBackwardsSkewStamp;
321
DWORD CurrentWindowsTimeGetter::sLastPostTime = 0;
322
323
} // namespace mozilla
324
325
/**************************************************************
326
*
327
* SECTION: globals variables
328
*
329
**************************************************************/
330
331
static const char* sScreenManagerContractID =
332
"@mozilla.org/gfx/screenmanager;1";
333
334
extern mozilla::LazyLogModule gWindowsLog;
335
336
// Global used in Show window enumerations.
337
static bool gWindowsVisible = false;
338
339
// True if we have sent a notification that we are suspending/sleeping.
340
static bool gIsSleepMode = false;
341
342
static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
343
344
// General purpose user32.dll hook object
345
static WindowsDllInterceptor sUser32Intercept;
346
347
// 2 pixel offset for eTransparencyBorderlessGlass which equals the size of
348
// the default window border Windows paints. Glass will be extended inward
349
// this distance to remove the border.
350
static const int32_t kGlassMarginAdjustment = 2;
351
352
// When the client area is extended out into the default window frame area,
353
// this is the minimum amount of space along the edge of resizable windows
354
// we will always display a resize cursor in, regardless of the underlying
355
// content.
356
static const int32_t kResizableBorderMinSize = 3;
357
358
// We should never really try to accelerate windows bigger than this. In some
359
// cases this might lead to no D3D9 acceleration where we could have had it
360
// but D3D9 does not reliably report when it supports bigger windows. 8192
361
// is as safe as we can get, we know at least D3D10 hardware always supports
362
// this, other hardware we expect to report correctly in D3D9.
363
#define MAX_ACCELERATED_DIMENSION 8192
364
365
// On window open (as well as after), Windows has an unfortunate habit of
366
// sending rather a lot of WM_NCHITTEST messages. Because we have to do point
367
// to DOM target conversions for these, we cache responses for a given
368
// coordinate this many milliseconds:
369
#define HITTEST_CACHE_LIFETIME_MS 50
370
371
#if defined(ACCESSIBILITY)
372
373
namespace mozilla {
374
375
/**
376
* Windows touchscreen code works by setting a global WH_GETMESSAGE hook and
377
* injecting tiptsf.dll. The touchscreen process then posts registered messages
378
* to our main thread. The tiptsf hook picks up those registered messages and
379
* uses them as commands, some of which call into UIA, which then calls into
380
* MSAA, which then sends WM_GETOBJECT to us.
381
*
382
* We can get ahead of this by installing our own thread-local WH_GETMESSAGE
383
* hook. Since thread-local hooks are called ahead of global hooks, we will
384
* see these registered messages before tiptsf does. At this point we can then
385
* raise a flag that blocks a11y before invoking CallNextHookEx which will then
386
* invoke the global tiptsf hook. Then when we see WM_GETOBJECT, we check the
387
* flag by calling TIPMessageHandler::IsA11yBlocked().
388
*
389
* For Windows 8, we also hook tiptsf!ProcessCaretEvents, which is an a11y hook
390
* function that also calls into UIA.
391
*/
392
class TIPMessageHandler {
393
public:
394
~TIPMessageHandler() {
395
if (mHook) {
396
::UnhookWindowsHookEx(mHook);
397
}
398
}
399
400
static void Initialize() {
401
if (!IsWin8OrLater()) {
402
return;
403
}
404
405
if (sInstance) {
406
return;
407
}
408
409
sInstance = new TIPMessageHandler();
410
ClearOnShutdown(&sInstance);
411
}
412
413
static bool IsA11yBlocked() {
414
if (!sInstance) {
415
return false;
416
}
417
418
return sInstance->mA11yBlockCount > 0;
419
}
420
421
private:
422
TIPMessageHandler() : mHook(nullptr), mA11yBlockCount(0) {
423
MOZ_ASSERT(NS_IsMainThread());
424
425
// Registered messages used by tiptsf
426
mMessages[0] = ::RegisterWindowMessage(L"ImmersiveFocusNotification");
427
mMessages[1] = ::RegisterWindowMessage(L"TipCloseMenus");
428
mMessages[2] = ::RegisterWindowMessage(L"TabletInputPanelOpening");
429
mMessages[3] = ::RegisterWindowMessage(L"IHM Pen or Touch Event noticed");
430
mMessages[4] = ::RegisterWindowMessage(L"ProgrammabilityCaretVisibility");
431
mMessages[5] = ::RegisterWindowMessage(L"CaretTrackingUpdateIPHidden");
432
mMessages[6] = ::RegisterWindowMessage(L"CaretTrackingUpdateIPInfo");
433
434
mHook = ::SetWindowsHookEx(WH_GETMESSAGE, &TIPHook, nullptr,
435
::GetCurrentThreadId());
436
MOZ_ASSERT(mHook);
437
438
// On touchscreen devices, tiptsf.dll will have been loaded when STA COM was
439
// first initialized.
440
if (!IsWin10OrLater() && GetModuleHandle(L"tiptsf.dll") &&
441
!sProcessCaretEventsStub) {
442
sTipTsfInterceptor.Init("tiptsf.dll");
443
DebugOnly<bool> ok = sProcessCaretEventsStub.Set(
444
sTipTsfInterceptor, "ProcessCaretEvents", &ProcessCaretEventsHook);
445
MOZ_ASSERT(ok);
446
}
447
448
if (!sSendMessageTimeoutWStub) {
449
sUser32Intercept.Init("user32.dll");
450
DebugOnly<bool> hooked = sSendMessageTimeoutWStub.Set(
451
sUser32Intercept, "SendMessageTimeoutW", &SendMessageTimeoutWHook);
452
MOZ_ASSERT(hooked);
453
}
454
}
455
456
class MOZ_RAII A11yInstantiationBlocker {
457
public:
458
A11yInstantiationBlocker() {
459
if (!TIPMessageHandler::sInstance) {
460
return;
461
}
462
++TIPMessageHandler::sInstance->mA11yBlockCount;
463
}
464
465
~A11yInstantiationBlocker() {
466
if (!TIPMessageHandler::sInstance) {
467
return;
468
}
469
MOZ_ASSERT(TIPMessageHandler::sInstance->mA11yBlockCount > 0);
470
--TIPMessageHandler::sInstance->mA11yBlockCount;
471
}
472
};
473
474
friend class A11yInstantiationBlocker;
475
476
static LRESULT CALLBACK TIPHook(int aCode, WPARAM aWParam, LPARAM aLParam) {
477
if (aCode < 0 || !sInstance) {
478
return ::CallNextHookEx(nullptr, aCode, aWParam, aLParam);
479
}
480
481
MSG* msg = reinterpret_cast<MSG*>(aLParam);
482
UINT& msgCode = msg->message;
483
484
for (uint32_t i = 0; i < ArrayLength(sInstance->mMessages); ++i) {
485
if (msgCode == sInstance->mMessages[i]) {
486
A11yInstantiationBlocker block;
487
return ::CallNextHookEx(nullptr, aCode, aWParam, aLParam);
488
}
489
}
490
491
return ::CallNextHookEx(nullptr, aCode, aWParam, aLParam);
492
}
493
494
static void CALLBACK ProcessCaretEventsHook(HWINEVENTHOOK aWinEventHook,
495
DWORD aEvent, HWND aHwnd,
496
LONG aObjectId, LONG aChildId,
497
DWORD aGeneratingTid,
498
DWORD aEventTime) {
499
A11yInstantiationBlocker block;
500
sProcessCaretEventsStub(aWinEventHook, aEvent, aHwnd, aObjectId, aChildId,
501
aGeneratingTid, aEventTime);
502
}
503
504
static LRESULT WINAPI SendMessageTimeoutWHook(HWND aHwnd, UINT aMsgCode,
505
WPARAM aWParam, LPARAM aLParam,
506
UINT aFlags, UINT aTimeout,
507
PDWORD_PTR aMsgResult) {
508
// We don't want to handle this unless the message is a WM_GETOBJECT that we
509
// want to block, and the aHwnd is a nsWindow that belongs to the current
510
// thread.
511
if (!aMsgResult || aMsgCode != WM_GETOBJECT ||
512
static_cast<DWORD>(aLParam) != OBJID_CLIENT ||
513
!WinUtils::GetNSWindowPtr(aHwnd) ||
514
::GetWindowThreadProcessId(aHwnd, nullptr) != ::GetCurrentThreadId() ||
515
!IsA11yBlocked()) {
516
return sSendMessageTimeoutWStub(aHwnd, aMsgCode, aWParam, aLParam, aFlags,
517
aTimeout, aMsgResult);
518
}
519
520
// In this case we want to fake the result that would happen if we had
521
// decided not to handle WM_GETOBJECT in our WndProc. We hand the message
522
// off to DefWindowProc to accomplish this.
523
*aMsgResult = static_cast<DWORD_PTR>(
524
::DefWindowProcW(aHwnd, aMsgCode, aWParam, aLParam));
525
526
return static_cast<LRESULT>(TRUE);
527
}
528
529
static WindowsDllInterceptor sTipTsfInterceptor;
530
static WindowsDllInterceptor::FuncHookType<WINEVENTPROC>
531
sProcessCaretEventsStub;
532
static WindowsDllInterceptor::FuncHookType<decltype(&SendMessageTimeoutW)>
533
sSendMessageTimeoutWStub;
534
static StaticAutoPtr<TIPMessageHandler> sInstance;
535
536
HHOOK mHook;
537
UINT mMessages[7];
538
uint32_t mA11yBlockCount;
539
};
540
541
WindowsDllInterceptor TIPMessageHandler::sTipTsfInterceptor;
542
WindowsDllInterceptor::FuncHookType<WINEVENTPROC>
543
TIPMessageHandler::sProcessCaretEventsStub;
544
WindowsDllInterceptor::FuncHookType<decltype(&SendMessageTimeoutW)>
545
TIPMessageHandler::sSendMessageTimeoutWStub;
546
StaticAutoPtr<TIPMessageHandler> TIPMessageHandler::sInstance;
547
548
} // namespace mozilla
549
550
#endif // defined(ACCESSIBILITY)
551
552
/**************************************************************
553
**************************************************************
554
**
555
** BLOCK: nsIWidget impl.
556
**
557
** nsIWidget interface implementation, broken down into
558
** sections.
559
**
560
**************************************************************
561
**************************************************************/
562
563
/**************************************************************
564
*
565
* SECTION: nsWindow construction and destruction
566
*
567
**************************************************************/
568
569
nsWindow::nsWindow(bool aIsChildWindow)
570
: nsWindowBase(),
571
mResizeState(NOT_RESIZING),
572
mIsChildWindow(aIsChildWindow) {
573
mIconSmall = nullptr;
574
mIconBig = nullptr;
575
mWnd = nullptr;
576
mTransitionWnd = nullptr;
577
mPaintDC = nullptr;
578
mPrevWndProc = nullptr;
579
mNativeDragTarget = nullptr;
580
mDeviceNotifyHandle = nullptr;
581
mInDtor = false;
582
mIsVisible = false;
583
mIsTopWidgetWindow = false;
584
mUnicodeWidget = true;
585
mDisplayPanFeedback = false;
586
mTouchWindow = false;
587
mFutureMarginsToUse = false;
588
mCustomNonClient = false;
589
mHideChrome = false;
590
mFullscreenMode = false;
591
mMousePresent = false;
592
mMouseInDraggableArea = false;
593
mDestroyCalled = false;
594
mIsEarlyBlankWindow = false;
595
mHasTaskbarIconBeenCreated = false;
596
mMouseTransparent = false;
597
mPickerDisplayCount = 0;
598
mWindowType = eWindowType_child;
599
mBorderStyle = eBorderStyle_default;
600
mOldSizeMode = nsSizeMode_Normal;
601
mLastSizeMode = nsSizeMode_Normal;
602
mLastSize.width = 0;
603
mLastSize.height = 0;
604
mOldStyle = 0;
605
mOldExStyle = 0;
606
mPainting = 0;
607
mLastKeyboardLayout = 0;
608
mBlurSuppressLevel = 0;
609
mLastPaintEndTime = TimeStamp::Now();
610
mCachedHitTestPoint.x = 0;
611
mCachedHitTestPoint.y = 0;
612
mCachedHitTestTime = TimeStamp::Now();
613
mCachedHitTestResult = 0;
614
#ifdef MOZ_XUL
615
mTransparencyMode = eTransparencyOpaque;
616
memset(&mGlassMargins, 0, sizeof mGlassMargins);
617
#endif
618
DWORD background = ::GetSysColor(COLOR_BTNFACE);
619
mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(background));
620
mSendingSetText = false;
621
mDefaultScale = -1.0; // not yet set, will be calculated on first use
622
mAspectRatio = 0.0; // not yet set, will be calculated on first use
623
624
mTaskbarPreview = nullptr;
625
626
mCompositorWidgetDelegate = nullptr;
627
628
// Global initialization
629
if (!sInstanceCount) {
630
// Global app registration id for Win7 and up. See
631
// WinTaskbar.cpp for details.
632
mozilla::widget::WinTaskbar::RegisterAppUserModelID();
633
KeyboardLayout::GetInstance()->OnLayoutChange(::GetKeyboardLayout(0));
634
#if defined(ACCESSIBILITY)
635
mozilla::TIPMessageHandler::Initialize();
636
#endif // defined(ACCESSIBILITY)
637
if (SUCCEEDED(::OleInitialize(nullptr))) {
638
sIsOleInitialized = TRUE;
639
}
640
NS_ASSERTION(sIsOleInitialized, "***** OLE is not initialized!\n");
641
MouseScrollHandler::Initialize();
642
// Init theme data
643
nsUXThemeData::UpdateNativeThemeInfo();
644
RedirectedKeyDownMessageManager::Forget();
645
if (mPointerEvents.ShouldEnableInkCollector()) {
646
InkCollector::sInkCollector = new InkCollector();
647
}
648
} // !sInstanceCount
649
650
mIdleService = nullptr;
651
652
mSizeConstraintsScale = GetDefaultScale().scale;
653
mMaxTextureSize = -1; // Will be calculated when layer manager is created.
654
655
mRequestFxrOutputPending = false;
656
657
sInstanceCount++;
658
}
659
660
nsWindow::~nsWindow() {
661
mInDtor = true;
662
663
// If the widget was released without calling Destroy() then the native window
664
// still exists, and we need to destroy it. Destroy() will early-return if it
665
// was already called. In any case it is important to call it before
666
// destroying mPresentLock (cf. 1156182).
667
Destroy();
668
669
// Free app icon resources. This must happen after `OnDestroy` (see bug
670
// 708033).
671
if (mIconSmall) ::DestroyIcon(mIconSmall);
672
673
if (mIconBig) ::DestroyIcon(mIconBig);
674
675
sInstanceCount--;
676
677
// Global shutdown
678
if (sInstanceCount == 0) {
679
if (InkCollector::sInkCollector) {
680
InkCollector::sInkCollector->Shutdown();
681
InkCollector::sInkCollector = nullptr;
682
}
683
IMEHandler::Terminate();
684
NS_IF_RELEASE(sCursorImgContainer);
685
if (sIsOleInitialized) {
686
::OleFlushClipboard();
687
::OleUninitialize();
688
sIsOleInitialized = FALSE;
689
}
690
}
691
692
NS_IF_RELEASE(mNativeDragTarget);
693
}
694
695
/**************************************************************
696
*
697
* SECTION: nsIWidget::Create, nsIWidget::Destroy
698
*
699
* Creating and destroying windows for this widget.
700
*
701
**************************************************************/
702
703
// Allow Derived classes to modify the height that is passed
704
// when the window is created or resized.
705
int32_t nsWindow::GetHeight(int32_t aProposedHeight) { return aProposedHeight; }
706
707
static bool ShouldCacheTitleBarInfo(nsWindowType aWindowType,
708
nsBorderStyle aBorderStyle) {
709
return (aWindowType == eWindowType_toplevel) &&
710
(aBorderStyle == eBorderStyle_default ||
711
aBorderStyle == eBorderStyle_all) &&
712
(!nsUXThemeData::sTitlebarInfoPopulatedThemed ||
713
!nsUXThemeData::sTitlebarInfoPopulatedAero);
714
}
715
716
// Create the proper widget
717
nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
718
const LayoutDeviceIntRect& aRect,
719
nsWidgetInitData* aInitData) {
720
nsWidgetInitData defaultInitData;
721
if (!aInitData) aInitData = &defaultInitData;
722
723
mUnicodeWidget = aInitData->mUnicode;
724
725
nsIWidget* baseParent =
726
aInitData->mWindowType == eWindowType_dialog ||
727
aInitData->mWindowType == eWindowType_toplevel ||
728
aInitData->mWindowType == eWindowType_invisible
729
? nullptr
730
: aParent;
731
732
mIsTopWidgetWindow = (nullptr == baseParent);
733
mBounds = aRect;
734
735
// Ensure that the toolkit is created.
736
nsToolkit::GetToolkit();
737
738
BaseCreate(baseParent, aInitData);
739
740
HWND parent;
741
if (aParent) { // has a nsIWidget parent
742
parent = aParent ? (HWND)aParent->GetNativeData(NS_NATIVE_WINDOW) : nullptr;
743
mParent = aParent;
744
} else { // has a nsNative parent
745
parent = (HWND)aNativeParent;
746
mParent =
747
aNativeParent ? WinUtils::GetNSWindowPtr((HWND)aNativeParent) : nullptr;
748
}
749
750
mIsRTL = aInitData->mRTL;
751
mOpeningAnimationSuppressed = aInitData->mIsAnimationSuppressed;
752
mAlwaysOnTop = aInitData->mAlwaysOnTop;
753
754
DWORD style = WindowStyle();
755
DWORD extendedStyle = WindowExStyle();
756
757
if (mWindowType == eWindowType_popup) {
758
if (!aParent) {
759
parent = nullptr;
760
}
761
762
if (!IsWin8OrLater() && HasBogusPopupsDropShadowOnMultiMonitor() &&
763
ShouldUseOffMainThreadCompositing()) {
764
extendedStyle |= WS_EX_COMPOSITED;
765
}
766
767
if (aInitData->mMouseTransparent) {
768
// This flag makes the window transparent to mouse events
769
mMouseTransparent = true;
770
extendedStyle |= WS_EX_TRANSPARENT;
771
}
772
} else if (mWindowType == eWindowType_invisible) {
773
// Make sure CreateWindowEx succeeds at creating a toplevel window
774
style &= ~0x40000000; // WS_CHILDWINDOW
775
} else {
776
// See if the caller wants to explictly set clip children and clip siblings
777
if (aInitData->clipChildren) {
778
style |= WS_CLIPCHILDREN;
779
} else {
780
style &= ~WS_CLIPCHILDREN;
781
}
782
if (aInitData->clipSiblings) {
783
style |= WS_CLIPSIBLINGS;
784
}
785
}
786
787
const wchar_t* className;
788
if (aInitData->mDropShadow) {
789
className = GetWindowPopupClass();
790
} else {
791
className = GetWindowClass();
792
}
793
// Plugins are created in the disabled state so that they can't
794
// steal focus away from our main window. This is especially
795
// important if the plugin has loaded in a background tab.
796
if (aInitData->mWindowType == eWindowType_plugin ||
797
aInitData->mWindowType == eWindowType_plugin_ipc_chrome ||
798
aInitData->mWindowType == eWindowType_plugin_ipc_content) {
799
style |= WS_DISABLED;
800
}
801
mWnd = ::CreateWindowExW(extendedStyle, className, L"", style, aRect.X(),
802
aRect.Y(), aRect.Width(), GetHeight(aRect.Height()),
803
parent, nullptr, nsToolkit::mDllInstance, nullptr);
804
805
if (!mWnd) {
806
NS_WARNING("nsWindow CreateWindowEx failed.");
807
return NS_ERROR_FAILURE;
808
}
809
810
mDeviceNotifyHandle = InputDeviceUtils::RegisterNotification(mWnd);
811
812
// If mDefaultScale is set before mWnd has been set, it will have the scale of
813
// the primary monitor, rather than the monitor that the window is actually
814
// on. For non-popup windows this gets corrected by the WM_DPICHANGED message
815
// which resets mDefaultScale, but for popup windows we don't reset
816
// mDefaultScale on that message. In order to ensure that popup windows
817
// spawned on a non-primary monitor end up with the correct scale, we reset
818
// mDefaultScale here so that it gets recomputed using the correct monitor now
819
// that we have a mWnd.
820
mDefaultScale = -1.0;
821
822
if (mIsRTL) {
823
DWORD dwAttribute = TRUE;
824
DwmSetWindowAttribute(mWnd, DWMWA_NONCLIENT_RTL_LAYOUT, &dwAttribute,
825
sizeof dwAttribute);
826
}
827
828
if (mOpeningAnimationSuppressed) {
829
SuppressAnimation(true);
830
}
831
832
if (mAlwaysOnTop) {
833
::SetWindowPos(mWnd, HWND_TOPMOST, 0, 0, 0, 0,
834
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
835
}
836
837
if (!IsPlugin() && mWindowType != eWindowType_invisible &&
838
MouseScrollHandler::Device::IsFakeScrollableWindowNeeded()) {
839
// Ugly Thinkpad Driver Hack (Bugs 507222 and 594977)
840
//
841
// We create two zero-sized windows as descendants of the top-level window,
842
// like so:
843
//
844
// Top-level window (MozillaWindowClass)
845
// FAKETRACKPOINTSCROLLCONTAINER (MozillaWindowClass)
846
// FAKETRACKPOINTSCROLLABLE (MozillaWindowClass)
847
//
848
// We need to have the middle window, otherwise the Trackpoint driver
849
// will fail to deliver scroll messages. WM_MOUSEWHEEL messages are
850
// sent to the FAKETRACKPOINTSCROLLABLE, which then propagate up the
851
// window hierarchy until they are handled by nsWindow::WindowProc.
852
// WM_HSCROLL messages are also sent to the FAKETRACKPOINTSCROLLABLE,
853
// but these do not propagate automatically, so we have the window
854
// procedure pretend that they were dispatched to the top-level window
855
// instead.
856
//
857
// The FAKETRACKPOINTSCROLLABLE needs to have the specific window styles it
858
// is given below so that it catches the Trackpoint driver's heuristics.
859
HWND scrollContainerWnd = ::CreateWindowW(
860
className, L"FAKETRACKPOINTSCROLLCONTAINER", WS_CHILD | WS_VISIBLE, 0,
861
0, 0, 0, mWnd, nullptr, nsToolkit::mDllInstance, nullptr);
862
HWND scrollableWnd = ::CreateWindowW(
863
className, L"FAKETRACKPOINTSCROLLABLE",
864
WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP | 0x30, 0, 0, 0, 0,
865
scrollContainerWnd, nullptr, nsToolkit::mDllInstance, nullptr);
866
867
// Give the FAKETRACKPOINTSCROLLABLE window a specific ID so that
868
// WindowProcInternal can distinguish it from the top-level window
869
// easily.
870
::SetWindowLongPtrW(scrollableWnd, GWLP_ID, eFakeTrackPointScrollableID);
871
872
// Make FAKETRACKPOINTSCROLLABLE use nsWindow::WindowProc, and store the
873
// old window procedure in its "user data".
874
WNDPROC oldWndProc;
875
if (mUnicodeWidget)
876
oldWndProc = (WNDPROC)::SetWindowLongPtrW(scrollableWnd, GWLP_WNDPROC,
877
(LONG_PTR)nsWindow::WindowProc);
878
else
879
oldWndProc = (WNDPROC)::SetWindowLongPtrA(scrollableWnd, GWLP_WNDPROC,
880
(LONG_PTR)nsWindow::WindowProc);
881
::SetWindowLongPtrW(scrollableWnd, GWLP_USERDATA, (LONG_PTR)oldWndProc);
882
}
883
884
SubclassWindow(TRUE);
885
886
// Starting with Windows XP, a process always runs within a terminal services
887
// session. In order to play nicely with RDP, fast user switching, and the
888
// lock screen, we should be handling WM_WTSSESSION_CHANGE. We must register
889
// our HWND in order to receive this message.
890
DebugOnly<BOOL> wtsRegistered =
891
::WTSRegisterSessionNotification(mWnd, NOTIFY_FOR_THIS_SESSION);
892
NS_ASSERTION(wtsRegistered, "WTSRegisterSessionNotification failed!\n");
893
894
mDefaultIMC.Init(this);
895
IMEHandler::InitInputContext(this, mInputContext);
896
897
// Do some initialization work, but only if (a) it hasn't already been done,
898
// and (b) this is the hidden window (which is conveniently created before
899
// any visible windows but after the profile has been initialized).
900
if (!sHaveInitializedPrefs && mWindowType == eWindowType_invisible) {
901
sSwitchKeyboardLayout =
902
Preferences::GetBool("intl.keyboard.per_window_layout", false);
903
sHaveInitializedPrefs = true;
904
}
905
906
// Query for command button metric data for rendering the titlebar. We
907
// only do this once on the first window that has an actual titlebar
908
if (ShouldCacheTitleBarInfo(mWindowType, mBorderStyle)) {
909
nsUXThemeData::UpdateTitlebarInfo(mWnd);
910
}
911
912
static bool a11yPrimed = false;
913
if (!a11yPrimed && mWindowType == eWindowType_toplevel) {
914
a11yPrimed = true;
915
if (Preferences::GetInt("accessibility.force_disabled", 0) == -1) {
916
::PostMessage(mWnd, MOZ_WM_STARTA11Y, 0, 0);
917
}
918
}
919
return NS_OK;
920
}
921
922
// Close this nsWindow
923
void nsWindow::Destroy() {
924
// WM_DESTROY has already fired, avoid calling it twice
925
if (mOnDestroyCalled) return;
926
927
// Don't destroy windows that have file pickers open, we'll tear these down
928
// later once the picker is closed.
929
mDestroyCalled = true;
930
if (mPickerDisplayCount) return;
931
932
// During the destruction of all of our children, make sure we don't get
933
// deleted.
934
nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
935
936
/**
937
* On windows the LayerManagerOGL destructor wants the widget to be around for
938
* cleanup. It also would like to have the HWND intact, so we nullptr it here.
939
*/
940
DestroyLayerManager();
941
942
/* We should clear our cached resources now and not wait for the GC to
943
* delete the nsWindow. */
944
ClearCachedResources();
945
946
InputDeviceUtils::UnregisterNotification(mDeviceNotifyHandle);
947
mDeviceNotifyHandle = nullptr;
948
949
// The DestroyWindow function destroys the specified window. The function
950
// sends WM_DESTROY and WM_NCDESTROY messages to the window to deactivate it
951
// and remove the keyboard focus from it. The function also destroys the
952
// window's menu, flushes the thread message queue, destroys timers, removes
953
// clipboard ownership, and breaks the clipboard viewer chain (if the window
954
// is at the top of the viewer chain).
955
//
956
// If the specified window is a parent or owner window, DestroyWindow
957
// automatically destroys the associated child or owned windows when it
958
// destroys the parent or owner window. The function first destroys child or
959
// owned windows, and then it destroys the parent or owner window.
960
VERIFY(::DestroyWindow(mWnd));
961
962
// Our windows can be subclassed which may prevent us receiving WM_DESTROY. If
963
// OnDestroy() didn't get called, call it now.
964
if (false == mOnDestroyCalled) {
965
MSGResult msgResult;
966
mWindowHook.Notify(mWnd, WM_DESTROY, 0, 0, msgResult);
967
OnDestroy();
968
}
969
}
970
971
/**************************************************************
972
*
973
* SECTION: Window class utilities
974
*
975
* Utilities for calculating the proper window class name for
976
* Create window.
977
*
978
**************************************************************/
979
980
const wchar_t* nsWindow::RegisterWindowClass(const wchar_t* aClassName,
981
UINT aExtraStyle,
982
LPWSTR aIconID) const {
983
WNDCLASSW wc;
984
if (::GetClassInfoW(nsToolkit::mDllInstance, aClassName, &wc)) {
985
// already registered
986
return aClassName;
987
}
988
989
wc.style = CS_DBLCLKS | aExtraStyle;
990
wc.lpfnWndProc = WinUtils::NonClientDpiScalingDefWindowProcW;
991
wc.cbClsExtra = 0;
992
wc.cbWndExtra = 0;
993
wc.hInstance = nsToolkit::mDllInstance;
994
wc.hIcon =
995
aIconID ? ::LoadIconW(::GetModuleHandleW(nullptr), aIconID) : nullptr;
996
wc.hCursor = nullptr;
997
wc.hbrBackground = mBrush;
998
wc.lpszMenuName = nullptr;
999
wc.lpszClassName = aClassName;
1000
1001
if (!::RegisterClassW(&wc)) {
1002
// For older versions of Win32 (i.e., not XP), the registration may
1003
// fail with aExtraStyle, so we have to re-register without it.
1004
wc.style = CS_DBLCLKS;
1005
::RegisterClassW(&wc);
1006
}
1007
return aClassName;
1008
}
1009
1010
static LPWSTR const gStockApplicationIcon = MAKEINTRESOURCEW(32512);
1011
1012
// Return the proper window class for everything except popups.
1013
const wchar_t* nsWindow::GetWindowClass() const {
1014
switch (mWindowType) {
1015
case eWindowType_invisible:
1016
return RegisterWindowClass(kClassNameHidden, 0, gStockApplicationIcon);
1017
case eWindowType_dialog:
1018
return RegisterWindowClass(kClassNameDialog, 0, 0);
1019
default:
1020
return RegisterWindowClass(GetMainWindowClass(), 0,
1021
gStockApplicationIcon);
1022
}
1023
}
1024
1025
// Return the proper popup window class
1026
const wchar_t* nsWindow::GetWindowPopupClass() const {
1027
return RegisterWindowClass(kClassNameDropShadow, CS_XP_DROPSHADOW,
1028
gStockApplicationIcon);
1029
}
1030
1031
/**************************************************************
1032
*
1033
* SECTION: Window styles utilities
1034
*
1035
* Return the proper windows styles and extended styles.
1036
*
1037
**************************************************************/
1038
1039
// Return nsWindow styles
1040
DWORD nsWindow::WindowStyle() {
1041
DWORD style;
1042
1043
switch (mWindowType) {
1044
case eWindowType_plugin:
1045
case eWindowType_plugin_ipc_chrome:
1046
case eWindowType_plugin_ipc_content:
1047
case eWindowType_child:
1048
style = WS_OVERLAPPED;
1049
break;
1050
1051
case eWindowType_dialog:
1052
style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU | DS_3DLOOK |
1053
DS_MODALFRAME | WS_CLIPCHILDREN;
1054
if (mBorderStyle != eBorderStyle_default)
1055
style |= WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1056
break;
1057
1058
case eWindowType_popup:
1059
style = WS_POPUP;
1060
if (!HasGlass()) {
1061
style |= WS_OVERLAPPED;
1062
}
1063
break;
1064
1065
default:
1066
NS_ERROR("unknown border style");
1067
// fall through
1068
1069
case eWindowType_toplevel:
1070
case eWindowType_invisible:
1071
style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU |
1072
WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPCHILDREN;
1073
break;
1074
}
1075
1076
if (mBorderStyle != eBorderStyle_default &&
1077
mBorderStyle != eBorderStyle_all) {
1078
if (mBorderStyle == eBorderStyle_none ||
1079
!(mBorderStyle & eBorderStyle_border))
1080
style &= ~WS_BORDER;
1081
1082
if (mBorderStyle == eBorderStyle_none ||
1083
!(mBorderStyle & eBorderStyle_title)) {
1084
style &= ~WS_DLGFRAME;
1085
style |= WS_POPUP;
1086
style &= ~WS_CHILD;
1087
}
1088
1089
if (mBorderStyle == eBorderStyle_none ||
1090
!(mBorderStyle & eBorderStyle_close))
1091
style &= ~0;
1092
// XXX The close box can only be removed by changing the window class,
1093
// as far as I know --- roc+moz@cs.cmu.edu
1094
1095
if (mBorderStyle == eBorderStyle_none ||
1096
!(mBorderStyle & (eBorderStyle_menu | eBorderStyle_close)))
1097
style &= ~WS_SYSMENU;
1098
// Looks like getting rid of the system menu also does away with the
1099
// close box. So, we only get rid of the system menu if you want neither it
1100
// nor the close box. How does the Windows "Dialog" window class get just
1101
// closebox and no sysmenu? Who knows.
1102
1103
if (mBorderStyle == eBorderStyle_none ||
1104
!(mBorderStyle & eBorderStyle_resizeh))
1105
style &= ~WS_THICKFRAME;
1106
1107
if (mBorderStyle == eBorderStyle_none ||
1108
!(mBorderStyle & eBorderStyle_minimize))
1109
style &= ~WS_MINIMIZEBOX;
1110
1111
if (mBorderStyle == eBorderStyle_none ||
1112
!(mBorderStyle & eBorderStyle_maximize))
1113
style &= ~WS_MAXIMIZEBOX;
1114
1115
if (IsPopupWithTitleBar()) {
1116
style |= WS_CAPTION;
1117
if (mBorderStyle & eBorderStyle_close) {
1118
style |= WS_SYSMENU;
1119
}
1120
}
1121
}
1122
1123
if (mIsChildWindow) {
1124
style |= WS_CLIPCHILDREN;
1125
if (!(style & WS_POPUP)) {
1126
style |= WS_CHILD; // WS_POPUP and WS_CHILD are mutually exclusive.
1127
}
1128
}
1129
1130
VERIFY_WINDOW_STYLE(style);
1131
return style;
1132
}
1133
1134
// Return nsWindow extended styles
1135
DWORD nsWindow::WindowExStyle() {
1136
switch (mWindowType) {
1137
case eWindowType_plugin:
1138
case eWindowType_plugin_ipc_chrome:
1139
case eWindowType_plugin_ipc_content:
1140
case eWindowType_child:
1141
return 0;
1142
1143
case eWindowType_dialog:
1144
return WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME;
1145
1146
case eWindowType_popup: {
1147
DWORD extendedStyle = WS_EX_TOOLWINDOW;
1148
if (mPopupLevel == ePopupLevelTop) extendedStyle |= WS_EX_TOPMOST;
1149
return extendedStyle;
1150
}
1151
default:
1152
NS_ERROR("unknown border style");
1153
// fall through
1154
1155
case eWindowType_toplevel:
1156
case eWindowType_invisible:
1157
return WS_EX_WINDOWEDGE;
1158
}
1159
}
1160
1161
/**************************************************************
1162
*
1163
* SECTION: Window subclassing utilities
1164
*
1165
* Set or clear window subclasses on native windows. Used in
1166
* Create and Destroy.
1167
*
1168
**************************************************************/
1169
1170
// Subclass (or remove the subclass from) this component's nsWindow
1171
void nsWindow::SubclassWindow(BOOL bState) {
1172
if (bState) {
1173
if (!mWnd || !IsWindow(mWnd)) {
1174
NS_ERROR("Invalid window handle");
1175
}
1176
1177
if (mUnicodeWidget) {
1178
mPrevWndProc = reinterpret_cast<WNDPROC>(
1179
SetWindowLongPtrW(mWnd, GWLP_WNDPROC,
1180
reinterpret_cast<LONG_PTR>(nsWindow::WindowProc)));
1181
} else {
1182
mPrevWndProc = reinterpret_cast<WNDPROC>(
1183
SetWindowLongPtrA(mWnd, GWLP_WNDPROC,
1184
reinterpret_cast<LONG_PTR>(nsWindow::WindowProc)));
1185
}
1186
NS_ASSERTION(mPrevWndProc, "Null standard window procedure");
1187
// connect the this pointer to the nsWindow handle
1188
WinUtils::SetNSWindowBasePtr(mWnd, this);
1189
} else {
1190
if (IsWindow(mWnd)) {
1191
if (mUnicodeWidget) {
1192
SetWindowLongPtrW(mWnd, GWLP_WNDPROC,
1193
reinterpret_cast<LONG_PTR>(mPrevWndProc));
1194
} else {
1195
SetWindowLongPtrA(mWnd, GWLP_WNDPROC,
1196
reinterpret_cast<LONG_PTR>(mPrevWndProc));
1197
}
1198
}
1199
WinUtils::SetNSWindowBasePtr(mWnd, nullptr);
1200
mPrevWndProc = nullptr;
1201
}
1202
}
1203
1204
/**************************************************************
1205
*
1206
* SECTION: nsIWidget::SetParent, nsIWidget::GetParent
1207
*
1208
* Set or clear the parent widgets using window properties, and
1209
* handles calculating native parent handles.
1210
*
1211
**************************************************************/
1212
1213
// Get and set parent widgets
1214
void nsWindow::SetParent(nsIWidget* aNewParent) {
1215
nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
1216
nsIWidget* parent = GetParent();
1217
if (parent) {
1218
parent->RemoveChild(this);
1219
}
1220
1221
mParent = aNewParent;
1222
1223
if (aNewParent) {
1224
ReparentNativeWidget(aNewParent);
1225
aNewParent->AddChild(this);
1226
return;
1227
}
1228
if (mWnd) {
1229
// If we have no parent, SetParent should return the desktop.
1230
VERIFY(::SetParent(mWnd, nullptr));
1231
}
1232
}
1233
1234
void nsWindow::ReparentNativeWidget(nsIWidget* aNewParent) {
1235
MOZ_ASSERT(aNewParent, "null widget");
1236
1237
mParent = aNewParent;
1238
if (mWindowType == eWindowType_popup) {
1239
return;
1240
}
1241
HWND newParent = (HWND)aNewParent->GetNativeData(NS_NATIVE_WINDOW);
1242
NS_ASSERTION(newParent, "Parent widget has a null native window handle");
1243
if (newParent && mWnd) {
1244
::SetParent(mWnd, newParent);
1245
}
1246
}
1247
1248
nsIWidget* nsWindow::GetParent(void) {
1249
if (mIsTopWidgetWindow) {
1250
return nullptr;
1251
}
1252
if (mInDtor || mOnDestroyCalled) {
1253
return nullptr;
1254
}
1255
return mParent;
1256
}
1257
1258
static int32_t RoundDown(double aDouble) {
1259
return aDouble > 0 ? static_cast<int32_t>(floor(aDouble))
1260
: static_cast<int32_t>(ceil(aDouble));
1261
}
1262
1263
float nsWindow::GetDPI() {
1264
float dpi = 96.0f;
1265
nsCOMPtr<nsIScreen> screen = GetWidgetScreen();
1266
if (screen) {
1267
screen->GetDpi(&dpi);
1268
}
1269
return dpi;
1270
}
1271
1272
double nsWindow::GetDefaultScaleInternal() {
1273
if (mDefaultScale <= 0.0) {
1274
mDefaultScale = WinUtils::LogToPhysFactor(mWnd);
1275
}
1276
return mDefaultScale;
1277
}
1278
1279
int32_t nsWindow::LogToPhys(double aValue) {
1280
return WinUtils::LogToPhys(
1281
::MonitorFromWindow(mWnd, MONITOR_DEFAULTTOPRIMARY), aValue);
1282
}
1283
1284
nsWindow* nsWindow::GetParentWindow(bool aIncludeOwner) {
1285
return static_cast<nsWindow*>(GetParentWindowBase(aIncludeOwner));
1286
}
1287
1288
nsWindowBase* nsWindow::GetParentWindowBase(bool aIncludeOwner) {
1289
if (mIsTopWidgetWindow) {
1290
// Must use a flag instead of mWindowType to tell if the window is the
1291
// owned by the topmost widget, because a child window can be embedded
1292
// inside a HWND which is not associated with a nsIWidget.
1293
return nullptr;
1294
}
1295
1296
// If this widget has already been destroyed, pretend we have no parent.
1297
// This corresponds to code in Destroy which removes the destroyed
1298
// widget from its parent's child list.
1299
if (mInDtor || mOnDestroyCalled) return nullptr;
1300
1301
// aIncludeOwner set to true implies walking the parent chain to retrieve the
1302
// root owner. aIncludeOwner set to false implies the search will stop at the
1303
// true parent (default).
1304
nsWindow* widget = nullptr;
1305
if (mWnd) {
1306
HWND parent = nullptr;
1307
if (aIncludeOwner)
1308
parent = ::GetParent(mWnd);
1309
else
1310
parent = ::GetAncestor(mWnd, GA_PARENT);
1311
1312
if (parent) {
1313
widget = WinUtils::GetNSWindowPtr(parent);
1314
if (widget) {
1315
// If the widget is in the process of being destroyed then
1316
// do NOT return it
1317
if (widget->mInDtor) {
1318
widget = nullptr;
1319
}
1320
}
1321
}
1322
}
1323
1324
return static_cast<nsWindowBase*>(widget);
1325
}
1326
1327
BOOL CALLBACK nsWindow::EnumAllChildWindProc(HWND aWnd, LPARAM aParam) {
1328
nsWindow* wnd = WinUtils::GetNSWindowPtr(aWnd);
1329
if (wnd) {
1330
reinterpret_cast<nsTArray<nsWindow*>*>(aParam)->AppendElement(wnd);
1331
}
1332
return TRUE;
1333
}
1334
1335
BOOL CALLBACK nsWindow::EnumAllThreadWindowProc(HWND aWnd, LPARAM aParam) {
1336
nsWindow* wnd = WinUtils::GetNSWindowPtr(aWnd);
1337
if (wnd) {
1338
reinterpret_cast<nsTArray<nsWindow*>*>(aParam)->AppendElement(wnd);
1339
}
1340
EnumChildWindows(aWnd, EnumAllChildWindProc, aParam);
1341
return TRUE;
1342
}
1343
1344
/* static*/
1345
nsTArray<nsWindow*> nsWindow::EnumAllWindows() {
1346
nsTArray<nsWindow*> windows;
1347
EnumThreadWindows(GetCurrentThreadId(), EnumAllThreadWindowProc,
1348
reinterpret_cast<LPARAM>(&windows));
1349
return windows;
1350
}
1351
1352
static already_AddRefed<SourceSurface> CreateSourceSurfaceForGfxSurface(
1353
gfxASurface* aSurface) {
1354
MOZ_ASSERT(aSurface);
1355
return Factory::CreateSourceSurfaceForCairoSurface(
1356
aSurface->CairoSurface(), aSurface->GetSize(),
1357
aSurface->GetSurfaceFormat());
1358
}
1359
1360
nsWindow::ScrollSnapshot* nsWindow::EnsureSnapshotSurface(
1361
ScrollSnapshot& aSnapshotData, const mozilla::gfx::IntSize& aSize) {
1362
// If the surface doesn't exist or is the wrong size then create new one.
1363
if (!aSnapshotData.surface || aSnapshotData.surface->GetSize() != aSize) {
1364
aSnapshotData.surface = new gfxWindowsSurface(aSize, kScrollCaptureFormat);
1365
aSnapshotData.surfaceHasSnapshot = false;
1366
}
1367
1368
return &aSnapshotData;
1369
}
1370
1371
already_AddRefed<SourceSurface> nsWindow::CreateScrollSnapshot() {
1372
RECT clip = {0};
1373
int rgnType = ::GetWindowRgnBox(mWnd, &clip);
1374
if (rgnType == RGN_ERROR) {
1375
// We failed to get the clip assume that we need a full fallback.
1376
clip.left = 0;
1377
clip.top = 0;
1378
clip.right = mBounds.Width();
1379
clip.bottom = mBounds.Height();
1380
return GetFallbackScrollSnapshot(clip);
1381
}
1382
1383
// Check that the window is in a position to snapshot. We don't check for
1384
// clipped width as that doesn't currently matter for APZ scrolling.
1385
if (clip.top || clip.bottom != mBounds.Height()) {
1386
return GetFallbackScrollSnapshot(clip);
1387
}
1388
1389
HDC windowDC = ::GetDC(mWnd);
1390
if (!windowDC) {
1391
return GetFallbackScrollSnapshot(clip);
1392
}
1393
auto releaseDC = MakeScopeExit([&] { ::ReleaseDC(mWnd, windowDC); });
1394
1395
gfx::IntSize snapshotSize(mBounds.Width(), mBounds.Height());
1396
ScrollSnapshot* snapshot;
1397
if (clip.left || clip.right != mBounds.Width()) {
1398
// Can't do a full snapshot, so use the partial snapshot.
1399
snapshot = EnsureSnapshotSurface(mPartialSnapshot, snapshotSize);
1400
} else {
1401
snapshot = EnsureSnapshotSurface(mFullSnapshot, snapshotSize);
1402
}
1403
1404
// Note that we know that the clip is full height.
1405
if (!::BitBlt(snapshot->surface->GetDC(), clip.left, 0,
1406
clip.right - clip.left, clip.bottom, windowDC, clip.left, 0,
1407
SRCCOPY)) {
1408
return GetFallbackScrollSnapshot(clip);
1409
}
1410
::GdiFlush();
1411
snapshot->surface->Flush();
1412
snapshot->surfaceHasSnapshot = true;
1413
snapshot->clip = clip;
1414
mCurrentSnapshot = snapshot;
1415
1416
return CreateSourceSurfaceForGfxSurface(mCurrentSnapshot->surface);
1417
}
1418
1419
already_AddRefed<SourceSurface> nsWindow::GetFallbackScrollSnapshot(
1420
const RECT& aRequiredClip) {
1421
gfx::IntSize snapshotSize(mBounds.Width(), mBounds.Height());
1422
1423
// If the current snapshot is the correct size and covers the required clip,
1424
// just keep that by returning null.
1425
// Note: we know the clip is always full height.
1426
if (mCurrentSnapshot &&
1427
mCurrentSnapshot->surface->GetSize() == snapshotSize &&
1428
mCurrentSnapshot->clip.left <= aRequiredClip.left &&
1429
mCurrentSnapshot->clip.right >= aRequiredClip.right) {
1430
return nullptr;
1431
}
1432
1433
// Otherwise we'll use the full snapshot, making sure it is big enough first.
1434
mCurrentSnapshot = EnsureSnapshotSurface(mFullSnapshot, snapshotSize);
1435
1436
// If there is no snapshot, create a default.
1437
if (!mCurrentSnapshot->surfaceHasSnapshot) {
1438
gfx::SurfaceFormat format = mCurrentSnapshot->surface->GetSurfaceFormat();
1439
RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForCairoSurface(
1440
mCurrentSnapshot->surface->CairoSurface(),
1441
mCurrentSnapshot->surface->GetSize(), &format);
1442
1443
DefaultFillScrollCapture(dt);
1444
}
1445
1446
return CreateSourceSurfaceForGfxSurface(mCurrentSnapshot->surface);
1447
}
1448
1449
/**************************************************************
1450
*
1451
* SECTION: nsIWidget::Show
1452
*
1453
* Hide or show this component.
1454
*
1455
**************************************************************/
1456
1457
void nsWindow::Show(bool bState) {
1458
if (mWindowType == eWindowType_popup) {
1459
// See bug 603793. When we try to draw D3D9/10 windows with a drop shadow
1460
// without the DWM on a secondary monitor, windows fails to composite
1461
// our windows correctly. We therefor switch off the drop shadow for
1462
// pop-up windows when the DWM is disabled and two monitors are
1463
// connected.
1464
if (HasBogusPopupsDropShadowOnMultiMonitor() &&
1465
WinUtils::GetMonitorCount() > 1 &&
1466
!nsUXThemeData::CheckForCompositor()) {
1467
if (sDropShadowEnabled) {
1468
::SetClassLongA(mWnd, GCL_STYLE, 0);
1469
sDropShadowEnabled = false;
1470
}
1471
} else {
1472
if (!sDropShadowEnabled) {
1473
::SetClassLongA(mWnd, GCL_STYLE, CS_DROPSHADOW);
1474
sDropShadowEnabled = true;
1475
}
1476
}
1477
1478
// WS_EX_COMPOSITED conflicts with the WS_EX_LAYERED style and causes
1479
// some popup menus to become invisible.
1480
LONG_PTR exStyle = ::GetWindowLongPtrW(mWnd, GWL_EXSTYLE);
1481
if (exStyle & WS_EX_LAYERED) {
1482
::SetWindowLongPtrW(mWnd, GWL_EXSTYLE, exStyle & ~WS_EX_COMPOSITED);
1483
}
1484
}
1485
1486
bool syncInvalidate = false;
1487
1488
bool wasVisible = mIsVisible;
1489
// Set the status now so that anyone asking during ShowWindow or
1490
// SetWindowPos would get the correct answer.
1491
mIsVisible = bState;
1492
1493
// We may have cached an out of date visible state. This can happen
1494
// when session restore sets the full screen mode.
1495
if (mIsVisible)
1496
mOldStyle |= WS_VISIBLE;
1497
else
1498
mOldStyle &= ~WS_VISIBLE;
1499
1500
if (!mIsVisible && wasVisible) {
1501
ClearCachedResources();
1502
}
1503
1504
if (mWnd) {
1505
if (bState) {
1506
if (!wasVisible && mWindowType == eWindowType_toplevel) {
1507
// speed up the initial paint after show for
1508
// top level windows:
1509
syncInvalidate = true;
1510
1511
// Set the cursor before showing the window to avoid the default wait
1512
// cursor.
1513
SetCursor(eCursor_standard, nullptr, 0, 0);
1514
1515
switch (mSizeMode) {
1516
case nsSizeMode_Fullscreen:
1517
::ShowWindow(mWnd, SW_SHOW);
1518
break;
1519
case nsSizeMode_Maximized:
1520
::ShowWindow(mWnd, SW_SHOWMAXIMIZED);
1521
break;
1522
case nsSizeMode_Minimized:
1523
::ShowWindow(mWnd, SW_SHOWMINIMIZED);
1524
break;
1525
default:
1526
if (CanTakeFocus()) {
1527
::ShowWindow(mWnd, SW_SHOWNORMAL);
1528
} else {
1529
::ShowWindow(mWnd, SW_SHOWNOACTIVATE);
1530
Unused << GetAttention(2);
1531
}
1532
break;
1533
}
1534
} else {
1535
DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW;
1536
if (wasVisible) flags |= SWP_NOZORDER;
1537
1538
if (mWindowType == eWindowType_popup) {
1539
// ensure popups are the topmost of the TOPMOST
1540
// layer. Remember not to set the SWP_NOZORDER
1541
// flag as that might allow the taskbar to overlap
1542
// the popup.
1543
flags |= SWP_NOACTIVATE;
1544
HWND owner = ::GetWindow(mWnd, GW_OWNER);
1545
::SetWindowPos(mWnd, owner ? 0 : HWND_TOPMOST, 0, 0, 0, 0, flags);
1546
} else {
1547
if (mWindowType == eWindowType_dialog && !CanTakeFocus())
1548
flags |= SWP_NOACTIVATE;
1549
1550
::SetWindowPos(mWnd, HWND_TOP, 0, 0, 0, 0, flags);
1551
}
1552
}
1553
1554
if (!wasVisible && (mWindowType == eWindowType_toplevel ||
1555
mWindowType == eWindowType_dialog)) {
1556
// when a toplevel window or dialog is shown, initialize the UI state
1557
::SendMessageW(
1558
mWnd, WM_CHANGEUISTATE,
1559
MAKEWPARAM(UIS_INITIALIZE, UISF_HIDEFOCUS | UISF_HIDEACCEL), 0);
1560
}
1561
} else {
1562
// Clear contents to avoid ghosting of old content if we display
1563
// this window again.
1564
if (wasVisible && mTransparencyMode == eTransparencyTransparent) {
1565
if (mCompositorWidgetDelegate) {
1566
mCompositorWidgetDelegate->ClearTransparentWindow();
1567
}
1568
}
1569
if (mWindowType != eWindowType_dialog) {
1570
::ShowWindow(mWnd, SW_HIDE);
1571
} else {
1572
::SetWindowPos(mWnd, 0, 0, 0, 0, 0,
1573
SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER |
1574
SWP_NOACTIVATE);
1575
}
1576
}
1577
}
1578
1579
#ifdef MOZ_XUL
1580
if (!wasVisible && bState) {
1581
Invalidate();
1582
if (syncInvalidate && !mInDtor && !mOnDestroyCalled) {
1583
::UpdateWindow(mWnd);
1584
}
1585
}
1586
#endif
1587
1588
if (mOpeningAnimationSuppressed) {
1589
SuppressAnimation(false);
1590
}
1591
}
1592
1593
/**************************************************************
1594
*
1595
* SECTION: nsIWidget::IsVisible
1596
*
1597
* Returns the visibility state.
1598
*
1599
**************************************************************/
1600
1601
// Return true if the whether the component is visible, false otherwise
1602
bool nsWindow::IsVisible() const { return mIsVisible; }
1603
1604
/**************************************************************
1605
*
1606
* SECTION: Window clipping utilities
1607
*
1608
* Used in Size and Move operations for setting the proper
1609
* window clipping regions for window transparency.
1610
*
1611
**************************************************************/
1612
1613
// XP and Vista visual styles sometimes require window clipping regions to be
1614
// applied for proper transparency. These routines are called on size and move
1615
// operations.
1616
// XXX this is apparently still needed in Windows 7 and later
1617
void nsWindow::ClearThemeRegion() {
1618
if (!HasGlass() &&
1619
(mWindowType == eWindowType_popup && !IsPopupWithTitleBar() &&
1620
(mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel))) {
1621
SetWindowRgn(mWnd, nullptr, false);
1622
}
1623
}
1624
1625
void nsWindow::SetThemeRegion() {
1626
// Popup types that have a visual styles region applied (bug 376408). This can
1627
// be expanded for other window types as needed. The regions are applied
1628
// generically to the base window so default constants are used for part and
1629
// state. At some point we might need part and state values from
1630
// nsNativeThemeWin's GetThemePartAndState, but currently windows that change
1631
// shape based on state haven't come up.
1632
if (!HasGlass() &&
1633
(mWindowType == eWindowType_popup && !IsPopupWithTitleBar() &&
1634
(mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel))) {
1635
HRGN hRgn = nullptr;
1636
RECT rect = {0, 0, mBounds.Width(), mBounds.Height()};
1637
1638
HDC dc = ::GetDC(mWnd);
1639
GetThemeBackgroundRegion(nsUXThemeData::GetTheme(eUXTooltip), dc,
1640
TTP_STANDARD, TS_NORMAL, &rect, &hRgn);
1641
if (hRgn) {
1642
if (!SetWindowRgn(mWnd, hRgn,
1643
false)) // do not delete or alter hRgn if accepted.
1644
DeleteObject(hRgn);
1645
}
1646
::ReleaseDC(mWnd, dc);
1647
}
1648
}
1649
1650
/**************************************************************
1651
*
1652
* SECTION: Touch and APZ-related functions
1653
*
1654
**************************************************************/
1655
1656
void nsWindow::RegisterTouchWindow() {
1657
mTouchWindow = true;
1658
::RegisterTouchWindow(mWnd, TWF_WANTPALM);
1659
::EnumChildWindows(mWnd, nsWindow::RegisterTouchForDescendants, 0);
1660
}
1661
1662
BOOL CALLBACK nsWindow::RegisterTouchForDescendants(HWND aWnd, LPARAM aMsg) {
1663
nsWindow* win = WinUtils::GetNSWindowPtr(aWnd);
1664
if (win) {
1665
::RegisterTouchWindow(aWnd, TWF_WANTPALM);
1666
}
1667
return TRUE;
1668
}
1669
1670
void nsWindow::LockAspectRatio(bool aShouldLock) {
1671
if (aShouldLock) {
1672
mAspectRatio = (float)mBounds.Height() / (float)mBounds.Width();
1673
} else {
1674
mAspectRatio = 0.0;
1675
}
1676
}
1677
1678
/**************************************************************
1679
*
1680
* SECTION: nsIWidget::SetWindowMouseTransparent
1681
*
1682
* Sets whether the window should ignore mouse events.
1683
*
1684
**************************************************************/
1685
void nsWindow::SetWindowMouseTransparent(bool aIsTransparent) {
1686
if (!mWnd) {
1687
return;
1688
}
1689
1690
LONG_PTR oldStyle = ::GetWindowLongPtrW(mWnd, GWL_EXSTYLE);
1691
LONG_PTR newStyle = aIsTransparent ? (oldStyle | WS_EX_TRANSPARENT)
1692
: (oldStyle & ~WS_EX_TRANSPARENT);
1693
::SetWindowLongPtrW(mWnd, GWL_EXSTYLE, newStyle);
1694
mMouseTransparent = aIsTransparent;
1695
}
1696
1697
/**************************************************************
1698
*
1699
* SECTION: nsIWidget::Move, nsIWidget::Resize,
1700
* nsIWidget::Size, nsIWidget::BeginResizeDrag
1701
*
1702
* Repositioning and sizing a window.
1703
*
1704
**************************************************************/
1705
1706
void nsWindow::SetSizeConstraints(const SizeConstraints& aConstraints) {
1707
SizeConstraints c = aConstraints;
1708
if (mWindowType != eWindowType_popup) {
1709
c.mMinSize.width =
1710
std::max(int32_t(::GetSystemMetrics(SM_CXMINTRACK)), c.mMinSize.width);
1711
c.mMinSize.height =
1712
std::max(int32_t(::GetSystemMetrics(SM_CYMINTRACK)), c.mMinSize.height);
1713
}
1714
1715
if (mMaxTextureSize > 0) {
1716
// We can't make ThebesLayers bigger than this anyway.. no point it letting
1717
// a window grow bigger as we won't be able to draw content there in
1718
// general.
1719
c.mMaxSize.width = std::min(c.mMaxSize.width, mMaxTextureSize);
1720
c.mMaxSize.height = std::min(c.mMaxSize.height, mMaxTextureSize);
1721
}
1722
1723
mSizeConstraintsScale = GetDefaultScale().scale;
1724
1725
nsBaseWidget::SetSizeConstraints(c);
1726
}
1727
1728
const SizeConstraints nsWindow::GetSizeConstraints() {
1729
double scale = GetDefaultScale().scale;
1730
if (mSizeConstraintsScale == scale || mSizeConstraintsScale == 0.0) {
1731
return mSizeConstraints;
1732
}
1733
scale /= mSizeConstraintsScale;
1734
SizeConstraints c = mSizeConstraints;
1735
if (c.mMinSize.width != NS_MAXSIZE) {
1736
c.mMinSize.width = NSToIntRound(c.mMinSize.width * scale);
1737
}
1738
if (c.mMinSize.height != NS_MAXSIZE) {
1739
c.mMinSize.height = NSToIntRound(c.mMinSize.height * scale);
1740
}
1741
if (c.mMaxSize.width != NS_MAXSIZE) {
1742
c.mMaxSize.width = NSToIntRound(c.mMaxSize.width * scale);
1743
}
1744
if (c.mMaxSize.height != NS_MAXSIZE) {
1745
c.mMaxSize.height = NSToIntRound(c.mMaxSize.height * scale);
1746
}
1747
return c;
1748
}
1749
1750
// Move this component
1751
void nsWindow::Move(double aX, double aY) {
1752
if (mWindowType == eWindowType_toplevel ||
1753
mWindowType == eWindowType_dialog) {
1754
SetSizeMode(nsSizeMode_Normal);
1755
}
1756
1757
// for top-level windows only, convert coordinates from desktop pixels
1758
// (the "parent" coordinate space) to the window's device pixel space
1759
double scale =
1760
BoundsUseDesktopPixels() ? GetDesktopToDeviceScale().scale : 1.0;
1761
int32_t x = NSToIntRound(aX * scale);
1762
int32_t y = NSToIntRound(aY * scale);
1763
1764
// Check to see if window needs to be moved first
1765
// to avoid a costly call to SetWindowPos. This check
1766
// can not be moved to the calling code in nsView, because
1767
// some platforms do not position child windows correctly
1768
1769
// Only perform this check for non-popup windows, since the positioning can
1770
// in fact change even when the x/y do not. We always need to perform the
1771
// check. See bug #97805 for details.
1772
if (mWindowType != eWindowType_popup && mBounds.IsEqualXY(x, y)) {
1773
// Nothing to do, since it is already positioned correctly.
1774
return;
1775
}
1776
1777
mBounds.MoveTo(x, y);
1778
1779
if (mWnd) {
1780
#ifdef DEBUG
1781
// complain if a window is moved offscreen (legal, but potentially
1782
// worrisome)
1783
if (mIsTopWidgetWindow) { // only a problem for top-level windows
1784
// Make sure this window is actually on the screen before we move it
1785
// XXX: Needs multiple monitor support
1786
HDC dc = ::GetDC(mWnd);
1787
if (dc) {
1788
if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
1789
RECT workArea;
1790
::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
1791
// no annoying assertions. just mention the issue.
1792
if (x < 0 || x >= workArea.right || y < 0 || y >= workArea.bottom) {
1793
MOZ_LOG(gWindowsLog, LogLevel::Info,
1794
("window moved to offscreen position\n"));
1795
}
1796
}
1797
::ReleaseDC(mWnd, dc);
1798
}
1799
}
1800
#endif
1801
ClearThemeRegion();
1802
1803
UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE;
1804
// Workaround SetWindowPos bug with D3D9. If our window has a clip
1805
// region, some drivers or OSes may incorrectly copy into the clipped-out
1806
// area.
1807
if (IsPlugin() && !mLayerManager && mClipRects &&
1808
(mClipRectCount != 1 ||
1809
!mClipRects[0].IsEqualInterior(
1810
LayoutDeviceIntRect(0, 0, mBounds.Width(), mBounds.Height())))) {
1811
flags |= SWP_NOCOPYBITS;
1812
}
1813
double oldScale = mDefaultScale;
1814
mResizeState = IN_SIZEMOVE;
1815
VERIFY(::SetWindowPos(mWnd, nullptr, x, y, 0, 0, flags));
1816
mResizeState = NOT_RESIZING;
1817
if (WinUtils::LogToPhysFactor(mWnd) != oldScale) {
1818
ChangedDPI();
1819
}
1820
1821
SetThemeRegion();
1822
}
1823
NotifyRollupGeometryChange();
1824
}
1825
1826
// Resize this component
1827
void nsWindow::Resize(double aWidth, double aHeight, bool aRepaint) {
1828
// for top-level windows only, convert coordinates from desktop pixels
1829
// (the "parent" coordinate space) to the window's device pixel space
1830
double scale =
1831
BoundsUseDesktopPixels() ? GetDesktopToDeviceScale().scale : 1.0;
1832
int32_t width = NSToIntRound(aWidth * scale);
1833
int32_t height = NSToIntRound(aHeight * scale);
1834
1835
NS_ASSERTION((width >= 0), "Negative width passed to nsWindow::Resize");
1836
NS_ASSERTION((height >= 0), "Negative height passed to nsWindow::Resize");
1837
1838
ConstrainSize(&width, &height);
1839
1840
// Avoid unnecessary resizing calls
1841
if (mBounds.IsEqualSize(width, height)) {
1842
if (aRepaint) {
1843
Invalidate();
1844
}
1845
return;
1846
}
1847
1848
// Set cached value for lightweight and printing
1849
mBounds.SizeTo(width, height);
1850
1851
if (mWnd) {
1852
UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE;
1853
1854
if (!aRepaint) {
1855
flags |= SWP_NOREDRAW;
1856
}
1857
1858
ClearThemeRegion();
1859
double oldScale = mDefaultScale;
1860
mResizeState = RESIZING;
1861
VERIFY(
1862
::SetWindowPos(mWnd, nullptr, 0, 0, width, GetHeight(height), flags));
1863
mResizeState = NOT_RESIZING;
1864
if (WinUtils::LogToPhysFactor(mWnd) != oldScale) {
1865
ChangedDPI();
1866
}
1867
SetThemeRegion();
1868
}
1869
1870
if (aRepaint) Invalidate();
1871
1872
NotifyRollupGeometryChange();
1873
}
1874
1875
// Resize this component
1876
void nsWindow::Resize(double aX, double aY, double aWidth, double aHeight,
1877
bool aRepaint) {
1878
// for top-level windows only, convert coordinates from desktop pixels
1879
// (the "parent" coordinate space) to the window's device pixel space
1880
double scale =
1881
BoundsUseDesktopPixels() ? GetDesktopToDeviceScale().scale : 1.0;
1882
int32_t x = NSToIntRound(aX * scale);
1883
int32_t y = NSToIntRound(aY * scale);
1884
int32_t width = NSToIntRound(aWidth * scale);
1885
int32_t height = NSToIntRound(aHeight * scale);
1886
1887
NS_ASSERTION((width >= 0), "Negative width passed to nsWindow::Resize");
1888
NS_ASSERTION((height >= 0), "Negative height passed to nsWindow::Resize");
1889
1890
ConstrainSize(&width, &height);
1891
1892
// Avoid unnecessary resizing calls
1893
if (mBounds.IsEqualRect(x, y, width, height)) {
1894
if (aRepaint) {
1895
Invalidate();
1896
}
1897
return;
1898
}
1899
1900
// Set cached value for lightweight and printing
1901
mBounds.SetRect(x, y, width, height);
1902
1903
if (mWnd) {
1904
UINT flags = SWP_NOZORDER | SWP_NOACTIVATE;
1905
if (!aRepaint) {
1906
flags |= SWP_NOREDRAW;
1907
}
1908
1909
ClearThemeRegion();
1910
double oldScale = mDefaultScale;
1911
mResizeState = RESIZING;
1912
VERIFY(
1913
::SetWindowPos(mWnd, nullptr, x, y, width, GetHeight(height), flags));
1914
mResizeState = NOT_RESIZING;
1915
if (WinUtils::LogToPhysFactor(mWnd) != oldScale) {
1916
ChangedDPI();
1917
}
1918
if (mTransitionWnd) {
1919
// If we have a fullscreen transition window, we need to make
1920
// it topmost again, otherwise the taskbar may be raised by
1921
// the system unexpectedly when we leave fullscreen state.
1922
::SetWindowPos(mTransitionWnd, HWND_TOPMOST, 0, 0, 0, 0,
1923
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
1924
}
1925
SetThemeRegion();
1926
}
1927
1928
if (aRepaint) Invalidate();
1929
1930
NotifyRollupGeometryChange();
1931
}
1932
1933
mozilla::Maybe<bool> nsWindow::IsResizingNativeWidget() {
1934
if (mResizeState == RESIZING) {
1935
return Some(true);
1936
}
1937
return Some(false);
1938
}
1939
1940
nsresult nsWindow::BeginResizeDrag(WidgetGUIEvent* aEvent, int32_t aHorizontal,
1941
int32_t aVertical) {
1942
NS_ENSURE_ARG_POINTER(aEvent);
1943
1944
if (aEvent->mClass != eMouseEventClass) {
1945
// you can only begin a resize drag with a mouse event
1946
return NS_ERROR_INVALID_ARG;