Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/xpfe/appshell/nsWindowMediator.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include "nsCOMPtr.h"
7
#include "nsString.h"
8
#include "nsReadableUtils.h"
9
#include "nsUnicharUtils.h"
10
#include "nsTArray.h"
11
#include "nsIBaseWindow.h"
12
#include "nsIWidget.h"
13
#include "nsIDOMWindow.h"
14
#include "nsIObserverService.h"
15
#include "nsIServiceManager.h"
16
#include "nsISimpleEnumerator.h"
17
#include "nsAppShellWindowEnumerator.h"
18
#include "nsWindowMediator.h"
19
#include "nsIWindowMediatorListener.h"
20
#include "nsGlobalWindow.h"
21
22
#include "nsIDocShell.h"
23
#include "nsIInterfaceRequestor.h"
24
#include "nsIInterfaceRequestorUtils.h"
25
#include "nsIXULWindow.h"
26
27
using namespace mozilla;
28
29
nsresult
30
nsWindowMediator::GetDOMWindow(nsIXULWindow* inWindow,
31
                               nsCOMPtr<nsPIDOMWindowOuter>& outDOMWindow)
32
0
{
33
0
  nsCOMPtr<nsIDocShell> docShell;
34
0
35
0
  outDOMWindow = nullptr;
36
0
  inWindow->GetDocShell(getter_AddRefs(docShell));
37
0
  NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
38
0
39
0
  outDOMWindow = docShell->GetWindow();
40
0
  return outDOMWindow ? NS_OK : NS_ERROR_FAILURE;
41
0
}
42
43
nsWindowMediator::nsWindowMediator() :
44
  mEnumeratorList(), mOldestWindow(nullptr), mTopmostWindow(nullptr),
45
  mTimeStamp(0), mSortingZOrder(false), mReady(false)
