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