@raydiant/playlist-window-manager 0.0.0-test-27 → 0.0.0-test-29

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,14 +62,12 @@ 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'),
70
+ contextIsolation: false,
76
71
  },
77
72
  });
78
73
 
@@ -81,28 +76,13 @@ export default class BrowserWindowRenderer
81
76
  private logger: Logger;
82
77
 
83
78
  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
-
79
+ this.offscreenWindow.setBounds(opts.bounds);
102
80
  if (opts.proxySettings) {
103
81
  this.proxySettings = opts.proxySettings;
104
82
  }
105
83
 
84
+ this.logger = opts.logger;
85
+
106
86
  if (opts.windowCrashHandler) {
107
87
  this.windowCrashHandler = opts.windowCrashHandler;
108
88
  }
@@ -115,21 +95,7 @@ export default class BrowserWindowRenderer
115
95
  backgroundColor,
116
96
  receiveMessageCallback,
117
97
  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
- );
98
+ }: CreateWindowOptions) {
133
99
  const window: BrowserWindowRendererWindow = {
134
100
  parentWindowId,
135
101
  // If we are creating a child window and renderChildWindowsAsBrowserViews is true,
@@ -144,7 +110,6 @@ export default class BrowserWindowRenderer
144
110
  : this.createOrGetPooledBrowserWindow(windowId, {
145
111
  show: false,
146
112
  frame: this.opts.frame,
147
- fullscreen: isFullscreen(this.opts.bounds),
148
113
  // NOTE: useWindowPool: true does not work with renderChildWindowsAsBrowserViews: false
149
114
  // because the parent can't be changed after creating the BrowserWindow.
150
115
  parent: parentWindowId
@@ -154,13 +119,21 @@ export default class BrowserWindowRenderer
154
119
  hasShadow: this.opts.hasShadow,
155
120
  webPreferences: {
156
121
  preload: path.join(__dirname, 'preload.js'),
122
+ contextIsolation: false,
157
123
  },
158
124
  }),
159
125
  // If we are creating a child window and renderChildWindowsAsBrowserViews is false that means
160
126
  // we are rendering child windows with BrowserWindow. BrowserWindows are positioned absolutely so
161
127
  // to place them in the correct spot relative to their parent we need to add the main window's x / y.
162
128
  // BrowserViews are relatively positioned so we don't need to do that.
163
- bounds: windowBounds,
129
+ bounds:
130
+ parentWindowId && !this.opts.renderChildWindowsAsBrowserViews
131
+ ? {
132
+ ...bounds,
133
+ x: bounds.x + this.opts.bounds.x,
134
+ y: bounds.y + this.opts.bounds.y,
135
+ }
136
+ : bounds,
164
137
 
165
138
  receiveMessageCallback: (
166
139
  _: IpcMainEvent,
@@ -180,7 +153,10 @@ export default class BrowserWindowRenderer
180
153
  );
181
154
  },
182
155
 
183
- renderProcessGoneCallback: (_: Event, details: Details) => {
156
+ renderProcessGoneCallback: (
157
+ _: Event,
158
+ details: RenderProcessGoneDetails
159
+ ) => {
184
160
  this.logger.error(
185
161
  `Window received 'render-process-gone' event. Reason: ${details.reason}`,
186
162
  { windowId }
@@ -209,20 +185,9 @@ export default class BrowserWindowRenderer
209
185
 
210
186
  if (window.view instanceof BrowserView) {
211
187
  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
188
  }
223
189
 
224
190
  this.windows[windowId] = window;
225
- this.windowsBounds[windowId] = lodash.cloneDeep(windowBounds);
226
191
  // Listen for messages from window.
227
192
  ipcMain.on(windowId, window.receiveMessageCallback);
228
193
 
@@ -234,49 +199,7 @@ export default class BrowserWindowRenderer
234
199
  );
235
200
  }
236
201
 
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
- }
202
+ window.view.setBounds(window.bounds);
280
203
 
281
204
  if (this.proxySettings) {
282
205
  await window.view.webContents.session.setProxy(this.proxySettings);
@@ -304,95 +227,28 @@ export default class BrowserWindowRenderer
304
227
  `Failed to update window bounds, missing window id '${windowId}'`
305
228
  );
306
229
  }
307
-
308
- this.logger.info(
309
- `playlist-window-manager/src/BrowserWindowRenderer.ts updateWindowBounds1: ${JSON.stringify(
310
- bounds
311
- )}`
312
- );
313
230
  window.bounds = bounds;
314
231
 
315
232
  if (window.view instanceof BrowserWindow && window.parentWindowId) {
316
233
  // Child BrowserWindows are absolutely positioned so we need to add the main windows
317
234
  // x/y to when updating the child window's bounds.
318
- const newBounds = {
235
+ window.view.setBounds({
319
236
  ...window.bounds,
320
237
  x: window.bounds.x + this.opts.bounds.x,
321
238
  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
- );
239
+ });
340
240
  } 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
- );
241
+ window.view.setBounds(window.bounds);
352
242
  }
353
243
  }
354
244
 
355
245
  public showWindow(windowId: string, isFocused: boolean) {
356
- this.logger.info(
357
- `playlist-window-manager/src/BrowserWindowRenderer.ts showWindow1: ${windowId}`
358
- );
359
246
  const window = this.getWindow(windowId);
360
- const windowBounds = this.getWindowBounds(windowId);
361
- if (!window || !windowBounds) {
247
+ if (!window) {
362
248
  throw new Error(`Failed to show window, missing window id '${windowId}'`);
363
249
  }
364
250
 
365
251
  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
252
  if (isFocused) {
397
253
  window.view.show();
398
254
  } else {
@@ -453,7 +309,6 @@ export default class BrowserWindowRenderer
453
309
  }
454
310
 
455
311
  delete this.windows[windowId];
456
- delete this.windowsBounds[windowId];
457
312
 
458
313
  if (this.opts.useWindowPool) {
459
314
  this.logPoolStats();
@@ -502,125 +357,10 @@ export default class BrowserWindowRenderer
502
357
  window.view.webContents.setAudioMuted(false);
503
358
  }
504
359
 
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
360
  private getWindow(windowId: string): BrowserWindowRendererWindow | null {
617
361
  return this.windows[windowId];
618
362
  }
619
363
 
620
- private getWindowBounds(windowId: string): WindowBounds | null {
621
- return this.windowsBounds[windowId];
622
- }
623
-
624
364
  private moveWindowOffscreen(window: BrowserWindowRendererWindow) {
625
365
  if (!(window.view instanceof BrowserView)) {
626
366
  throw new Error(
@@ -728,18 +468,6 @@ export default class BrowserWindowRenderer
728
468
  }
729
469
  }
730
470
 
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
471
  return browserWindow;
744
472
  }
745
473
 
@@ -747,13 +475,6 @@ export default class BrowserWindowRenderer
747
475
  windowId: string,
748
476
  browserWindow: BrowserWindow
749
477
  ) {
750
- this.logger.info(
751
- `playlist-window-manager/src/BrowserWindowRenderer.ts destroyOrUnloadPooledBrowserWindow1: ${JSON.stringify(
752
- {
753
- windowId,
754
- }
755
- )}`
756
- );
757
478
  if (this.opts.useWindowPool) {
758
479
  this.hideWindow(windowId);
759
480
  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