46
0
{
47
0
}
48
49
nsWindowMediator::~nsWindowMediator()
50
0
{
51
0
  while (mOldestWindow)
52
0
    UnregisterWindow(mOldestWindow);
53
0
}
54
55
nsresult nsWindowMediator::Init()
56
0
{
57
0
  nsresult rv;
58
0
  nsCOMPtr<nsIObserverService> obsSvc =
59
0
    do_GetService("@mozilla.org/observer-service;1", &rv);
60
0
  NS_ENSURE_SUCCESS(rv, rv);
61
0
  rv = obsSvc->AddObserver(this, "xpcom-shutdown", true);
62
0
  NS_ENSURE_SUCCESS(rv, rv);
63
0
64
0
  mReady = true;
65
0
  return NS_OK;
66
0
}
67
68
NS_IMETHODIMP nsWindowMediator::RegisterWindow(nsIXULWindow* inWindow)
69
0
{
70
0
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
71
0
  NS_ENSURE_STATE(mReady);
72
0
73
0
  if (GetInfoFor(inWindow)) {
74
0
    NS_ERROR("multiple window registration");
75
0
    return NS_ERROR_FAILURE;
76
0
  }
77
0
78
0
  mTimeStamp++;
79
0
80
0
  // Create window info struct and add to list of windows
81
0
  nsWindowInfo* windowInfo = new nsWindowInfo(inWindow, mTimeStamp);
82
0
83
0
  ListenerArray::ForwardIterator iter(mListeners);
84
0
  while (iter.HasMore()) {
85
0
    iter.GetNext()->OnOpenWindow(inWindow);
86
0
  }
87
0
88
0
  if (mOldestWindow)
89
0
    windowInfo->InsertAfter(mOldestWindow->mOlder, nullptr);
90
0
  else
91
0
    mOldestWindow = windowInfo;
92
0
93
0
  return NS_OK;
94
0
}
95
96
NS_IMETHODIMP
97
nsWindowMediator::UnregisterWindow(nsIXULWindow* inWindow)
98
0
{
99
0
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
100
0
  NS_ENSURE_STATE(mReady);
101
0
  nsWindowInfo *info = GetInfoFor(inWindow);
102
0
  if (info)
103
0
    return UnregisterWindow(info);
104
0
  return NS_ERROR_INVALID_ARG;
105
0
}
106
107
nsresult
108
nsWindowMediator::UnregisterWindow(nsWindowInfo *inInfo)
109
0
{
110
0
  // Inform the iterators
111
0
  uint32_t index = 0;
112
0
  while (index < mEnumeratorList.Length()) {
113
0
    mEnumeratorList[index]->WindowRemoved(inInfo);
114
0
    index++;
115
0
  }
116
0
117
0
  nsIXULWindow* window = inInfo->mWindow.get();
118
0
  ListenerArray::ForwardIterator iter(mListeners);
119
0
  while (iter.HasMore()) {
120
0
    iter.GetNext()->OnCloseWindow(window);
121
0
  }
122
0
123
0
  // Remove from the lists and free up
124
0
  if (inInfo == mOldestWindow)
125
0
    mOldestWindow = inInfo->mYounger;
126
0
  if (inInfo == mTopmostWindow)
127
0
    mTopmostWindow = inInfo->mLower;
128
0
  inInfo->Unlink(true, true);
129
0
  if (inInfo == mOldestWindow)
130
0
    mOldestWindow = nullptr;
131
0
  if (inInfo == mTopmostWindow)
132
0
    mTopmostWindow = nullptr;
133
0
  delete inInfo;
134
0
135
0
  return NS_OK;
136
0
}
137
138
nsWindowInfo*
139
nsWindowMediator::GetInfoFor(nsIXULWindow *aWindow)
140
0
{
141
0
  nsWindowInfo *info,
142
0
               *listEnd;
143
0
144
0
  if (!aWindow)
145
0
    return nullptr;
146
0
147
0
  info = mOldestWindow;
148
0
  listEnd = nullptr;
149
0
  while (info != listEnd) {
150
0
    if (info->mWindow.get() == aWindow)
151
0
      return info;
152
0
    info = info->mYounger;
153
0
    listEnd = mOldestWindow;
154
0
  }
155
0
  return nullptr;
156
0
}
157
158
nsWindowInfo*
159
nsWindowMediator::GetInfoFor(nsIWidget *aWindow)
160
0
{
161
0
  nsWindowInfo *info,
162
0
               *listEnd;
163
0
164
0
  if (!aWindow)
165
0
    return nullptr;
166
0
167
0
  info = mOldestWindow;
168
0
  listEnd = nullptr;
169
0
170
0
  nsCOMPtr<nsIWidget> scanWidget;
171
0
  while (info != listEnd) {
172
0
    nsCOMPtr<nsIBaseWindow> base(do_QueryInterface(info->mWindow));
173
0
    if (base)
174
0
      base->GetMainWidget(getter_AddRefs(scanWidget));
175
0
    if (aWindow == scanWidget.get())
176
0
      return info;
177
0
    info = info->mYounger;
178
0
    listEnd = mOldestWindow;
179
0
  }
180
0
  return nullptr;
181
0
}
182
183
NS_IMETHODIMP
184
nsWindowMediator::GetEnumerator(const char16_t* inType, nsISimpleEnumerator** outEnumerator)
185
0
{
186
0
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
187
0
  NS_ENSURE_ARG_POINTER(outEnumerator);
188
0
  NS_ENSURE_STATE(mReady);
189
0
190
0
  RefPtr<nsAppShellWindowEnumerator> enumerator = new nsASDOMWindowEarlyToLateEnumerator(inType, *this);
191
0
  enumerator.forget(outEnumerator);
192
0
  return NS_OK;
193
0
}
194
195
NS_IMETHODIMP
196
nsWindowMediator::GetXULWindowEnumerator(const char16_t* inType, nsISimpleEnumerator** outEnumerator)
197
0
{
198
0
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
199
0
  NS_ENSURE_ARG_POINTER(outEnumerator);
200
0
  NS_ENSURE_STATE(mReady);
201
0
202
0
  RefPtr<nsAppShellWindowEnumerator> enumerator = new nsASXULWindowEarlyToLateEnumerator(inType, *this);
203
0
  enumerator.forget(outEnumerator);
204
0
  return NS_OK;
205
0
}
206
207
NS_IMETHODIMP
208
nsWindowMediator::GetZOrderDOMWindowEnumerator(
209
            const char16_t *aWindowType, bool aFrontToBack,
210
            nsISimpleEnumerator **_retval)
