1 // Copyright (c) 2012 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.
5 // Custom binding for the app_window API.
7 var appWindowNatives = requireNative('app_window_natives');
8 var runtimeNatives = requireNative('runtime');
9 var Binding = require('binding').Binding;
10 var Event = require('event_bindings').Event;
11 var forEach = require('utils').forEach;
12 var renderViewObserverNatives = requireNative('renderViewObserverNatives');
14 var appWindowData = null;
15 var currentAppWindow = null;
17 var appWindow = Binding.create('app.window');
18 appWindow.registerCustomHook(function(bindingsAPI) {
19 var apiFunctions = bindingsAPI.apiFunctions;
21 apiFunctions.setCustomCallback('create',
22 function(name, request, windowParams) {
24 if (windowParams.viewId) {
25 view = appWindowNatives.GetView(
26 windowParams.viewId, windowParams.injectTitlebar);
30 // No route to created window. If given a callback, trigger it with an
32 if (request.callback) {
34 delete request.callback;
39 if (windowParams.existingWindow) {
40 // Not creating a new window, but activating an existing one, so trigger
41 // callback with existing window and don't do anything else.
42 if (request.callback) {
43 request.callback(view.chrome.app.window.current());
44 delete request.callback;
49 // Initialize appWindowData in the newly created JS context
50 view.chrome.app.window.initializeAppWindow(windowParams);
52 var callback = request.callback;
54 delete request.callback;
61 renderViewObserverNatives.OnDocumentElementCreated(
65 callback(view.chrome.app.window.current());
76 apiFunctions.setHandleRequest('current', function() {
77 if (!currentAppWindow) {
78 console.error('The JavaScript context calling ' +
79 'chrome.app.window.current() has no associated AppWindow.');
82 return currentAppWindow;
85 apiFunctions.setHandleRequest('getAll', function() {
86 var views = runtimeNatives.GetExtensionViews(-1, 'SHELL');
87 return $Array.map(views, function(win) {
88 return win.chrome.app.window.current();
92 apiFunctions.setHandleRequest('get', function(id) {
93 var windows = $Array.filter(chrome.app.window.getAll(), function(win) {
96 return windows.length > 0 ? windows[0] : null;
99 // This is an internal function, but needs to be bound with setHandleRequest
100 // because it is called from a different JS context.
101 apiFunctions.setHandleRequest('initializeAppWindow', function(params) {
102 var currentWindowInternal =
103 Binding.create('app.currentWindowInternal').generate();
104 var AppWindow = function() {};
105 forEach(currentWindowInternal, function(key, value) {
106 AppWindow.prototype[key] = value;
108 AppWindow.prototype.moveTo = $Function.bind(window.moveTo, window);
109 AppWindow.prototype.resizeTo = $Function.bind(window.resizeTo, window);
110 AppWindow.prototype.contentWindow = window;
111 AppWindow.prototype.onClosed = new Event();
112 AppWindow.prototype.close = function() {
113 this.contentWindow.close();
115 AppWindow.prototype.getBounds = function() {
116 var bounds = appWindowData.bounds;
117 return { left: bounds.left, top: bounds.top,
118 width: bounds.width, height: bounds.height };
120 AppWindow.prototype.getMinWidth = function() {
121 return appWindowData.minWidth;
123 AppWindow.prototype.getMinHeight = function() {
124 return appWindowData.minHeight;
126 AppWindow.prototype.getMaxWidth = function() {
127 return appWindowData.maxWidth;
129 AppWindow.prototype.getMaxHeight = function() {
130 return appWindowData.maxHeight;
132 AppWindow.prototype.isFullscreen = function() {
133 return appWindowData.fullscreen;
135 AppWindow.prototype.isMinimized = function() {
136 return appWindowData.minimized;
138 AppWindow.prototype.isMaximized = function() {
139 return appWindowData.maximized;
141 AppWindow.prototype.isAlwaysOnTop = function() {
142 return appWindowData.alwaysOnTop;
145 Object.defineProperty(AppWindow.prototype, 'id', {get: function() {
146 return appWindowData.id;
151 bounds: { left: params.bounds.left, top: params.bounds.top,
152 width: params.bounds.width, height: params.bounds.height },
153 minWidth: params.minWidth,
154 minHeight: params.minHeight,
155 maxWidth: params.maxWidth,
156 maxHeight: params.maxHeight,
157 fullscreen: params.fullscreen,
158 minimized: params.minimized,
159 maximized: params.maximized,
160 alwaysOnTop: params.alwaysOnTop
162 currentAppWindow = new AppWindow;
166 function boundsEqual(bounds1, bounds2) {
167 if (!bounds1 || !bounds2)
169 return (bounds1.left == bounds2.left && bounds1.top == bounds2.top &&
170 bounds1.width == bounds2.width && bounds1.height == bounds2.height);
173 function dispatchEventIfExists(target, name) {
174 // Sometimes apps like to put their own properties on the window which
175 // break our assumptions.
176 var event = target[name];
177 if (event && (typeof event.dispatch == 'function'))
180 console.warn('Could not dispatch ' + name + ', event has been clobbered');
183 function updateAppWindowProperties(update) {
187 var oldData = appWindowData;
188 update.id = oldData.id;
189 appWindowData = update;
191 var currentWindow = currentAppWindow;
193 if (!boundsEqual(oldData.bounds, update.bounds))
194 dispatchEventIfExists(currentWindow, "onBoundsChanged");
196 if (!oldData.fullscreen && update.fullscreen)
197 dispatchEventIfExists(currentWindow, "onFullscreened");
198 if (!oldData.minimized && update.minimized)
199 dispatchEventIfExists(currentWindow, "onMinimized");
200 if (!oldData.maximized && update.maximized)
201 dispatchEventIfExists(currentWindow, "onMaximized");
203 if ((oldData.fullscreen && !update.fullscreen) ||
204 (oldData.minimized && !update.minimized) ||
205 (oldData.maximized && !update.maximized))
206 dispatchEventIfExists(currentWindow, "onRestored");
209 function onAppWindowClosed() {
210 if (!currentAppWindow)
212 dispatchEventIfExists(currentAppWindow, "onClosed");
215 exports.binding = appWindow.generate();
216 exports.onAppWindowClosed = onAppWindowClosed;
217 exports.updateAppWindowProperties = updateAppWindowProperties;