• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/**
6 * @fileoverview
7 * Apps v2 custom title bar implementation
8 */
9
10'use strict';
11
12/** @suppress {duplicate} */
13var remoting = remoting || {};
14
15/**
16 * @param {HTMLElement} titleBar The root node of the title-bar DOM hierarchy.
17 * @constructor
18 */
19remoting.WindowFrame = function(titleBar) {
20  /**
21   * @type {remoting.ClientSession}
22   * @private
23   */
24  this.clientSession_ = null;
25
26  /**
27   * @type {HTMLElement}
28   * @private
29   */
30  this.titleBar_ = titleBar;
31
32  /**
33   * @type {HTMLElement}
34   * @private
35   */
36  this.title_ = /** @type {HTMLElement} */
37      (titleBar.querySelector('.window-title'));
38  base.debug.assert(this.title_ != null);
39
40  /**
41   * @type {HTMLElement}
42   * @private
43   */
44  this.maximizeRestoreControl_ = /** @type {HTMLElement} */
45      (titleBar.querySelector('.window-maximize-restore'));
46  base.debug.assert(this.maximizeRestoreControl_ != null);
47
48  var optionsButton = titleBar.querySelector('.window-options');
49  base.debug.assert(optionsButton != null);
50  this.optionMenuButton_ = new remoting.MenuButton(
51      optionsButton,
52      this.onShowOptionsMenu_.bind(this),
53      this.onHideOptionsMenu_.bind(this));
54
55  /**
56   * @type {HTMLElement}
57   * @private
58   */
59  this.optionsMenuList_ = /** @type {HTMLElement} */
60      (optionsButton.querySelector('.window-options-menu'));
61  base.debug.assert(this.optionsMenuList_ != null);
62
63  /**
64   * @type {Array.<{cls:string, fn: function()}>}
65   */
66  var handlers = [
67    { cls: 'window-disconnect', fn: this.disconnectSession_.bind(this) },
68    { cls: 'window-maximize-restore',
69      fn: this.maximizeOrRestoreWindow_.bind(this) },
70    { cls: 'window-minimize', fn: this.minimizeWindow_.bind(this) },
71    { cls: 'window-close', fn: window.close.bind(window) },
72    { cls: 'window-controls-stub', fn: this.toggleWindowControls_.bind(this) }
73  ];
74  for (var i = 0; i < handlers.length; ++i) {
75    var element = titleBar.querySelector('.' + handlers[i].cls);
76    base.debug.assert(element != null);
77    element.addEventListener('click', handlers[i].fn, false);
78  }
79
80  // Ensure that tool-tips are always correct.
81  this.handleWindowStateChange_();
82  chrome.app.window.current().onMaximized.addListener(
83      this.handleWindowStateChange_.bind(this));
84  chrome.app.window.current().onRestored.addListener(
85      this.handleWindowStateChange_.bind(this));
86  chrome.app.window.current().onFullscreened.addListener(
87      this.handleWindowStateChange_.bind(this));
88  chrome.app.window.current().onFullscreened.addListener(
89      this.showWindowControlsPreview_.bind(this));
90};
91
92/**
93 * @return {remoting.OptionsMenu}
94 */
95remoting.WindowFrame.prototype.createOptionsMenu = function() {
96  return new remoting.OptionsMenu(
97      this.titleBar_.querySelector('.menu-send-ctrl-alt-del'),
98      this.titleBar_.querySelector('.menu-send-print-screen'),
99      this.titleBar_.querySelector('.menu-resize-to-client'),
100      this.titleBar_.querySelector('.menu-shrink-to-fit'),
101      this.titleBar_.querySelector('.menu-new-connection'),
102      this.titleBar_.querySelector('.window-fullscreen'),
103      this.titleBar_.querySelector('.menu-start-stop-recording'));
104};
105
106/**
107 * @param {remoting.ClientSession} clientSession The client session, or null if
108 *     there is no connection.
109 */
110remoting.WindowFrame.prototype.setClientSession = function(clientSession) {
111  this.clientSession_ = clientSession;
112  var windowTitle = document.head.querySelector('title');
113  if (this.clientSession_) {
114    this.title_.innerText = clientSession.getHostDisplayName();
115    windowTitle.innerText = clientSession.getHostDisplayName() + ' - ' +
116        chrome.i18n.getMessage(/*i18n-content*/'PRODUCT_NAME');
117  } else {
118    this.title_.innerHTML = '&nbsp;';
119    windowTitle.innerText =
120        chrome.i18n.getMessage(/*i18n-content*/'PRODUCT_NAME');
121  }
122  this.handleWindowStateChange_();
123};
124
125/**
126 * @return {{width: number, height: number}} The size of the window, ignoring
127 *     the title-bar and window borders, if visible.
128 */
129remoting.WindowFrame.prototype.getClientArea = function() {
130  if (chrome.app.window.current().isFullscreen()) {
131    return { 'height': window.innerHeight, 'width': window.innerWidth };
132  } else {
133    var kBorderWidth = 1;
134    var titleHeight = this.titleBar_.clientHeight;
135    return {
136      'height': window.innerHeight - titleHeight - 2 * kBorderWidth,
137      'width': window.innerWidth - 2 * kBorderWidth
138    };
139  }
140};
141
142/**
143 * @private
144 */
145remoting.WindowFrame.prototype.disconnectSession_ = function() {
146  // When the user disconnects, exit full-screen mode. This should not be
147  // necessary, as we do the same thing in client_session.js when the plugin
148  // is removed. However, there seems to be a bug in chrome.AppWindow.restore
149  // that causes it to get stuck in full-screen mode without this.
150  if (chrome.app.window.current().isFullscreen()) {
151    chrome.app.window.current().restore();
152  }
153  remoting.disconnect();
154};
155
156/**
157 * @private
158 */
159remoting.WindowFrame.prototype.maximizeOrRestoreWindow_ = function() {
160  /** @type {boolean} */
161  var restore =
162      chrome.app.window.current().isFullscreen() ||
163      chrome.app.window.current().isMaximized();
164  if (restore) {
165    chrome.app.window.current().restore();
166  } else {
167    chrome.app.window.current().maximize();
168  }
169};
170
171/**
172 * @private
173 */
174remoting.WindowFrame.prototype.minimizeWindow_ = function() {
175  chrome.app.window.current().minimize();
176};
177
178/**
179 * @private
180 */
181remoting.WindowFrame.prototype.toggleWindowControls_ = function() {
182  this.titleBar_.classList.toggle('opened');
183};
184
185/**
186 * Update the tool-top for the maximize/full-screen/restore icon to reflect
187 * its current behaviour.
188 *
189 * @private
190 */
191remoting.WindowFrame.prototype.handleWindowStateChange_ = function() {
192  // Set the title for the maximize/restore/full-screen button
193  /** @type {string} */
194  var tag = '';
195  if (chrome.app.window.current().isFullscreen()) {
196    tag = /*i18n-content*/'EXIT_FULL_SCREEN';
197  } else if (chrome.app.window.current().isMaximized()) {
198    tag = /*i18n-content*/'RESTORE_WINDOW';
199  } else {
200    tag = /*i18n-content*/'MAXIMIZE_WINDOW';
201  }
202  this.maximizeRestoreControl_.title = l10n.getTranslationOrError(tag);
203
204  // Ensure that the options menu aligns correctly for the side of the window
205  // it occupies.
206  if (chrome.app.window.current().isFullscreen()) {
207    this.optionsMenuList_.classList.add('right-align');
208  } else {
209    this.optionsMenuList_.classList.remove('right-align');
210  }
211};
212
213/**
214 * Callback invoked when the options menu is shown.
215 * @private
216 */
217remoting.WindowFrame.prototype.onShowOptionsMenu_ = function() {
218  remoting.optionsMenu.onShow();
219  this.titleBar_.classList.add('menu-opened');
220};
221
222/**
223 * Callback invoked when the options menu is shown.
224 * @private
225 */
226remoting.WindowFrame.prototype.onHideOptionsMenu_ = function() {
227  this.titleBar_.classList.remove('menu-opened');
228};
229
230/**
231 * Show the window controls for a few seconds
232 *
233 * @private
234 */
235remoting.WindowFrame.prototype.showWindowControlsPreview_ = function() {
236  /**
237   * @type {HTMLElement}
238   */
239  var target =  this.titleBar_;
240  var kPreviewTimeoutMs = 3000;
241  var hidePreview = function() {
242    target.classList.remove('preview');
243  };
244  target.classList.add('preview');
245  window.setTimeout(hidePreview, kPreviewTimeoutMs);
246};
247
248
249/** @type {remoting.WindowFrame} */
250remoting.windowFrame = null;
251