211
0
{
212
0
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
213
0
  NS_ENSURE_ARG_POINTER(_retval);
214
0
  NS_ENSURE_STATE(mReady);
215
0
216
0
  RefPtr<nsAppShellWindowEnumerator> enumerator;
217
0
  if (aFrontToBack)
218
0
    enumerator = new nsASDOMWindowFrontToBackEnumerator(aWindowType, *this);
219
0
  else
220
0
    enumerator = new nsASDOMWindowBackToFrontEnumerator(aWindowType, *this);
221
0
222
0
  enumerator.forget(_retval);
223
0
  return NS_OK;
224
0
}
225
226
NS_IMETHODIMP
227
nsWindowMediator::GetZOrderXULWindowEnumerator(
228
            const char16_t *aWindowType, bool aFrontToBack,
229
            nsISimpleEnumerator **_retval)
230
0
{
231
0
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
232
0
  NS_ENSURE_ARG_POINTER(_retval);
233
0
  NS_ENSURE_STATE(mReady);
234
0
235
0
  RefPtr<nsAppShellWindowEnumerator> enumerator;
236
0
  if (aFrontToBack)
237
0
    enumerator = new nsASXULWindowFrontToBackEnumerator(aWindowType, *this);
238
0
  else
239
0
    enumerator = new nsASXULWindowBackToFrontEnumerator(aWindowType, *this);
240
0
241
0
  enumerator.forget(_retval);
242
0
  return NS_OK;
243
0
}
244
245
int32_t
246
nsWindowMediator::AddEnumerator(nsAppShellWindowEnumerator * inEnumerator)
247
0
{
248
0
  return mEnumeratorList.AppendElement(inEnumerator) != nullptr;
249
0
}
250
251
int32_t
252
nsWindowMediator::RemoveEnumerator(nsAppShellWindowEnumerator * inEnumerator)
253
0
{
254
0
  return mEnumeratorList.RemoveElement(inEnumerator);
255
0
}
256
257
// Returns the window of type inType ( if null return any window type ) which has the most recent
258
// time stamp
259
NS_IMETHODIMP
260
nsWindowMediator::GetMostRecentWindow(const char16_t* inType,
261
                                      mozIDOMWindowProxy** outWindow)
262
0
{
263
0
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
264
0
  NS_ENSURE_ARG_POINTER(outWindow);
265
0
  *outWindow = nullptr;
266
0
  if (!mReady)
267
0
    return NS_OK;
268
0
269
0
  // Find the most window with the highest time stamp that matches
270
0
  // the requested type
271
0
  nsWindowInfo* info = MostRecentWindowInfo(inType, false);
272
0
  if (info && info->mWindow) {
273
0
    nsCOMPtr<nsPIDOMWindowOuter> DOMWindow;
274
0
    if (NS_SUCCEEDED(GetDOMWindow(info->mWindow, DOMWindow))) {
275
0
      DOMWindow.forget(outWindow);
276
0
      return NS_OK;
277
0
    }
278
0
    return NS_ERROR_FAILURE;
279
0
  }
280
0
281
0
  return NS_OK;
282
0
}
283
284
NS_IMETHODIMP
285
nsWindowMediator::GetMostRecentNonPBWindow(const char16_t* aType, mozIDOMWindowProxy** aWindow)
286
0
{
287
0
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
288
0
  NS_ENSURE_ARG_POINTER(aWindow);
289
0
  *aWindow = nullptr;
290
0
291
0
  nsWindowInfo *info = MostRecentWindowInfo(aType, true);
292
0
  nsCOMPtr<nsPIDOMWindowOuter> domWindow;
293
0
  if (info && info->mWindow) {
294
0
    GetDOMWindow(info->mWindow, domWindow);
295
0
  }
296
0
297
0
  if (!domWindow) {
298
0
    return NS_ERROR_FAILURE;
299
0
  }
300
0
301
0
  domWindow.forget(aWindow);
302
0
  return NS_OK;
303
0
}
304
305
nsWindowInfo*
306
nsWindowMediator::MostRecentWindowInfo(const char16_t* inType,
307
                                       bool aSkipPrivateBrowsingOrClosed)
