@raydiant/playlist-window-manager 0.0.0-test-26 → 0.0.0-test-28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,12 +3,11 @@ import {
3
3
  BrowserWindow,
4
4
  BrowserView,
5
5
  ipcMain,
6
- screen,
7
6
  IpcMainEvent,
8
7
  Event,
9
- Details,
10
8
  BrowserWindowConstructorOptions,
11
9
  BrowserViewConstructorOptions,
10
+ RenderProcessGoneDetails,
12
11
  } from 'electron';
13
12
  import {
14
13
  PresentationWindowRenderer,
@@ -16,9 +15,7 @@ import {
16
15
  WindowBounds,
17
16
  Logger,
18
17
  } from './types';
19
- import lodash from 'lodash';
20
18
  import WindowUnresponsiveError from './WindowUnresponsiveError';
21
- import { areBoundsEqual, isFullscreen } from './boundUtils';
22
19
 
23
20
  interface ProxySettings {
24
21
  proxyRules: string;
@@ -35,7 +32,10 @@ interface BrowserWindowRendererWindow {
35
32
  payload?: any
36
33
  ) => void;
37
34
  unresponsiveCallback: () => void;
38
- renderProcessGoneCallback: (event: Event, details: Details) => void;
35
+ renderProcessGoneCallback: (
36
+ event: Event,
37
+ details: RenderProcessGoneDetails
38
+ ) => void;
39
39
  }
40
40
 
41
41
  interface BrowserWindowRendererOptions {
@@ -55,9 +55,6 @@ export default class BrowserWindowRenderer
55
55
  private windows: {
56
56
  [windowId: string]: BrowserWindowRendererWindow;
57
57
  } = {};
58
- private windowsBounds: {
59
- [windowId: string]: WindowBounds;
60
- } = {};
61
58
  private windowCrashHandler: (reason: string) => void = (_: string) => {};
62
59
 
63
60
  private browserWindowPool = new WindowPool<BrowserWindow>();
@@ -65,12 +62,9 @@ export default class BrowserWindowRenderer
65
62
 
66
63
  // Create a hidden window to preload BrowserViews.
67
64
  private offscreenWindow = new BrowserWindow({
68
- ...this.opts.bounds,
69
65
  show: false,
70
66
  frame: this.opts.frame,
71
67
  hasShadow: this.opts.hasShadow,
72
- useContentSize: true,
73
- fullscreen: isFullscreen(this.opts.bounds),
74
68
  webPreferences: {
75
69
  preload: path.join(__dirname, 'preload.js'),
76
70
  },
@@ -81,28 +75,13 @@ export default class BrowserWindowRenderer
81
75
  private logger: Logger;
82
76
 
83
77
  constructor(private opts: BrowserWindowRendererOptions) {
84
- this.logger = opts.logger;
85
- opts.logger.info(
86
- `playlist-window-manager/src/BrowserWindowRenderer.ts constructor1 ${JSON.stringify(
87
- opts.bounds
88
- )}`
89
- );
90
- this.setWindowOrViewBounds(this.offscreenWindow, opts.bounds);
91
- opts.logger.info(
92
- `playlist-window-manager/src/BrowserWindowRenderer.ts constructor2 ${JSON.stringify(
93
- {
94
- fullscreen: this.offscreenWindow.isFullScreen(),
95
- bounds: this.offscreenWindow.getBounds(),
96
- normalBounds: this.offscreenWindow.getNormalBounds(),
97
- contentBounds: this.offscreenWindow.getContentBounds(),
98
- }
99
- )}`
100
- );
101
-
78
+ this.offscreenWindow.setBounds(opts.bounds);
102
79
  if (opts.proxySettings) {
103
80
  this.proxySettings = opts.proxySettings;
104
81
  }
105
82
 
83
+ this.logger = opts.logger;
84
+
106
85
  if (opts.windowCrashHandler) {
107
86
  this.windowCrashHandler = opts.windowCrashHandler;
108
87
  }
@@ -115,21 +94,7 @@ export default class BrowserWindowRenderer
115
94
  backgroundColor,
116
95
  receiveMessageCallback,
117
96
  errorCallback,
118
- }: CreateWindowOptions): Promise<void> {
119
- const windowBounds =
120
- parentWindowId && !this.opts.renderChildWindowsAsBrowserViews
121
- ? {
122
- ...bounds,
123
- x: bounds.x + this.opts.bounds.x,
124
- y: bounds.y + this.opts.bounds.y,
125
- }
126
- : bounds;
127
-
128
- this.logger.info(
129
- `playlist-window-manager/src/BrowserWindowRenderer.ts createWindow1: ${JSON.stringify(
130
- windowBounds
131
- )}`
132
- );
97
+ }: CreateWindowOptions) {
133
98
  const window: BrowserWindowRendererWindow = {
134
99
  parentWindowId,
135
100
  // If we are creating a child window and renderChildWindowsAsBrowserViews is true,
@@ -144,7 +109,6 @@ export default class BrowserWindowRenderer
144
109
  : this.createOrGetPooledBrowserWindow(windowId, {
145
110
  show: false,
146
111
  frame: this.opts.frame,
147
- fullscreen: isFullscreen(this.opts.bounds),
148
112
  // NOTE: useWindowPool: true does not work with renderChildWindowsAsBrowserViews: false
149
113
  // because the parent can't be changed after creating the BrowserWindow.
150
114
  parent: parentWindowId
@@ -160,7 +124,14 @@ export default class BrowserWindowRenderer
160
124
  // we are rendering child windows with BrowserWindow. BrowserWindows are positioned absolutely so
161
125
  // to place them in the correct spot relative to their parent we need to add the main window's x / y.
162
126
  // BrowserViews are relatively positioned so we don't need to do that.
163
- bounds: windowBounds,
127
+ bounds:
128
+ parentWindowId && !this.opts.renderChildWindowsAsBrowserViews
129
+ ? {
130
+ ...bounds,
131
+ x: bounds.x + this.opts.bounds.x,
132
+ y: bounds.y + this.opts.bounds.y,
133
+ }
134
+ : bounds,
164
135
 
165
136
  receiveMessageCallback: (
166
137
  _: IpcMainEvent,
@@ -180,7 +151,10 @@ export default class BrowserWindowRenderer
180
151
  );
181
152
  },
182
153
 
183
- renderProcessGoneCallback: (_: Event, details: Details) => {
154
+ renderProcessGoneCallback: (
155
+ _: Event,
156
+ details: RenderProcessGoneDetails
157
+ ) => {
184
158
  this.logger.error(
185
159
  `Window received 'render-process-gone' event. Reason: ${details.reason}`,
186
160
  { windowId }
@@ -209,20 +183,9 @@ export default class BrowserWindowRenderer
209
183
 
210
184
  if (window.view instanceof BrowserView) {
211
185
  this.moveWindowOffscreen(window);
212
- this.logger.info(
213
- `playlist-window-manager/src/BrowserWindowRenderer.ts createWindow2: ${JSON.stringify(
214
- {
215
- fullscreen: this.offscreenWindow.isFullScreen(),
216
- bounds: this.offscreenWindow.getBounds(),
217
- normalBounds: this.offscreenWindow.getNormalBounds(),
218
- contentBounds: this.offscreenWindow.getContentBounds(),
219
- }
220
- )}`
221
- );
222
186
  }
223
187
 
224
188
  this.windows[windowId] = window;
225
- this.windowsBounds[windowId] = lodash.cloneDeep(windowBounds);
226
189
  // Listen for messages from window.
227
190
  ipcMain.on(windowId, window.receiveMessageCallback);
228
191
 
@@ -234,49 +197,7 @@ export default class BrowserWindowRenderer
234
197
  );
235
198
  }
236
199
 
237
- if (window.view instanceof BrowserWindow) {
238
- this.logger.info(
239
- `playlist-window-manager/src/BrowserWindowRenderer.ts createWindow4: ${JSON.stringify(
240
- {
241
- newBounds: window.bounds,
242
- fullscreen: window.view.isFullScreen(),
243
- bounds: window.view.getBounds(),
244
- contentBounds: window.view.getContentBounds(),
245
- normalBounds: window.view.getNormalBounds(),
246
- }
247
- )}`
248
- );
249
- } else {
250
- this.logger.info(
251
- `playlist-window-manager/src/BrowserWindowRenderer.ts createWindow5: ${JSON.stringify(
252
- {
253
- newBounds: window.bounds,
254
- bounds: window.view.getBounds(),
255
- }
256
- )}`
257
- );
258
- }
259
- this.setWindowOrViewBounds(window.view, window.bounds);
260
- if (window.view instanceof BrowserWindow) {
261
- this.logger.info(
262
- `playlist-window-manager/src/BrowserWindowRenderer.ts createWindow7: ${JSON.stringify(
263
- {
264
- fullscreen: window.view.isFullScreen(),
265
- bounds: window.view.getBounds(),
266
- contentBounds: window.view.getContentBounds(),
267
- normalBounds: window.view.getNormalBounds(),
268
- }
269
- )}`
270
- );
271
- } else {
272
- this.logger.info(
273
- `playlist-window-manager/src/BrowserWindowRenderer.ts createWindow8: ${JSON.stringify(
274
- {
275
- bounds: window.view.getBounds(),
276
- }
277
- )}`
278
- );
279
- }
200
+ window.view.setBounds(window.bounds);
280
201
 
281
202
  if (this.proxySettings) {
282
203
  await window.view.webContents.session.setProxy(this.proxySettings);
@@ -304,95 +225,28 @@ export default class BrowserWindowRenderer
304
225
  `Failed to update window bounds, missing window id '${windowId}'`
305
226
  );
306
227
  }
307
-
308
- this.logger.info(
309
- `playlist-window-manager/src/BrowserWindowRenderer.ts updateWindowBounds1: ${JSON.stringify(
310
- bounds
311
- )}`
312
- );
313
228
  window.bounds = bounds;
314
229
 
315
230
  if (window.view instanceof BrowserWindow && window.parentWindowId) {
316
231
  // Child BrowserWindows are absolutely positioned so we need to add the main windows
317
232
  // x/y to when updating the child window's bounds.
318
- const newBounds = {
233
+ window.view.setBounds({
319
234
  ...window.bounds,
320
235
  x: window.bounds.x + this.opts.bounds.x,
321
236
  y: window.bounds.y + this.opts.bounds.y,
322
- };
323
- this.logger.info(
324
- `playlist-window-manager/src/BrowserWindowRenderer.ts updateWindowBounds2: ${JSON.stringify(
325
- newBounds
326
- )}`
327
- );
328
- this.setWindowOrViewBounds(window.view, newBounds);
329
-
330
- this.logger.info(
331
- `playlist-window-manager/src/BrowserWindowRenderer.ts updateWindowBounds3: ${JSON.stringify(
332
- {
333
- fullscreen: window.view.isFullScreen(),
334
- bounds: window.view.getBounds(),
335
- normalBounds: window.view.getNormalBounds(),
336
- contentBounds: window.view.getContentBounds(),
337
- }
338
- )}`
339
- );
237
+ });
340
238
  } else {
341
- this.logger.info(
342
- `playlist-window-manager/src/BrowserWindowRenderer.ts updateWindowBounds4: ${JSON.stringify(
343
- window.bounds
344
- )}`
345
- );
346
- this.setWindowOrViewBounds(window.view, window.bounds);
347
- this.logger.info(
348
- `playlist-window-manager/src/BrowserWindowRenderer.ts updateWindowBounds5: ${JSON.stringify(
349
- window.view.getBounds()
350
- )}`
351
- );
239
+ window.view.setBounds(window.bounds);
352
240
  }
353
241
  }
354
242
 
355
243
  public showWindow(windowId: string, isFocused: boolean) {
356
- this.logger.info(
357
- `playlist-window-manager/src/BrowserWindowRenderer.ts showWindow1: ${windowId}`
358
- );
359
244
  const window = this.getWindow(windowId);
360
- const windowBounds = this.getWindowBounds(windowId);
361
- if (!window || !windowBounds) {
245
+ if (!window) {
362
246
  throw new Error(`Failed to show window, missing window id '${windowId}'`);
363
247
  }
364
248
 
365
249
  if (window.view instanceof BrowserWindow) {
366
- this.logger.info(
367
- `playlist-window-manager/src/BrowserWindowRenderer.ts showWindow2: ${JSON.stringify(
368
- {
369
- fullscreen: window.view.isFullScreen(),
370
- isMaximized: window.view.isMaximized(),
371
- bounds: window.view.getBounds(),
372
- windowBounds: windowBounds,
373
- normalBounds: window.view.getNormalBounds(),
374
- contentBounds: window.view.getContentBounds(),
375
- }
376
- )}`
377
- );
378
- if (!areBoundsEqual(window.view.getBounds(), windowBounds)) {
379
- this.logger.info(
380
- `playlist-window-manager/src/BrowserWindowRenderer.ts showWindow3: setWindowOrViewBounds`
381
- );
382
- this.setWindowOrViewBounds(window.view, windowBounds);
383
- }
384
-
385
- this.logger.info(
386
- `playlist-window-manager/src/BrowserWindowRenderer.ts showWindow4: ${JSON.stringify(
387
- {
388
- fullscreen: window.view.isFullScreen(),
389
- isMaximized: window.view.isMaximized(),
390
- bounds: window.view.getBounds(),
391
- normalBounds: window.view.getNormalBounds(),
392
- contentBounds: window.view.getContentBounds(),
393
- }
394
- )}`
395
- );
396
250
  if (isFocused) {
397
251
  window.view.show();
398
252
  } else {
@@ -453,7 +307,6 @@ export default class BrowserWindowRenderer
453
307
  }
454
308
 
455
309
  delete this.windows[windowId];
456
- delete this.windowsBounds[windowId];
457
310
 
458
311
  if (this.opts.useWindowPool) {
459
312
  this.logPoolStats();
@@ -502,125 +355,10 @@ export default class BrowserWindowRenderer
502
355
  window.view.webContents.setAudioMuted(false);
503
356
  }
504
357
 
505
- /**
506
- * This function is designed to solve missing 1px issue.
507
- * If we set 1920x1080 bounds on 1920x1080 display
508
- * then the actual BrowserWindow resolution would be
509
- * 1919x1079.
510
- */
511
- private setWindowOrViewBounds(
512
- window: BrowserWindow | BrowserView,
513
- bounds: WindowBounds
514
- ) {
515
- if (window instanceof BrowserView) {
516
- this.logger.info(
517
- `playlist-window-manager/src/BrowserWindowRenderer.ts setWindowOrViewBounds1: ${JSON.stringify(
518
- {
519
- windowBounds: window.getBounds(),
520
- bounds,
521
- }
522
- )}`
523
- );
524
- window.setBounds(bounds);
525
- return;
526
- }
527
-
528
- this.logger.info(
529
- `playlist-window-manager/src/BrowserWindowRenderer.ts setWindowOrViewBounds2: ${JSON.stringify(
530
- {
531
- newBounds: bounds,
532
- fullscreen: window.isFullScreen(),
533
- isMaximized: window.isMaximized(),
534
- bounds: window.getBounds(),
535
- contentBounds: window.getContentBounds(),
536
- normalBounds: window.getNormalBounds(),
537
- }
538
- )}`
539
- );
540
-
541
- // calling setBounds or setFullscreen may introduce -1px resolution error
542
- // so we try to avoid unnecessary calls
543
- if (areBoundsEqual(window.getBounds(), bounds)) {
544
- this.logger.info(
545
- `playlist-window-manager/src/BrowserWindowRenderer.ts setWindowOrViewBounds3: bounds are equal`
546
- );
547
- return;
548
- }
549
-
550
- if (isFullscreen(bounds) !== window.isFullScreen()) {
551
- this.logger.info(
552
- `playlist-window-manager/src/BrowserWindowRenderer.ts setWindowOrViewBounds4: setFullScreen`
553
- );
554
- window.setFullScreen(isFullscreen(bounds));
555
- }
556
-
557
- this.logger.info(
558
- `playlist-window-manager/src/BrowserWindowRenderer.ts setWindowOrViewBounds5: ${JSON.stringify(
559
- {
560
- fullscreen: window.isFullScreen(),
561
- isMaximized: window.isMaximized(),
562
- bounds: window.getBounds(),
563
- contentBounds: window.getContentBounds(),
564
- normalBounds: window.getNormalBounds(),
565
- }
566
- )}`
567
- );
568
-
569
- if (!areBoundsEqual(window.getBounds(), bounds)) {
570
- this.logger.info(
571
- `playlist-window-manager/src/BrowserWindowRenderer.ts setWindowOrViewBounds6: setBounds`
572
- );
573
- window.setBounds(bounds);
574
- }
575
-
576
- this.logger.info(
577
- `playlist-window-manager/src/BrowserWindowRenderer.ts setWindowOrViewBounds7: ${JSON.stringify(
578
- {
579
- fullscreen: window.isFullScreen(),
580
- isMaximized: window.isMaximized(),
581
- bounds: window.getBounds(),
582
- contentBounds: window.getContentBounds(),
583
- normalBounds: window.getNormalBounds(),
584
- }
585
- )}`
586
- );
587
-
588
- if (window.isFullScreen() && !isFullscreen(window.getBounds())) {
589
- this.logger.info(
590
- `playlist-window-manager/src/BrowserWindowRenderer.ts setWindowOrViewBounds8: maximize: ${JSON.stringify(
591
- {
592
- fullscreen: window.isFullScreen(),
593
- isMaximized: window.isMaximized(),
594
- bounds: window.getBounds(),
595
- contentBounds: window.getContentBounds(),
596
- normalBounds: window.getNormalBounds(),
597
- }
598
- )}`
599
- );
600
- window.maximize();
601
- }
602
-
603
- this.logger.info(
604
- `playlist-window-manager/src/BrowserWindowRenderer.ts setWindowOrViewBounds9: ${JSON.stringify(
605
- {
606
- fullscreen: window.isFullScreen(),
607
- isMaximized: window.isMaximized(),
608
- bounds: window.getBounds(),
609
- contentBounds: window.getContentBounds(),
610
- normalBounds: window.getNormalBounds(),
611
- }
612
- )}`
613
- );
614
- }
615
-
616
358
  private getWindow(windowId: string): BrowserWindowRendererWindow | null {
617
359
  return this.windows[windowId];
618
360
  }
619
361
 
620
- private getWindowBounds(windowId: string): WindowBounds | null {
621
- return this.windowsBounds[windowId];
622
- }
623
-
624
362
  private moveWindowOffscreen(window: BrowserWindowRendererWindow) {
625
363
  if (!(window.view instanceof BrowserView)) {
626
364
  throw new Error(
@@ -728,18 +466,6 @@ export default class BrowserWindowRenderer
728
466
  }
729
467
  }
730
468
 
731
- this.logger.info(
732
- `playlist-window-manager/src/BrowserWindowRenderer.ts createOrGetPooledBrowserWindow1: ${JSON.stringify(
733
- {
734
- screen: screen.getPrimaryDisplay().bounds,
735
- fullscreen: browserWindow.isFullScreen(),
736
- bounds: browserWindow.getBounds(),
737
- contentBounds: browserWindow.getContentBounds(),
738
- normalBounds: browserWindow.getNormalBounds(),
739
- }
740
- )}`
741
- );
742
-
743
469
  return browserWindow;
744
470
  }
745
471
 
@@ -747,13 +473,6 @@ export default class BrowserWindowRenderer
747
473
  windowId: string,
748
474
  browserWindow: BrowserWindow
749
475
  ) {
750
- this.logger.info(
751
- `playlist-window-manager/src/BrowserWindowRenderer.ts destroyOrUnloadPooledBrowserWindow1: ${JSON.stringify(
752
- {
753
- windowId,
754
- }
755
- )}`
756
- );
757
476
  if (this.opts.useWindowPool) {
758
477
  this.hideWindow(windowId);
759
478
  await browserWindow.webContents.loadURL('about:blank');
@@ -9,6 +9,10 @@ import {
9
9
  Logger,
10
10
  WorkerState,
11
11
  AnalyticsEvent,
12
+ Charge,
13
+ ChargeRequest,
14
+ ChargeResponse,
15
+ Terminal,
12
16
  } from './types';
13
17
  import PresentationWindow from './PresentationWindow';
14
18
  import PlaylistWindowManagerState from './PlaylistWindowManagerState';
@@ -67,6 +71,9 @@ export interface PlaylistWindowManagerOptions {
67
71
 
68
72
  // Called when the current window wants to disable the interrupt lock
69
73
  onDisableInterruptLock?: () => void;
74
+
75
+ // Called when a window needs the current terminal object.
76
+ getTerminal?: () => Terminal | null;
70
77
  }
71
78
 
72
79
  // Wait at least 3 seconds before restarting or moving onto the next window
@@ -84,12 +91,12 @@ export default class PlaylistWindowManager extends EventEmitter {
84
91
  private overrideNextPresentation: RE.NextPresentationID | null = null;
85
92
  private currentWindow: PresentationWindow | null = null;
86
93
  private nextWindow: PresentationWindow | null = null;
87
- private hasPendingInterrupt = false;
94
+ private hasPendingInterrupt: boolean = false;
88
95
  private ruleEngine: RE.RuleEngine | null = null;
89
96
  private state: PlaylistWindowManagerState | null = null;
90
97
  private renderer: PresentationWindowRenderer | null = null;
91
- private restartCurrentWindowOnEnd = false;
92
- private shouldHardRestart = false;
98
+ private restartCurrentWindowOnEnd: boolean = false;
99
+ private shouldHardRestart: boolean = false;
93
100
  private currentWindowError: null | Error = null;
94
101
  private interruptCheckTimeout: ReturnType<typeof setTimeout> | null = null;
95
102
  private currentPresentationCompleteTimeout: ReturnType<
@@ -98,8 +105,8 @@ export default class PlaylistWindowManager extends EventEmitter {
98
105
  private lastCompleteAt: Date | null = null;
99
106
  private bounds?: WindowBounds;
100
107
  private themeOverride?: Theme;
101
- private forceMute = false;
102
- private isFocused = false;
108
+ private forceMute: boolean = false;
109
+ private isFocused: boolean = false;
103
110
 
104
111
  private workerState: WorkerState = {};
105
112
 
@@ -344,7 +351,6 @@ export default class PlaylistWindowManager extends EventEmitter {
344
351
  }
345
352
 
346
353
  public updateBounds(bounds: WindowBounds) {
347
- // TODO log bounds
348
354
  this.bounds = bounds;
349
355
  if (this.currentWindow) {
350
356
  this.currentWindow.updateBounds(this.bounds);
@@ -397,7 +403,7 @@ export default class PlaylistWindowManager extends EventEmitter {
397
403
  }
398
404
  }
399
405
 
400
- public async show(isFocused = true) {
406
+ public async show(isFocused: boolean = true) {
401
407
  if (this.currentWindow) {
402
408
  // Save the focused state so we know if preloaded windows should be
403
409
  // focused when swapped for the current.
@@ -441,6 +447,43 @@ export default class PlaylistWindowManager extends EventEmitter {
441
447
  }
442
448
  }
443
449
 
450
+ public sendChargeResponse(response: ChargeResponse) {
451
+ // Send charge response to the current window. The window will check if
452
+ // has a matching request id and if so, send the response to the app.
453
+ if (this.currentWindow) {
454
+ this.currentWindow.sendChargeResponse(response);
455
+ }
456
+
457
+ // Send charge response to the next window.
458
+ if (this.nextWindow) {
459
+ this.nextWindow.sendChargeResponse(response);
460
+ }
461
+ }
462
+
463
+ public sendCharge(charge: Charge) {
464
+ // Send charge to the current window.
465
+ if (this.currentWindow) {
466
+ this.currentWindow.sendCharge(charge);
467
+ }
468
+
469
+ // Send charge to the next window.
470
+ if (this.nextWindow) {
471
+ this.nextWindow.sendCharge(charge);
472
+ }
473
+ }
474
+
475
+ public sendTerminal(terminal: Terminal | null) {
476
+ // Send terminal to the current window.
477
+ if (this.currentWindow) {
478
+ this.currentWindow.sendTerminal(terminal);
479
+ }
480
+
481
+ // Send terminal to the next window.
482
+ if (this.nextWindow) {
483
+ this.nextWindow.sendTerminal(terminal);
484
+ }
485
+ }
486
+
444
487
  private createWindow(pr: RE.NextPresentationID): PresentationWindow {
445
488
  const {
446
489
  readyTimeoutDurationSeconds,
@@ -480,12 +523,6 @@ export default class PlaylistWindowManager extends EventEmitter {
480
523
 
481
524
  const windowId = uuidv4();
482
525
 
483
- logger.info(
484
- `playlist-window-manager/src/PlaylistWindowManager.ts createWindow1 ${JSON.stringify(
485
- this.bounds
486
- )}`
487
- );
488
-
489
526
  return new PresentationWindow({
490
527
  windowManager: this,
491
528
  renderer: this.renderer,
@@ -511,6 +548,7 @@ export default class PlaylistWindowManager extends EventEmitter {
511
548
  globalRule: this.ruleEngine.globalRule,
512
549
  isPreview,
513
550
  workerState: this.workerState,
551
+ getTerminal: this.options.getTerminal,
514
552
  });
515
553
  }
516
554
 
@@ -530,6 +568,7 @@ export default class PlaylistWindowManager extends EventEmitter {
530
568
  this.currentWindow.onEnableInterruptLock(this.handleEnableInterruptLock);
531
569
  this.currentWindow.onDisableInterruptLock(this.handleDisableInterruptLock);
532
570
  this.currentWindow.onAnalyticsEvent(this.handleAnalyticsEvent);
571
+ this.currentWindow.onChargeRequest(this.handleChargeRequest);
533
572
 
534
573
  await this.currentWindow.load();
535
574
  }
@@ -702,6 +741,7 @@ export default class PlaylistWindowManager extends EventEmitter {
702
741
  this.handleDisableInterruptLock
703
742
  );
704
743
  this.currentWindow.onAnalyticsEvent(this.handleAnalyticsEvent);
744
+ this.currentWindow.onChargeRequest(this.handleChargeRequest);
705
745
  }
706
746
 
707
747
  // Play new current window.
@@ -771,6 +811,12 @@ export default class PlaylistWindowManager extends EventEmitter {
771
811
  this.emitCurrentWindowEvent('window_analytics_event', event);
772
812
  };
773
813
 
814
+ private handleChargeRequest = (request: ChargeRequest) => {
815
+ // Emit the event on the current window. Only the current window should
816
+ // send charge requests since the next window is not visible.
817
+ this.emitCurrentWindowEvent('window_charge_request', request);
818
+ };
819
+
774
820
  private handleCurrentPresentationComplete = async () => {
775
821
  const { logger } = this.options;
776
822