- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / renderer / resources / extensions / app_window_custom_bindings.js
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.
4
5 // Custom binding for the app_window API.
6
7 var appWindowNatives = requireNative('app_window_natives');
8 var Binding = require('binding').Binding;
9 var Event = require('event_bindings').Event;
10 var forEach = require('utils').forEach;
11 var renderViewObserverNatives = requireNative('renderViewObserverNatives');
12 var sendRequest = require('sendRequest').sendRequest;
13
14 var appWindowData = null;
15 var currentAppWindow = null;
16
17 var appWindow = Binding.create('app.window');
18 appWindow.registerCustomHook(function(bindingsAPI) {
19   var apiFunctions = bindingsAPI.apiFunctions;
20
21   apiFunctions.setCustomCallback('create',
22                                  function(name, request, windowParams) {
23     var view = null;
24     if (windowParams.viewId) {
25       view = appWindowNatives.GetView(
26           windowParams.viewId, windowParams.injectTitlebar);
27     }
28
29     if (!view) {
30       // No route to created window. If given a callback, trigger it with an
31       // undefined object.
32       if (request.callback) {
33         request.callback();
34         delete request.callback;
35       }
36       return;
37     }
38
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;
45       }
46       return;
47     }
48
49     // Initialize appWindowData in the newly created JS context
50     view.chrome.app.window.initializeAppWindow(windowParams);
51
52     var callback = request.callback;
53     if (callback) {
54       delete request.callback;
55       if (!view) {
56         callback(undefined);
57         return;
58       }
59
60       var willCallback =
61           renderViewObserverNatives.OnDocumentElementCreated(
62               windowParams.viewId,
63               function(success) {
64                 if (success) {
65                   callback(view.chrome.app.window.current());
66                 } else {
67                   callback(undefined);
68                 }
69               });
70       if (!willCallback) {
71         callback(undefined);
72       }
73     }
74   });
75
76   apiFunctions.setHandleRequest('current', function() {
77     if (!currentAppWindow) {
78       console.error('The JavaScript context calling ' +
79                     'chrome.app.window.current() has no associated AppWindow.');
80       return null;
81     }
82     return currentAppWindow;
83   });
84
85   // This is an internal function, but needs to be bound with setHandleRequest
86   // because it is called from a different JS context.
87   apiFunctions.setHandleRequest('initializeAppWindow', function(params) {
88     var currentWindowInternal =
89         Binding.create('app.currentWindowInternal').generate();
90     var AppWindow = function() {};
91     forEach(currentWindowInternal, function(key, value) {
92       AppWindow.prototype[key] = value;
93     });
94     AppWindow.prototype.moveTo = $Function.bind(window.moveTo, window);
95     AppWindow.prototype.resizeTo = $Function.bind(window.resizeTo, window);
96     AppWindow.prototype.contentWindow = window;
97     AppWindow.prototype.onClosed = new Event();
98     AppWindow.prototype.close = function() {
99       this.contentWindow.close();
100     };
101     AppWindow.prototype.getBounds = function() {
102       var bounds = appWindowData.bounds;
103       return { left: bounds.left, top: bounds.top,
104                width: bounds.width, height: bounds.height };
105     };
106     AppWindow.prototype.getMinWidth = function() {
107       return appWindowData.minWidth;
108     };
109     AppWindow.prototype.getMinHeight = function() {
110       return appWindowData.minHeight;
111     };
112     AppWindow.prototype.getMaxWidth = function() {
113       return appWindowData.maxWidth;
114     };
115     AppWindow.prototype.getMaxHeight = function() {
116       return appWindowData.maxHeight;
117     };
118     AppWindow.prototype.isFullscreen = function() {
119       return appWindowData.fullscreen;
120     };
121     AppWindow.prototype.isMinimized = function() {
122       return appWindowData.minimized;
123     };
124     AppWindow.prototype.isMaximized = function() {
125       return appWindowData.maximized;
126     };
127     AppWindow.prototype.isAlwaysOnTop = function() {
128       return appWindowData.alwaysOnTop;
129     };
130
131     Object.defineProperty(AppWindow.prototype, 'id', {get: function() {
132       return appWindowData.id;
133     }});
134
135     appWindowData = {
136       id: params.id || '',
137       bounds: { left: params.bounds.left, top: params.bounds.top,
138                 width: params.bounds.width, height: params.bounds.height },
139       minWidth: params.minWidth,
140       minHeight: params.minHeight,
141       maxWidth: params.maxWidth,
142       maxHeight: params.maxHeight,
143       fullscreen: params.fullscreen,
144       minimized: params.minimized,
145       maximized: params.maximized,
146       alwaysOnTop: params.alwaysOnTop
147     };
148     currentAppWindow = new AppWindow;
149   });
150 });
151
152 function boundsEqual(bounds1, bounds2) {
153   if (!bounds1 || !bounds2)
154     return false;
155   return (bounds1.left == bounds2.left && bounds1.top == bounds2.top &&
156           bounds1.width == bounds2.width && bounds1.height == bounds2.height);
157 }
158
159 function dispatchEventIfExists(target, name) {
160   // Sometimes apps like to put their own properties on the window which
161   // break our assumptions.
162   var event = target[name];
163   if (event && (typeof event.dispatch == 'function'))
164     event.dispatch();
165   else
166     console.warn('Could not dispatch ' + name + ', event has been clobbered');
167 }
168
169 function updateAppWindowProperties(update) {
170   if (!appWindowData)
171     return;
172
173   var oldData = appWindowData;
174   update.id = oldData.id;
175   appWindowData = update;
176
177   var currentWindow = currentAppWindow;
178
179   if (!boundsEqual(oldData.bounds, update.bounds))
180     dispatchEventIfExists(currentWindow, "onBoundsChanged");
181
182   if (!oldData.fullscreen && update.fullscreen)
183     dispatchEventIfExists(currentWindow, "onFullscreened");
184   if (!oldData.minimized && update.minimized)
185     dispatchEventIfExists(currentWindow, "onMinimized");
186   if (!oldData.maximized && update.maximized)
187     dispatchEventIfExists(currentWindow, "onMaximized");
188
189   if ((oldData.fullscreen && !update.fullscreen) ||
190       (oldData.minimized && !update.minimized) ||
191       (oldData.maximized && !update.maximized))
192     dispatchEventIfExists(currentWindow, "onRestored");
193 };
194
195 function onAppWindowClosed() {
196   if (!currentAppWindow)
197     return;
198   dispatchEventIfExists(currentAppWindow, "onClosed");
199 }
200
201 exports.binding = appWindow.generate();
202 exports.onAppWindowClosed = onAppWindowClosed;
203 exports.updateAppWindowProperties = updateAppWindowProperties;