308
0
{
309
0
  int32_t       lastTimeStamp = -1;
310
0
  nsAutoString  typeString(inType);
311
0
  bool          allWindows = !inType || typeString.IsEmpty();
312
0
313
0
  // Find the most recent window with the highest time stamp that matches
314
0
  // the requested type and has the correct browsing mode.
315
0
  nsWindowInfo* searchInfo = mOldestWindow;
316
0
  nsWindowInfo* listEnd = nullptr;
317
0
  nsWindowInfo* foundInfo = nullptr;
318
0
  for (; searchInfo != listEnd; searchInfo = searchInfo->mYounger) {
319
0
    listEnd = mOldestWindow;
320
0
321
0
    if (!allWindows && !searchInfo->TypeEquals(typeString)) {
322
0
      continue;
323
0
    }
324
0
    if (searchInfo->mTimeStamp < lastTimeStamp) {
325
0
      continue;
326
0
    }
327
0
    if (!searchInfo->mWindow) {
328
0
      continue;
329
0
    }
330
0
    if (aSkipPrivateBrowsingOrClosed) {
331
0
      nsCOMPtr<nsIDocShell> docShell;
332
0
      searchInfo->mWindow->GetDocShell(getter_AddRefs(docShell));
333
0
      nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
334
0
      if (!loadContext || loadContext->UsePrivateBrowsing()) {
335
0
        continue;
336
0
      }
337
0
338
0
      nsCOMPtr<nsPIDOMWindowOuter> piwindow = docShell->GetWindow();
339
0
      if (!piwindow || piwindow->Closed()) {
340
0
        continue;
341
0
      }
342
0
    }
343
0
344
0
    foundInfo = searchInfo;
345
0
    lastTimeStamp = searchInfo->mTimeStamp;
346
0
  }
347
0
348
0
  return foundInfo;
349
0
}
350
351
NS_IMETHODIMP
352
nsWindowMediator::GetOuterWindowWithId(uint64_t aWindowID,
353
                                       mozIDOMWindowProxy** aWindow)
354
0
{
355
0
  RefPtr<nsGlobalWindowOuter> window = nsGlobalWindowOuter::GetOuterWindowWithId(aWindowID);
356
0
  nsCOMPtr<nsPIDOMWindowOuter> outer = window ? window->AsOuter() : nullptr;
357
0
  outer.forget(aWindow);
358
0
  return NS_OK;
359
0
}
360
361
NS_IMETHODIMP
362
nsWindowMediator::GetCurrentInnerWindowWithId(uint64_t aWindowID,
363
                                              mozIDOMWindow** aWindow)
364
0
{
365
0
  RefPtr<nsGlobalWindowInner> window = nsGlobalWindowInner::GetInnerWindowWithId(aWindowID);
366
0
367
0
  // not found
368
0
  if (!window)
369
0
    return NS_OK;
370
0
371
0
  nsCOMPtr<nsPIDOMWindowInner> inner = window->AsInner();
372
0
  nsCOMPtr<nsPIDOMWindowOuter> outer = inner->GetOuterWindow();
373
0
  NS_ENSURE_TRUE(outer, NS_ERROR_UNEXPECTED);
374
0
375
0
  // outer is already using another inner, so it's same as not found
376
0
  if (outer->GetCurrentInnerWindow() != inner)
377
0
    return NS_OK;
378
0
379
0
  inner.forget(aWindow);
380
0
  return NS_OK;
381
0
}
382
383
NS_IMETHODIMP
384
nsWindowMediator::UpdateWindowTimeStamp(nsIXULWindow* inWindow)
385
0
{
386
0
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
387
0
  NS_ENSURE_STATE(mReady);
388
0
  nsWindowInfo *info = GetInfoFor(inWindow);
389
0
  if (info) {
390
0
    // increment the window's time stamp
391
0
    info->mTimeStamp = ++mTimeStamp;
392
0
    return NS_OK;
393
0
  }
394
0
  return NS_ERROR_FAILURE;
395
0
}
396
397
/* This method's plan is to intervene only when absolutely necessary.
398
   We will get requests to place our windows behind unknown windows.
399
   For the most part, we need to leave those alone (turning them into
400
   explicit requests to be on top breaks Windows.) So generally we
401
   calculate a change as seldom as possible.
402
*/
403
NS_IMETHODIMP
404
nsWindowMediator::CalculateZPosition(
405
                nsIXULWindow   *inWindow,
406
                uint32_t        inPosition,
407
                nsIWidget      *inBelow,
408
                uint32_t       *outPosition,
409
                nsIWidget     **outBelow,
410
                bool           *outAltered)
411
0
{
412
0
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
413
0
  NS_ENSURE_ARG_POINTER(outBelow);
414
0
  NS_ENSURE_STATE(mReady);
415
0
416
0
  *outBelow = nullptr;
417
0
418
0
  if (!inWindow || !outPosition || !outAltered)
419
0
    return NS_ERROR_NULL_POINTER;
420
0
421
0
  if (inPosition != nsIWindowMediator::zLevelTop &&
422
0
      inPosition != nsIWindowMediator::zLevelBottom &&
423
0
      inPosition != nsIWindowMediator::zLevelBelow)
424
0
    return NS_ERROR_INVALID_ARG;
425
0
426
0
  nsWindowInfo *info = mTopmostWindow;
427
0
  nsIXULWindow *belowWindow = nullptr;
428
0
  bool          found = false;
429
0
  nsresult      result = NS_OK;
430
0
431
0
  *outPosition = inPosition;
432
0
  *outAltered = false;
433
0
434
0
  if (mSortingZOrder) { // don't fight SortZOrder()
435
0
    *outBelow = inBelow;
436
0
    NS_IF_ADDREF(*outBelow);
437
0
    return NS_OK;
438
0
  }
439
0
440
0
  uint32_t inZ;
441
0
  GetZLevel(inWindow, &inZ);
442
0
443
0
  if (inPosition == nsIWindowMediator::zLevelBelow) {
444
0
    // locate inBelow. use topmost if it can't be found or isn't in the
445
0
    // z-order list
446
0
    info = GetInfoFor(inBelow);
447
0
    if (!info || (info->mYounger != info && info->mLower == info))
448
0
      info = mTopmostWindow;
449
0
    else
450
0
      found = true;
451
0
452
0
    if (!found) {
453
0
      /* Treat unknown windows as a request to be on top.
454
0
         Not as it should be, but that's what Windows gives us.
455
0
         Note we change inPosition, but not *outPosition. This forces
456
0
         us to go through the "on top" calculation just below, without
457
0
         necessarily changing the output parameters. */
458
0
      inPosition = nsIWindowMediator::zLevelTop;
459
0
    }
460
0
  }
461
0
462
0
  if (inPosition == nsIWindowMediator::zLevelTop) {
463
0
    if (mTopmostWindow && mTopmostWindow->mZLevel > inZ) {
464
0
      // asked for topmost, can't have it. locate highest allowed position.
465
0
      do {
466
0
        if (info->mZLevel <= inZ)
467
0
          break;
468
0
        info = info->mLower;
469
0
      } while (info != mTopmostWindow);
470
0
471
0
      *outPosition = nsIWindowMediator::zLevelBelow;
472
0
      belowWindow = info->mHigher->mWindow;
473
0
      *outAltered = true;
474
0
    }
475
0
  } else if (inPosition == nsIWindowMediator::zLevelBottom) {
476
0
    if (mTopmostWindow && mTopmostWindow->mHigher->mZLevel < inZ) {
477
0
      // asked for bottommost, can't have it. locate lowest allowed position.
478
0
      do {
479
0
        info = info->mHigher;
480
0
        if (info->mZLevel >= inZ)
481
0
          break;
482
0
      } while (info != mTopmostWindow);
483
0
484
0
      *outPosition = nsIWindowMediator::zLevelBelow;
485
0
      belowWindow = info->mWindow;
486
0
      *outAltered = true;
487
0
    }
488
0
  } else {
489
0
    unsigned long relativeZ;
490
0
491
0
    // check that we're in the right z-plane
492
0
    if (found) {
493
0
      belowWindow = info->mWindow;
494
0
      relativeZ = info->mZLevel;
495
0
      if (relativeZ > inZ) {
496
0
        // might be OK. is lower window, if any, lower?
497
0
        if (info->mLower != info && info->mLower->mZLevel > inZ) {
498
0
          do {
499
0
            if (info->mZLevel <= inZ)
500
0
              break;
501
0
            info = info->mLower;
502
0
          } while (info != mTopmostWindow);
503
0
504
0
          belowWindow = info->mHigher->mWindow;
505
0
          *outAltered = true;
506
0
        }
507
0
      } else if (relativeZ < inZ) {
508
0
        // nope. look for a higher window to be behind.
509
0
        do {
510
0
          info = info->mHigher;
511
0
          if (info->mZLevel >= inZ)
512
0
            break;
513
0
        } while (info != mTopmostWindow);
514
0
515
0
        if (info->mZLevel >= inZ)
516
0
          belowWindow = info->mWindow;
517
0
        else
518
0
          *outPosition = nsIWindowMediator::zLevelTop;
519
0
        *outAltered = true;
520
0
      } // else they're equal, so it's OK
521
0
    }
522
0
  }
523
0
524
0
  if (NS_SUCCEEDED(result) && belowWindow) {
525
0
    nsCOMPtr<nsIBaseWindow> base(do_QueryInterface(belowWindow));
526
0
    if (base)
527
0
      base->GetMainWidget(outBelow);
528
0
    else
529
0
      result = NS_ERROR_NO_INTERFACE;
530
0
  }
531
0
532
0
  return result;
533
0
}
534
535
NS_IMETHODIMP
536
nsWindowMediator::SetZPosition(
537
                nsIXULWindow *inWindow,
538
                uint32_t      inPosition,
539
                nsIXULWindow *inBelow)
540
0
{
541
0
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
542
0
  nsWindowInfo *inInfo,
543
0
               *belowInfo;
544
0
545
0
  if ((inPosition != nsIWindowMediator::zLevelTop &&
546
0
       inPosition != nsIWindowMediator::zLevelBottom &&
547
0
       inPosition != nsIWindowMediator::zLevelBelow) ||
548
0
      !inWindow) {
549
0
    return NS_ERROR_INVALID_ARG;
550
0
  }
551
0
552
0
  if (mSortingZOrder) // don't fight SortZOrder()
553
0
    return NS_OK;
554
0
555
0
  NS_ENSURE_STATE(mReady);
556
0
557
0
  /* Locate inWindow and unlink it from the z-order list.
558
0
     It's important we look for it in the age list, not the z-order list.
559
0
     This is because the former is guaranteed complete, while
560
0
     now may be this window's first exposure to the latter. */
561
0
  inInfo = GetInfoFor(inWindow);
562
0
  if (!inInfo)
563
0
    return NS_ERROR_INVALID_ARG;
564
0
565
0
  // locate inBelow, place inWindow behind it
566
0
  if (inPosition == nsIWindowMediator::zLevelBelow) {
567
0
    belowInfo = GetInfoFor(inBelow);
568
0
    // it had better also be in the z-order list
569
0
    if (belowInfo &&
570
0
        belowInfo->mYounger != belowInfo && belowInfo->mLower == belowInfo) {
571
0
      belowInfo = nullptr;
572
0
    }
573
0
    if (!belowInfo) {
574
0
      if (inBelow)
575
0
        return NS_ERROR_INVALID_ARG;
576
0
      else
577
0
        inPosition = nsIWindowMediator::zLevelTop;
578
0
    }
579
0
  }
580
0
  if (inPosition == nsIWindowMediator::zLevelTop ||
581
0
      inPosition == nsIWindowMediator::zLevelBottom)
582
0
    belowInfo = mTopmostWindow ? mTopmostWindow->mHigher : nullptr;
583
0
584
0
  if (inInfo != belowInfo) {
585
0
    inInfo->Unlink(false, true);
586
0
    inInfo->InsertAfter(nullptr, belowInfo);
587
0
  }
588
0
  if (inPosition == nsIWindowMediator::zLevelTop)
589
0
    mTopmostWindow = inInfo;
590
0
591
0
  return NS_OK;
592
0
}
593
594
NS_IMETHODIMP
595
nsWindowMediator::GetZLevel(nsIXULWindow *aWindow, uint32_t *_retval)
596
0
{
597
0
  NS_ENSURE_ARG_POINTER(_retval);
598
0
  *_retval = nsIXULWindow::normalZ;
599
0
  // This can fail during window destruction.
600
0
  nsWindowInfo *info = GetInfoFor(aWindow);
601
0
  if (info) {
602
0
    *_retval = info->mZLevel;
603
0
  }
604
0
  return NS_OK;
605
0
}
606
607
NS_IMETHODIMP
608
nsWindowMediator::SetZLevel(nsIXULWindow *aWindow, uint32_t aZLevel)
609
0
{
610
0
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
611
0
  NS_ENSURE_STATE(mReady);
612
0
613
0
  nsWindowInfo *info = GetInfoFor(aWindow);
614
0
  NS_ASSERTION(info, "setting z level of unregistered window");
615
0
  if (!info)
616
0
    return NS_ERROR_FAILURE;
617
0
618
0
  if (info->mZLevel != aZLevel) {
619
0
    bool lowered = info->mZLevel > aZLevel;
620
0
    info->mZLevel = aZLevel;
621
0
    if (lowered)
622
0
      SortZOrderFrontToBack();
623
0
    else
624
0
      SortZOrderBackToFront();
625
0
  }
626
0
  return NS_OK;
627
0
}
628
629
/*   Fix potentially out-of-order windows by performing an insertion sort
630
   on the z-order list. The method will work no matter how broken the
631
   list, but its assumed usage is immediately after one window's z level
632
   has been changed, so one window is potentially out of place. Such a sort
633
   is most efficiently done in a particular direction. Use this one
634
   if a window's z level has just been reduced, so the sort is most efficiently
635
   done front to back.
636
     Note it's hardly worth going to all the trouble to write two versions
637
   of this method except that if we choose the inefficient sorting direction,
638
   on slow systems windows could visibly bubble around the window that
639
   was moved.
640
*/
641
void
642
nsWindowMediator::SortZOrderFrontToBack()
643
0
{
644
0
  nsWindowInfo *scan,   // scans list looking for problems
645
0
               *search, // searches for correct placement for scan window
646
0
               *prev,   // previous search element
647
0
               *lowest; // bottom-most window in list
648
0
  bool         finished;
649
0
650
0
  if (!mTopmostWindow) // early during program execution there's no z list yet
651
0
    return;            // there's also only one window, so this is not dangerous
652
0
653
0
  mSortingZOrder = true;
654
0
655
0
  /* Step through the list from top to bottom. If we find a window which
656
0
     should be moved down in the list, move it to its highest legal position. */
657
0
  do {
658
0
    finished = true;
659
0
    lowest = mTopmostWindow->mHigher;
660
0
    scan = mTopmostWindow;
661
0
    while (scan != lowest) {
662
0
      uint32_t scanZ = scan->mZLevel;
663
0
      if (scanZ < scan->mLower->mZLevel) { // out of order
664
0
        search = scan->mLower;
665
0
        do {
666
0
          prev = search;
667
0
          search = search->mLower;
668
0
        } while (prev != lowest && scanZ < search->mZLevel);
669
0
670
0
        // reposition |scan| within the list
671
0
        if (scan == mTopmostWindow)
672
0
          mTopmostWindow = scan->mLower;
673
0
        scan->Unlink(false, true);
674
0
        scan->InsertAfter(nullptr, prev);
675
0
676
0
        // fix actual window order
677
0
        nsCOMPtr<nsIBaseWindow> base;
678
0
        nsCOMPtr<nsIWidget> scanWidget;
679
0
        nsCOMPtr<nsIWidget> prevWidget;
680
0
        base = do_QueryInterface(scan->mWindow);
681
0
        if (base)
682
0
          base->GetMainWidget(getter_AddRefs(scanWidget));
683
0
        base = do_QueryInterface(prev->mWindow);
684
0
        if (base)
685
0
          base->GetMainWidget(getter_AddRefs(prevWidget));
686
0
        if (scanWidget)
687
0
          scanWidget->PlaceBehind(eZPlacementBelow, prevWidget, false);
688
0
689
0
        finished = false;
690
0
        break;
691
0
      }
692
0
      scan = scan->mLower;
693
0
    }
694
0
  } while (!finished);
695
0
696
0
  mSortingZOrder = false;
697
0
}
698
699
// see comment for SortZOrderFrontToBack
700
void
701
nsWindowMediator::SortZOrderBackToFront()
702
0
{
703
0
  nsWindowInfo *scan,   // scans list looking for problems
704
0
               *search, // searches for correct placement for scan window
705
0
               *lowest; // bottom-most window in list
706
0
  bool         finished;
707
0
708
0
  if (!mTopmostWindow) // early during program execution there's no z list yet
709
0
    return;            // there's also only one window, so this is not dangerous
710
0
711
0
  mSortingZOrder = true;
712
0
713
0
  /* Step through the list from bottom to top. If we find a window which
714
0
     should be moved up in the list, move it to its lowest legal position. */
715
0
  do {
716
0
    finished = true;
717
0
    lowest = mTopmostWindow->mHigher;
718
0
    scan = lowest;
719
0
    while (scan != mTopmostWindow) {
720
0
      uint32_t scanZ = scan->mZLevel;
721
0
      if (scanZ > scan->mHigher->mZLevel) { // out of order
722
0
        search = scan;
723
0
        do {
724
0
          search = search->mHigher;
725
0
        } while (search != lowest && scanZ > search->mZLevel);
726
0
727
0
        // reposition |scan| within the list
728
0
        if (scan != search && scan != search->mLower) {
729
0
          scan->Unlink(false, true);
730
0
          scan->InsertAfter(nullptr, search);
731
0
        }
732
0
        if (search == lowest)
733
0
          mTopmostWindow = scan;
734
0
735
0
        // fix actual window order
736
0
        nsCOMPtr<nsIBaseWindow> base;
737
0
        nsCOMPtr<nsIWidget> scanWidget;
738
0
        nsCOMPtr<nsIWidget> searchWidget;
739
0
        base = do_QueryInterface(scan->mWindow);
740
0
        if (base)
741
0
          base->GetMainWidget(getter_AddRefs(scanWidget));
742
0
        if (mTopmostWindow != scan) {
743
0
          base = do_QueryInterface(search->mWindow);
744
0
          if (base)
745
0
            base->GetMainWidget(getter_AddRefs(searchWidget));
746
0
        }
747
0
        if (scanWidget)
748
0
          scanWidget->PlaceBehind(eZPlacementBelow, searchWidget, false);
749
0
        finished = false;
750
0
        break;
751
0
      }
752
0
      scan = scan->mHigher;
753
0
    }
754
0
  } while (!finished);
755
0
756
0
  mSortingZOrder = false;
757
0
}
758
759
NS_IMPL_ISUPPORTS(nsWindowMediator,
760
  nsIWindowMediator,
761
  nsIObserver,
762
  nsISupportsWeakReference)
763
764
NS_IMETHODIMP
765
nsWindowMediator::AddListener(nsIWindowMediatorListener* aListener)
766
0
{
767
0
  NS_ENSURE_ARG_POINTER(aListener);
768
0
769
0
  mListeners.AppendElement(aListener);
770
0
771
0
  return NS_OK;
772
0
}
773
774
NS_IMETHODIMP
775
nsWindowMediator::RemoveListener(nsIWindowMediatorListener* aListener)
776
0
{
777
0
  NS_ENSURE_ARG_POINTER(aListener);
778
0
779
0
  mListeners.RemoveElement(aListener);
780
0
781
0
  return NS_OK;
782
0
}
783
784
NS_IMETHODIMP
785
nsWindowMediator::Observe(nsISupports* aSubject,
786
                          const char* aTopic,
787
                          const char16_t* aData)
788
0
{
789
0
  if (!strcmp(aTopic, "xpcom-shutdown") && mReady) {
790
0
    MOZ_RELEASE_ASSERT(NS_IsMainThread());
791
0
    while (mOldestWindow)
792
0
      UnregisterWindow(mOldestWindow);
793
0
    mReady = false;
794
0
  }
795
0
  return NS_OK;
796
0
}