Compare commits

..

499 Commits

Author SHA1 Message Date
Cheng Zhao
c76f510cea Bump v0.8.3. 2014-01-07 08:26:12 -08:00
Cheng Zhao
968f75529a Fix possible crashes when quiting message loop. 2014-01-08 11:55:54 +08:00
Cheng Zhao
93d5a2e195 Fix invoking non-exist method when quiting. 2014-01-08 10:51:32 +08:00
Cheng Zhao
367285f3f3 Merge pull request #152 from atom/gfx-module
Add screen module
2014-01-07 04:46:24 -08:00
Cheng Zhao
95b2003193 📝 Add docs on screen module. 2014-01-07 20:35:13 +08:00
Cheng Zhao
bcdc44c1c6 Support converting v8 value to arbitrary vector or map. 2014-01-07 20:29:17 +08:00
Cheng Zhao
4ae2738ce5 Add screen.getPrimaryDisplay() API. 2014-01-07 20:15:55 +08:00
Cheng Zhao
e09a2ff811 Add support to convert gfx::Rect and gfx::Size to v8 value. 2014-01-07 20:15:23 +08:00
Cheng Zhao
7253a35455 Add initial screen module. 2014-01-07 20:00:25 +08:00
Cheng Zhao
1b1cf87115 Add support to convert gfx::Point to v8 value. 2014-01-07 20:00:02 +08:00
Cheng Zhao
3ec755e978 💄 2014-01-07 19:44:37 +08:00
Cheng Zhao
cf4616de7f api::EventEmitter could also be used by renderer. 2014-01-07 19:32:40 +08:00
Cheng Zhao
2755fbaadf Update apm. 2014-01-07 02:50:52 -08:00
Cheng Zhao
6f222651d7 Bump v0.8.2. 2014-01-07 18:44:37 +08:00
Cheng Zhao
fe4841a1cd Set module's filename to path of html.
The relative require relies on module.filename to work as expected.
2014-01-07 14:30:18 +08:00
Cheng Zhao
fe8a2b9ee0 Still support 'atom-delegate' API for old apps. 2014-01-07 09:50:00 +08:00
Cheng Zhao
b939232670 mac: Should set default size when creating window. 2014-01-06 18:58:30 +08:00
Cheng Zhao
cac3973731 Flip the y axis in CapturePage API, fixes #148. 2013-12-31 14:40:42 +08:00
Cheng Zhao
19a35b58f0 Merge pull request #147 from atom/remote-docs
Revise the docs on remote module
2013-12-30 18:02:14 -08:00
Cheng Zhao
5e51ad30d7 Add notes about remote buffer in capturePage API's docs. 2013-12-31 10:00:29 +08:00
Cheng Zhao
e1e5cb5ba4 Add notes on remote buffer. 2013-12-30 23:15:15 +08:00
Cheng Zhao
8d124c7157 Revise the docs of remote module. 2013-12-30 22:06:33 +08:00
Cheng Zhao
67ed72294b Bump v0.8.1. 2013-12-29 23:09:19 +08:00
Cheng Zhao
1bb5481071 Fix circulate require. 2013-12-29 22:33:53 +08:00
Cheng Zhao
876063b1ba Fix console.log under Windows.
The process.log is not added until the next iteration of uv loop.
2013-12-29 22:32:26 +08:00
Cheng Zhao
7d193033f5 💄 Fix wrong order of parameter when killing process. 2013-12-29 22:11:54 +08:00
Cheng Zhao
074ea374e0 We are now on v0.8.0 release. 2013-12-27 16:22:34 +08:00
Cheng Zhao
f6c3a69595 Merge pull request #146 from atom/window-open
Implement window.open in pure js
2013-12-26 23:54:19 -08:00
Cheng Zhao
f28881e203 Fix crash caused by BrowserWindow.destroy(). 2013-12-27 15:41:00 +08:00
Cheng Zhao
6312c1108a Add spec for window.open. 2013-12-27 14:58:13 +08:00
Cheng Zhao
0de40febab Add basic support for window.open's features. 2013-12-27 14:57:53 +08:00
Cheng Zhao
1701f572e2 Fix crash when calling method of destroyed object. 2013-12-27 14:47:50 +08:00
Cheng Zhao
15a9be6b93 Implement a simple window.open with pure js. 2013-12-27 14:39:23 +08:00
Cheng Zhao
a60be1563f Do not implement window.open. 2013-12-27 14:32:24 +08:00
Cheng Zhao
a2522efb25 Build for x64 architecture on OS X, fixes #132. 2013-12-27 14:17:35 +08:00
Cheng Zhao
7c3f22a333 Bump v0.8.0. 2013-12-27 14:09:10 +08:00
Cheng Zhao
2945e1b50a Merge pull request #140 from atom/chrome31
Update to Chrome 31
2013-12-26 22:07:17 -08:00
Cheng Zhao
aedacd39d2 Rename 'finish-launching' event to 'ready',
'finish-launching' is more like a OS X message name, and in atom-shell
it means initialization has done, so 'ready' seems to be a better name
and more easy to remember.

The 'will-finish-launching' event just represents the corresponding
message on OS X and is the same with 'ready' on other platforms, so we
keep its name to indicate that it's only useful for OS X specified
code.
2013-12-27 11:08:26 +08:00
Cheng Zhao
d3f33152d0 Get rid of the ugly ATOM_BROWSER_INTERNAL_NEW message. 2013-12-26 18:41:21 +08:00
Cheng Zhao
cfca12d4a5 Use the gyp vendored by brightray. 2013-12-25 18:47:19 +08:00
Cheng Zhao
754cd88cc2 Update brightray: Fix building on Windows. 2013-12-24 16:05:50 +08:00
Cheng Zhao
031426d54e Use our fork of V8ValueConverter for all cases. 2013-12-23 22:42:21 +08:00
Cheng Zhao
980e8ca4dc Free the node environment when releasing context. 2013-12-23 22:19:51 +08:00
Cheng Zhao
df0094b6cb Move node integration from RenderViewObserver to RendererClient. 2013-12-23 22:08:45 +08:00
Cheng Zhao
02d94c8b2e Print pid when logging. 2013-12-23 22:04:49 +08:00
Cheng Zhao
902be9bab5 Update node: Removed two unused patches. 2013-12-20 14:20:24 +08:00
Cheng Zhao
f646d2dda8 Enable high DPI support. 2013-12-20 14:14:07 +08:00
Cheng Zhao
92b19f89d9 Remove the unzip spec completely. 2013-12-17 23:21:40 +08:00
Cheng Zhao
d8eb465eb9 Fix protocol spec on Windows. 2013-12-17 23:03:36 +08:00
Cheng Zhao
c04a9933cc Fix __filename on Windows. 2013-12-17 22:16:15 +08:00
Cheng Zhao
5b12f80d01 Discard the require('atom-delegate') API. 2013-12-17 22:08:45 +08:00
Cheng Zhao
75c44ca057 Fix initializing V8 on Windows. 2013-12-17 21:55:56 +08:00
Cheng Zhao
56f709ff1f Continue fixing compilation erros on Windows. 2013-12-17 18:34:45 +08:00
Cheng Zhao
0215c2fbee Make all the windows code compile for Chrome 31. 2013-12-17 17:52:57 +08:00
Cheng Zhao
6e079d8bc4 Also search C:/Program Files (x86) for node binary. 2013-12-17 13:14:54 +08:00
Cheng Zhao
a4715f936b Merge branch 'master' into chrome31
Conflicts:
	common/atom_version.h
2013-12-17 12:58:25 +08:00
Cheng Zhao
1d88b31edd Use node-runas for testing native modules. 2013-12-17 12:00:21 +08:00
Cheng Zhao
e07e26ca76 Fix third party module specs. 2013-12-16 22:46:16 +08:00
Cheng Zhao
c82e73a4ec Update apm: Fix installing for node v0.11.x. 2013-12-16 22:37:43 +08:00
Cheng Zhao
eda4249bf8 Add deps/npm and deps/mdb_v8 in node headers. 2013-12-16 22:37:17 +08:00
Cheng Zhao
09201e3e65 Update brightray: Remove webkit hacks. 2013-12-16 21:19:12 +08:00
Cheng Zhao
2ca2d37e93 Clean out node_modules in cibuild. 2013-12-16 15:15:33 +08:00
Cheng Zhao
d3416e2873 Bump node version to v0.11.9. 2013-12-16 14:52:15 +08:00
Cheng Zhao
4e4e316005 Include Environment declarations in node_common.h. 2013-12-16 14:46:05 +08:00
Cheng Zhao
8fc1e055bf Update apm for node version and architecture change. 2013-12-16 14:40:03 +08:00
Cheng Zhao
d51ea21afa Use singular form of spec names. 2013-12-16 00:31:40 +08:00
Cheng Zhao
abf982e4e5 Remove the on_watcher_queue_updated hack. 2013-12-15 19:50:43 +08:00
Cheng Zhao
998e9792fb Make setImmediate have the same side effect with upstream node. 2013-12-15 19:09:00 +08:00
Cheng Zhao
c87b21148c Supress the unzip module spec.
The unzip module is not compatible with node v0.11.x, so we do not need
to test it anymore.
2013-12-15 19:08:10 +08:00
Cheng Zhao
7e67f7632d 💄 Fix cpplint warnings. 2013-12-15 17:09:35 +08:00
Cheng Zhao
cd68396bd5 Disable use of deprecated functions in specs. 2013-12-15 17:02:43 +08:00
Cheng Zhao
474e1fcd3b Fix protocol module specs. 2013-12-15 16:53:07 +08:00
Cheng Zhao
cfeeec37eb Fix capturePage() spec. 2013-12-15 16:32:49 +08:00
Cheng Zhao
0a84c30d3b Redirect window.onerror to uncaughtException. 2013-12-15 16:32:41 +08:00
Cheng Zhao
7ba03ce23d Add setImmediate function in renderer. 2013-12-15 16:21:23 +08:00
Cheng Zhao
cc5db4dab9 Suppress the EventEmitter's warning for ObjectsRegistry.
It's possible that many objects subscribed to it.
2013-12-15 16:15:18 +08:00
Cheng Zhao
aa3e8385df Set __filename to the html file in renderer. 2013-12-15 16:11:00 +08:00
Cheng Zhao
886ebdb002 Use node's Environment feature to add "require" in renderer. 2013-12-15 14:20:28 +08:00
Kevin Sawicki
ea2f87683a Merge pull request #144 from shama/typo
Fix a couple minor typos in docs
2013-12-13 08:44:06 -08:00
Kyle Robinson Young
c116f6b35c Fix a couple minor typos in docs 2013-12-12 22:31:19 -08:00
Cheng Zhao
2413eebd7b Disable accelerated compositing to fix everything. 2013-12-13 00:57:08 +08:00
Cheng Zhao
7708e7a8c4 Update node for renderer node integration fixes. 2013-12-12 16:49:56 +08:00
Cheng Zhao
1c0b391419 Fix the black devtools view.
Without using UnderlayOpenGLHostingWindow the devtools view would just
be black.
2013-12-12 15:49:08 +08:00
Cheng Zhao
28f5d184b3 Do not depend on node to set include_dirs.
Part of atom/node#2.
2013-12-12 14:07:00 +08:00
Cheng Zhao
fc00da9732 Update brightray, which contains all our patches in master. 2013-12-12 10:43:50 +08:00
Cheng Zhao
9ea75b7519 We are now at v0.8.0-pre. 2013-12-12 10:43:34 +08:00
Cheng Zhao
61c63a6af9 Fix crashes about persistent v8 functions. 2013-12-12 00:10:09 +08:00
Cheng Zhao
e4bfa373de Fix node integration to browser after updated to Chrome31. 2013-12-11 23:59:03 +08:00
Cheng Zhao
d53915c6ab Fix recursive calling of handle(). 2013-12-11 23:57:37 +08:00
Cheng Zhao
409a431892 Huge commit to use new V8 and Content APIs.
Still got a lots of linking errors!
2013-12-11 15:48:19 +08:00
Cheng Zhao
d82cfc023f 💄 There should be no space between & and type name. 2013-12-10 14:27:25 +08:00
Cheng Zhao
f9c41f33e5 node::ObjectWrap how had a handle() method. 2013-12-10 14:15:37 +08:00
Cheng Zhao
4ec4b01218 base/string16.h was moved to base/strings/string16.h. 2013-12-10 14:14:05 +08:00
Cheng Zhao
0a37852757 Update to node v0.11.9. 2013-12-10 14:07:32 +08:00
Cheng Zhao
42ffa5813f Update libchromiumcontent and brightray to use Chrome31. 2013-12-09 17:23:32 +08:00
Cheng Zhao
597e17b540 Fix template related compilation errors of VC++. 2013-12-09 16:34:10 +08:00
Cheng Zhao
9ac0591386 Bump v0.7.6. 2013-12-08 22:42:43 -08:00
Cheng Zhao
cb73a3c572 Remove the RestartHangMonitorTimeout API, which is useless now. 2013-12-09 14:17:56 +08:00
Cheng Zhao
2c672052e6 Flatten spec files, make them seem cleaner. 2013-12-06 22:23:02 +08:00
Cheng Zhao
b431e96f9d Update node: Add fs.lstatSyncNoException, closes #138. 2013-12-06 21:51:47 +08:00
Cheng Zhao
36445f8d8b Merge pull request #139 from atom/browser-cleaner
Do not rely on renderer to report the deletion of render view
2013-12-06 05:17:27 -08:00
Cheng Zhao
085b1a45ee Report the right render view that is deleted. 2013-12-06 15:53:40 +08:00
Cheng Zhao
844fccc177 Use random number as id in CallbacksRegistry.
It's very possible that the callbacks got GCed before the render view is
closed (like page getting refreshed), so we should not let browser call
the wrong callback, instead we should throw error whenever a callback is
not found.
2013-12-06 15:04:51 +08:00
Cheng Zhao
0a63395b0f 💄 Restore old settings in app specs. 2013-12-06 14:54:29 +08:00
Cheng Zhao
623e0f3ae4 Release render view's remote objects when it's deleted.
Privously we release them when the window is unloaded, which is not
correct since a render view can have multiple windows (or js contexts)
and when the unload event is emitted the render view could already have
gone.

This PR does the cleaning work purely in browser, so here is no need to
worry about renderer's life time.
2013-12-06 14:44:25 +08:00
Cheng Zhao
e9e90b481a 💄 Fix cpplint warnings. 2013-12-05 23:54:57 +08:00
Cheng Zhao
4a1ee39156 Get rid of manually converting to base::Value when possible. 2013-12-05 23:47:07 +08:00
Cheng Zhao
e5afa72b4d Fail quietly when getting null renderer view.
It happens when the window is closing.
2013-12-05 23:34:43 +08:00
Cheng Zhao
287c948845 Enable getting scoped_ptr type from v8 value.
God damned C++ template.
2013-12-05 23:25:14 +08:00
Cheng Zhao
4625f051c8 Simplify V8 operations in renderer ipc code. 2013-12-05 22:12:27 +08:00
Cheng Zhao
8d271a6655 Update node: Fixed a handle leak in fs.statNoException(). 2013-12-05 21:41:39 +08:00
Cheng Zhao
65b3435156 Bump v0.7.5. 2013-12-05 13:48:19 +08:00
Cheng Zhao
3c60e07653 Merge pull request #136 from atom/fix-ua
Use name and version information of package.json
2013-12-04 21:44:35 -08:00
Cheng Zhao
564c5c1664 Add simple specs for app.getName() and app.getVersion(). 2013-12-05 13:37:01 +08:00
Cheng Zhao
5f4a9316f1 📝 Add usage of productName of package.json. 2013-12-05 11:46:36 +08:00
Cheng Zhao
a0c0bb18b7 Choose a better name for the default_app. 2013-12-05 11:31:16 +08:00
Cheng Zhao
284160bf2d Set application's name and version from the package.json. 2013-12-05 11:30:06 +08:00
Cheng Zhao
0229c3187b Override the user agent to contain application and atom-shell's version. 2013-12-05 11:21:11 +08:00
Cheng Zhao
eec8560119 📝 Update documentation on changes of "app" module. 2013-12-05 11:02:09 +08:00
Cheng Zhao
fc4ed9be12 Use bundle's name as application name when we have one. 2013-12-05 10:42:04 +08:00
Cheng Zhao
a614134144 Simplify V8 operations. 2013-12-05 10:35:57 +08:00
Cheng Zhao
5670ee7693 Add API to get and override application name. 2013-12-05 10:32:58 +08:00
Cheng Zhao
420ae1a2cc Add API to override browser version. 2013-12-05 10:26:01 +08:00
Cheng Zhao
02bbf07d3a Enable overriding UA strings. 2013-12-05 10:08:11 +08:00
Cheng Zhao
121163f9ca Add conversions between V8 Value and GURL. 2013-12-05 10:07:51 +08:00
Kevin Sawicki
d79626f02f 📝 Update repo link to atom/atom 2013-12-04 09:09:30 -08:00
Cheng Zhao
7cffbc8a1a Bump v0.7.4. 2013-12-04 22:12:58 +08:00
Cheng Zhao
170ef2362f Merge pull request #133 from atom/sheet-unresponsive
Do not send "unresponsive" message if window is showing a modal dialog.
2013-12-04 06:11:38 -08:00
Cheng Zhao
e45f83e62a Make sure browserWindow.destroy() doesn't leave zombie processes. 2013-12-04 22:00:20 +08:00
Cheng Zhao
687c9de5d7 win: Implement NativeWindowWin::HasModalDialog(). 2013-12-04 21:18:53 +08:00
Cheng Zhao
e43b39a009 Do not send "unresponsive" message if window is showing a modal dialog. 2013-12-04 17:18:55 +08:00
Cheng Zhao
bfe8928ab1 Do not use flags to mark whether the window is unresponsive.
It's error prone.
2013-12-04 17:10:59 +08:00
Cheng Zhao
d6d1604623 mac: Add API to return whether the window has attached sheet. 2013-12-04 16:32:32 +08:00
Cheng Zhao
7d5826df85 Add "Cmd" and "Control" alias for "Command" and "Ctrl". 2013-11-29 16:31:38 +08:00
Cheng Zhao
9493c1b0bb Bump v0.7.3. 2013-11-29 16:22:27 +08:00
Cheng Zhao
a2aa20b6b2 Add "Edit" menu in specs window. 2013-11-29 16:21:43 +08:00
Cheng Zhao
c8d0968e00 Use CommandOrControl to replace Command in specs windows. 2013-11-29 16:14:44 +08:00
Cheng Zhao
8237edcf0d Add "CommandOrControl" to represent "Command" on OS X and "Ctrl" on other platforms. 2013-11-29 16:11:48 +08:00
Cheng Zhao
13261921a7 Merge pull request #130 from atom/force-closing
Send the "unresponsive" event if window does not close or cancel the close in 500ms when closing it.
2013-11-28 23:42:27 -08:00
Cheng Zhao
adc5495d2b Prompt unresponsive state in spec window. 2013-11-29 15:19:30 +08:00
Cheng Zhao
02d14ed23b Fix returning the chosen option for synchronous dialogs. 2013-11-29 15:19:00 +08:00
Cheng Zhao
a0a5b20ef1 Send the "unresponsive" event if window is not closed in 500ms when closing it. 2013-11-29 14:52:12 +08:00
Cheng Zhao
fd081e162b Bump v0.7.2. 2013-11-28 21:00:40 +08:00
Cheng Zhao
30be4a847f win: Do not generate symbols for static libraries and strip .pdb in symbol name. 2013-11-28 20:53:07 +08:00
Cheng Zhao
0d77ba5222 No need to ship atom.exe.pdb any more. 2013-11-28 20:14:45 +08:00
Cheng Zhao
94569f7f8c Fix executing python script in gyp. 2013-11-28 20:11:06 +08:00
Cheng Zhao
fdfff63119 💄 Wrong IP for default crash reporter server. 2013-11-28 12:38:33 +08:00
Cheng Zhao
da03784610 Bump v0.7.1. 2013-11-23 01:09:42 -08:00
Cheng Zhao
deef68bcf9 Also search libchromiumcontent download dir for dSYMs. 2013-11-23 01:07:38 -08:00
Cheng Zhao
6393e2e1e5 Bump v0.7.0. 2013-11-27 16:11:19 +08:00
Cheng Zhao
bf77fcc03e Merge pull request #124 from atom/breakpad
Use breakpad for crash reporting
2013-11-26 23:33:43 -08:00
Cheng Zhao
386b921914 win: Register msdia80.dll automatically when dumping symbols. 2013-11-26 22:05:32 +08:00
Cheng Zhao
401fe76acd 💄 Add missing ""s. 2013-11-26 21:35:19 +08:00
Cheng Zhao
2fd3616ef3 win: Implement the atom_dump_symbols target. 2013-11-26 21:34:27 +08:00
Cheng Zhao
ffaf535d00 Add script to generate symbols from pdbs on Windows. 2013-11-26 21:23:50 +08:00
Cheng Zhao
9ac5ea5a6c Mention that pyobjc is needed for homebrew python. 2013-11-26 11:46:45 +08:00
Cheng Zhao
edf7496443 Also clean up libchromiumcontent in cibuild. 2013-11-26 11:04:37 +08:00
Cheng Zhao
151b2b5ad5 Also upload product name, company name and version in crash report. 2013-11-26 10:19:50 +08:00
Cheng Zhao
1fc9ef33db Remove the build directory beforing rebuilding in cibuild. 2013-11-26 09:39:24 +08:00
Cheng Zhao
858f21a69c mac: Dump symbols from .dSYM when possible. 2013-11-26 09:30:51 +08:00
Cheng Zhao
3a4835ff1c Also download libchromiumcontent symbols on Mac. 2013-11-25 23:13:58 +08:00
Cheng Zhao
47d37cc1e3 Download libchromiumcontent symbols when creating symbols. 2013-11-25 16:02:35 +08:00
Cheng Zhao
a5224f705d mac: Use "Atom Framework.framework" instead of "Atom.framework".
The "Atom.framework" would confuse breakpad with "App.app" when finding
symbols.
2013-11-25 15:37:39 +08:00
Cheng Zhao
b737e602b7 mac: Store crash dumps under /tmp/ProductName Crashes/.
If we put them under ~/Library/ then we need to clean them, which makes
things more complicated.
2013-11-24 23:42:54 +08:00
Cheng Zhao
59f586ba59 Use "Atom-Shell" instead of "atom-shell" for product names. 2013-11-24 23:17:48 +08:00
Cheng Zhao
70b7659893 win: Set uploading parameters in crash reporter. 2013-11-24 22:57:47 +08:00
Cheng Zhao
717b664802 win: Make out-of-process crash dump work. 2013-11-24 22:22:08 +08:00
Cheng Zhao
75e1fb63c8 Start the crash service process on non-Mac. 2013-11-24 20:45:12 +08:00
Cheng Zhao
a9c20dc42f 💄 Remove ununsed "display_name". 2013-11-24 20:36:08 +08:00
Cheng Zhao
dce7e50636 win: Setup crash service according to command line parameters. 2013-11-24 20:33:26 +08:00
Cheng Zhao
edd2bd74c9 win: Print crash service's log to file. 2013-11-24 18:17:31 +08:00
Cheng Zhao
6f8c46d2f4 win: Start as crash service when ATOM_SHELL_INTERNAL_CRASH_SERVICE is set. 2013-11-24 17:35:58 +08:00
Cheng Zhao
4bab284f2e Add crash_service on Windows. 2013-11-23 20:26:47 +08:00
Cheng Zhao
59b3e74542 Merge branch 'master' into breakpad 2013-11-22 19:37:34 +08:00
Cheng Zhao
4af646b760 Bump v0.6.12. 2013-11-22 15:18:21 +08:00
Cheng Zhao
5720d4f802 Merge pull request #128 from atom/api-capture-page
Add BrowserWindow.capturePage API.
2013-11-21 22:52:22 -08:00
Cheng Zhao
80824b13c6 Add spec for BrowserWindow.capturePage. 2013-11-22 14:42:39 +08:00
Cheng Zhao
33ad68f7a7 doc: Explain BrowserWindow.capturePage. 2013-11-22 14:39:10 +08:00
Cheng Zhao
4af802f215 Enable ignoring |rect| when calling BrowserWindow.capturePage. 2013-11-22 14:29:20 +08:00
Cheng Zhao
3b4a45ac65 Add BrowserWindow.capturePage API. 2013-11-22 14:23:19 +08:00
Cheng Zhao
a0548530e7 Enable converting V8 value to gfx::Rect. 2013-11-22 14:22:28 +08:00
Cheng Zhao
8d6764e0a0 Return screenshot's data buffer instead of directly saving to file. 2013-11-21 22:03:29 +08:00
Cheng Zhao
36ecb35cb1 Add API to capture a page into file. 2013-11-21 21:50:06 +08:00
Cheng Zhao
9ad3b7939f Bump v0.6.11. 2013-11-20 22:51:26 +08:00
Cheng Zhao
8493975840 doc: Mention that Command would not be meaningful on Windows. 2013-11-20 22:48:47 +08:00
Cheng Zhao
ec880d64bf Merge pull request #125 from atom/dont-map-meta
Don't map command to ctrl
2013-11-20 06:35:20 -08:00
Matt Colyer
113d644615 Don't map command to ctrl
We no longer what this behavior because it's confusing unless you
understand that atom-shell does this.
2013-11-19 15:18:54 -08:00
Cheng Zhao
4105527d07 win: Initialize exception handler. 2013-11-19 21:37:02 +08:00
Cheng Zhao
2228184066 Cause a real crash instead of debugger break in process.crash().
On Windows the debugger break would not be treated as crash.
2013-11-19 21:36:18 +08:00
Cheng Zhao
1af4ecfc26 win: Make console output work on cygwin. 2013-11-19 20:56:22 +08:00
Cheng Zhao
9981fd51da win: Fix error when bootstraping. 2013-11-19 20:43:30 +08:00
Cheng Zhao
458ff5c41f Always use atom-shell as product name.
Since the symbols of atom-shell would be used by all third party
applications, it would make server handling more complicated if we allow
users to custom the uploaded product name. We should always use
atom-shell as product name when uploading so the server would not be
confused when searching symbols, and the user specified product name
could be show in UI.
2013-11-19 12:33:02 +08:00
Cheng Zhao
7735d8fbfd Update default crash report submission URL. 2013-11-19 12:27:20 +08:00
Cheng Zhao
20e368eb89 Do not append "Renderer" in product name when uploading. 2013-11-19 12:19:59 +08:00
Cheng Zhao
ed3358e501 Add spec for custom uploading parameters. 2013-11-18 18:37:32 +08:00
Cheng Zhao
d181ff4e7f Enable customing upload parameters for sending crash report. 2013-11-18 18:27:50 +08:00
Cheng Zhao
f8f09eb974 Enable converting v8 object to dict type. 2013-11-18 18:15:34 +08:00
Cheng Zhao
28b692aeaa Always use atom-shell's verion when uploading crash report. 2013-11-18 18:03:41 +08:00
Cheng Zhao
aef6d44a01 Also upload symbols to GitHub Release. 2013-11-18 18:02:38 +08:00
Cheng Zhao
e4b4087fdb Create symbols zip file when creating distribution. 2013-11-18 11:41:44 +08:00
Cheng Zhao
1d2de6d1fb mac: Add target to dump breakpad symbols. 2013-11-15 22:52:08 +08:00
Cheng Zhao
67dd596386 Enable starting crash-reporter without parameters. 2013-11-15 11:00:48 +08:00
Cheng Zhao
bd0836581b Check the upload parameters in crash-reporter spec. 2013-11-15 10:37:22 +08:00
Cheng Zhao
cdb5e24d2f Add spec for crash-reporter 2013-11-15 00:10:43 +08:00
Cheng Zhao
6b02be6da8 Add extra uploading parameters for crash reporter. 2013-11-14 18:02:15 +08:00
Cheng Zhao
d1a5c49843 win: Add stubs for crash reporter. 2013-11-14 13:42:28 +08:00
Cheng Zhao
dd4e43eb02 doc: Update new crash-reporter API. 2013-11-14 13:39:44 +08:00
Cheng Zhao
9007a45051 Refactor crash reporter to be more cross-platform friendly. 2013-11-14 13:33:09 +08:00
Cheng Zhao
801a19504a No more downloading QuincyKit. 2013-11-13 19:19:57 +08:00
Cheng Zhao
a6989847ea Add API to set product name for crash reporter. 2013-11-13 19:12:13 +08:00
Cheng Zhao
e7d25385b0 Add "Renderer" suffix in name when crashing in renderer process. 2013-11-13 19:06:11 +08:00
Cheng Zhao
62f200d252 Mention in doc that crash-reporter is available for renderer. 2013-11-13 17:30:49 +08:00
Cheng Zhao
374cf948e4 Make the crash reporter available for both browser and renderer. 2013-11-13 17:29:35 +08:00
Cheng Zhao
8f558fb252 mac: Tune parameters of breakpad. 2013-11-13 17:20:52 +08:00
Cheng Zhao
8f2dd91e34 Setup breakpad in crash reporter. 2013-11-13 17:20:52 +08:00
Cheng Zhao
896c1793d3 mac: Copy necessary breakpad binaries to package. 2013-11-13 17:20:51 +08:00
Cheng Zhao
85428d8eb3 No more use of QuincyKit. 2013-11-13 17:20:51 +08:00
Cheng Zhao
57bee8b788 Update to latest gyp and depot_tools. 2013-11-12 18:34:01 +08:00
Cheng Zhao
0ad51c394b mac: Get rid of all the third party warnings. 2013-11-12 18:16:37 +08:00
Cheng Zhao
e8455d5c9a Add breakpad as build dependency. 2013-11-12 18:07:25 +08:00
Cheng Zhao
2768eaa676 Add breakpad. 2013-11-12 15:49:03 +08:00
Cheng Zhao
6c0621fe05 Bump v0.6.10. 2013-11-11 20:04:15 +08:00
Cheng Zhao
baa6d9730c win: Enable setting window icon in creation options. 2013-11-11 19:29:40 +08:00
Cheng Zhao
d5ffa4dc77 Fix a possible dead lock when quiting.
It could happen that we are quitting when the embed thread is still
waiting for the main thread, so we make sure embed thread is always
signaled when quitting.
2013-11-11 16:59:57 +08:00
Cheng Zhao
01dd5638d0 Update brightray for fixing the 'ARCHS' issue. 2013-11-08 19:05:30 -08:00
Cheng Zhao
ec5cd2fb1c Do not set sdk_root, it's already set by brightray. 2013-11-08 19:01:56 -08:00
Cheng Zhao
44c0dc9104 Bump v0.6.9. 2013-11-07 16:59:45 +08:00
Cheng Zhao
7324f0468b 💄 fix typo. 2013-11-07 16:59:33 +08:00
Cheng Zhao
64e3a6b437 Add x permission for bump-version.py. 2013-11-07 16:58:09 +08:00
Cheng Zhao
690ab7d4ae Add tag and commit after version is bumped. 2013-11-07 15:41:14 +08:00
Cheng Zhao
48a0ac9a96 Update Info.plist when bumping version. 2013-11-07 15:37:21 +08:00
Cheng Zhao
7212fa1056 Also update atom_version.h and atom.rc in bump-version.py. 2013-11-07 15:19:37 +08:00
Cheng Zhao
8d710609fd win: Fix setting icon after format of atom.rc has changed. 2013-11-07 15:09:45 +08:00
Cheng Zhao
7dcbd11863 Conver atom.rc from unicode file to ASCII file. 2013-11-07 15:06:57 +08:00
Cheng Zhao
e075a8b49e Add tool to help bump version. 2013-11-07 12:52:26 +08:00
Cheng Zhao
d1dc041aaf win: Use exe's icon as window icon, fixed #123. 2013-11-07 11:06:25 +08:00
Cheng Zhao
85243edf4e win: Add an icon. 2013-11-07 09:55:59 +08:00
Cheng Zhao
faeea88b16 Write correct version in .rc file. 2013-11-05 22:26:33 +08:00
Cheng Zhao
139d581e5b Bump v0.6.8. 2013-11-05 13:15:17 +08:00
Cheng Zhao
64b2d0da36 Add a corresponding .h file for atom_main.cc.
It's required if we want to include Chromium headers before C headers
and do not break cpplint rules in the meanwhile.
2013-11-05 13:12:13 +08:00
Cheng Zhao
dc1a8b644a Get the status of devtools from brightray, fixed #27. 2013-11-05 10:32:45 +08:00
Cheng Zhao
8bb3b53833 Make cpplint pass headers test without setting "NOLINT". 2013-11-05 10:00:11 +08:00
Cheng Zhao
8112fe741e Merge pull request #122 from atom/fix-console-stdio
Fix console STDIO
2013-11-04 17:11:53 -08:00
Paul Betts
60f24eb22b This method seems to work, :shipit: 2013-11-04 16:56:50 -08:00
Paul Betts
fd20050fc9 First hack at fixing console IO 2013-11-04 14:15:19 -08:00
Cheng Zhao
c5946bf977 Bump v0.6.7. 2013-11-02 16:49:21 +08:00
Cheng Zhao
618d0c6397 Fix the "'true' is not recognized as an internal or external command" error. 2013-11-01 10:15:41 +08:00
Cheng Zhao
362bb6e68b Mention required options of WDK and Win7 SDK, fixed #114. 2013-10-31 20:06:36 +08:00
Cheng Zhao
b88168c0d2 Bump v0.6.6. 2013-10-28 10:47:57 +08:00
Cheng Zhao
df919a4be8 Expose libuv's symbols. 2013-10-28 10:47:04 +08:00
Cheng Zhao
45f864d2b4 Make atom-shell compile-able with VS 2010 Express. 2013-10-26 19:39:45 +08:00
Cheng Zhao
602f02b867 💄 Fix typo of doc. 2013-10-26 18:09:22 +08:00
Cheng Zhao
5cf61c9ab4 Add more details on building with VS 2010 Express. 2013-10-26 18:07:20 +08:00
Cheng Zhao
49a7954824 Bump v0.6.5. 2013-10-26 17:49:44 +08:00
Cheng Zhao
198b52bf40 win: Ship the pdb file, fixes #112. 2013-10-26 17:44:51 +08:00
Cheng Zhao
cb31140d3a Do "compress" the archive when creating zip.
By default the zipfile module doesn't do the compression unless we
explictly specify the method.
2013-10-26 17:42:12 +08:00
Cheng Zhao
f2c1d8f4b2 Update to latest apm. 2013-10-26 17:24:40 +08:00
Cheng Zhao
3ddba90d94 Fix creating zip distribution on Windows. 2013-10-26 17:23:16 +08:00
Cheng Zhao
887a2a3c00 Bump v0.6.4. 2013-10-22 10:25:53 +08:00
Cheng Zhao
585777e62d Allow single-character accelerators. 2013-10-22 09:38:19 +08:00
Cheng Zhao
640f45a5b3 Fix a possible crash when calling AdapterRequestJob::Kill(). 2013-10-22 09:33:38 +08:00
Cheng Zhao
8bcb545119 Bump v0.6.3. 2013-10-21 18:22:16 +08:00
Cheng Zhao
aa911cdb2e Merge pull request #110 from atom/better-accelerator
Support more accelerators in menu, closes #107.
2013-10-21 01:53:34 -07:00
Cheng Zhao
27be89d39a Should not touch process.argv when starting the default_app. 2013-10-21 16:48:52 +08:00
Cheng Zhao
5ce66fca5c Do not use sscanf. 2013-10-21 15:59:45 +08:00
Cheng Zhao
94e4044160 Allow "Space" in accelerator. 2013-10-21 15:35:54 +08:00
Cheng Zhao
30eabfb9f6 Allow "F1" - "F24" in accelerator. 2013-10-21 15:33:19 +08:00
Cheng Zhao
a6eb261af0 Get rid of the NormalizeShortcutSuggestion function. 2013-10-21 14:34:25 +08:00
Cheng Zhao
6e4f74ae35 Allow more special keys in the accelerator. 2013-10-21 14:25:36 +08:00
Cheng Zhao
f091352c56 Slightly optimize accelerator token comparing. 2013-10-21 14:05:43 +08:00
Cheng Zhao
534ff5efdb Be case-insensible of accelerators. 2013-10-21 13:46:37 +08:00
Cheng Zhao
51d92454ce Map all single symbols in the keyboard to accelerators. 2013-10-21 13:39:55 +08:00
Cheng Zhao
af413b2d97 Bump v0.6.2. 2013-10-17 10:22:35 +08:00
Cheng Zhao
7c30d037a3 mac: Enable to set the 'Help' menu, fixes #109. 2013-10-17 10:21:24 +08:00
Cheng Zhao
acda56210b Specify the version instead of using "*" for dependencies in package.json. 2013-10-17 09:58:55 +08:00
Cheng Zhao
61b2377cf2 Use stream-uploading to upload the asset to GitHub. 2013-10-15 09:04:05 +08:00
Cheng Zhao
7fa6407f65 Bump v0.6.1. 2013-10-14 11:59:19 +08:00
Cheng Zhao
41de0b420a Unescape the script path before passing it to cefode.js, fixed #108. 2013-10-14 11:58:20 +08:00
Cheng Zhao
0ad1fc842d Do not multipart-encode the uploaded file. 2013-10-10 18:05:01 +08:00
Cheng Zhao
7f0e7f3835 Check the build version of Release build in upload script. 2013-10-10 14:39:54 +08:00
Cheng Zhao
6ff644fe60 Bump v0.6.0. 2013-10-10 14:35:37 +08:00
Cheng Zhao
92c68797d0 Enable more common ASCII tokens to be used in accelerator, fixes #107. 2013-10-10 14:33:59 +08:00
Cheng Zhao
9a2fc8f4ea Add 'Quit' to spec window's menu. 2013-10-10 14:33:42 +08:00
Cheng Zhao
6a712d4db4 Merge pull request #105 from atom/windows-menu
Implement menu API on Windows, fixes #75.
2013-10-06 17:58:42 -07:00
Cheng Zhao
a182de20a4 win: Newly created window should also be aware of application menu. 2013-10-07 08:56:52 +08:00
Cheng Zhao
caaab22841 Do not dereference remote callback if its renderer view is released. 2013-10-05 20:53:31 +08:00
Cheng Zhao
1e1fec15b6 Make objects registry code more structured. 2013-10-05 20:47:49 +08:00
Cheng Zhao
1524ced816 Set application menu would set menu for all windows on Windows. 2013-10-05 14:31:30 +08:00
Cheng Zhao
93f1a3dbd5 Make app.setApplicationMenu an alias to Menu.setApplicationMenu. 2013-10-05 13:46:48 +08:00
Cheng Zhao
666f6b3a01 Add app.getBrowserWindows() API. 2013-10-05 13:13:04 +08:00
Cheng Zhao
61cc0bba25 💄 fix typo in doc. 2013-10-05 13:03:08 +08:00
Cheng Zhao
587484a5d0 Make sure application menu always get referenced. 2013-10-05 12:56:30 +08:00
Cheng Zhao
defb6c9882 Don't wait for request in http spec.
This spec is used to crash atom-shell, we don't care if http request
succeeds.
2013-10-04 23:39:34 +08:00
Cheng Zhao
55a35d473d win: Make web view focused initialy. 2013-10-04 23:38:37 +08:00
Cheng Zhao
d86172cc87 win: Make window menu's accelerators work. 2013-10-04 23:36:31 +08:00
Cheng Zhao
32432cc770 Convert "Command" to "Ctrl" in accelerators on non-Mac. 2013-10-04 23:01:29 +08:00
Cheng Zhao
ae98d9c8b6 💄 NativeWindowClientView no longer needs a extra content view. 2013-10-04 09:04:32 +08:00
Cheng Zhao
4e2d3f3d12 win: Make native window a views::View. 2013-10-04 08:52:45 +08:00
Cheng Zhao
a2f679e4bd win: Respond to events of window menu. 2013-10-03 23:34:42 +08:00
Cheng Zhao
06ae5c06b8 Make sure binary version is dumped before uploading. 2013-10-03 11:48:13 +08:00
Cheng Zhao
0483871388 Add --version flag to print atom-shell's version. 2013-10-03 11:36:17 +08:00
Cheng Zhao
7f7e13edc3 Dump v0.5.4. 2013-10-03 10:06:34 +08:00
Cheng Zhao
bbb9c37f70 BrowserWindow.focus() should not make window become visible, fixed #106. 2013-10-03 09:42:20 +08:00
Cheng Zhao
88ce2a5390 Add BrowserWindow.isVisible() API. 2013-10-03 08:28:22 +08:00
Cheng Zhao
6748573dee Show a simple menu in default_app on Windows. 2013-10-02 21:51:19 +08:00
Cheng Zhao
5c8566e0d4 win: Show popup menu at right place. 2013-10-02 21:43:52 +08:00
Cheng Zhao
5a6ff0f80d win: Add BrowserWindow.setMenu API. 2013-10-02 21:24:21 +08:00
Cheng Zhao
2024ae5dba 💄 Fix build on Windows. 2013-10-02 20:43:30 +08:00
Cheng Zhao
aa6d5a3ff6 Update to latest apm. 2013-10-02 20:26:25 +08:00
Cheng Zhao
419da689c9 Dump v0.5.3. 2013-09-29 21:50:19 +08:00
Cheng Zhao
709563c090 Set proxy service at the right place. 2013-09-29 21:43:17 +08:00
Cheng Zhao
b50a2c9dc1 Add spec for sending http request. 2013-09-29 20:57:57 +08:00
Cheng Zhao
43a5453de5 💄 Fix target version of atom-shell's uploading. 2013-09-29 20:18:55 +08:00
Cheng Zhao
87d94ff1ae Do not require uploading a tag before publish release. 2013-09-29 15:31:20 +08:00
Cheng Zhao
8b4414345b Dump v0.5.2. 2013-09-29 15:28:58 +08:00
Cheng Zhao
6e43074586 Still upload distribution file to S3 since Atom hasn't used Releases API yet. 2013-09-29 15:15:16 +08:00
Cheng Zhao
99d901bc9a Switch to use the ProxyResolverV8, fixes atom/atom#894. 2013-09-29 15:06:29 +08:00
Cheng Zhao
95e79124eb Do not publish release when body of release note is empty. 2013-09-27 15:55:46 +08:00
Cheng Zhao
54b0d0c9c0 Free the native window's memory after the event were sent for all observers.
If we delete the window immediately other observers may get a invalid
window and cause random crashes.
2013-09-27 15:24:03 +08:00
Cheng Zhao
10a46b4229 Merge pull request #104 from atom/pylint
Lint python and coffee scripts
2013-09-26 20:06:10 -07:00
Cheng Zhao
af3f07f4cc 💄 Adding trailing comma in package.json. 2013-09-27 11:03:38 +08:00
Cheng Zhao
f4f42b30ee 💄 Fix warnings of coffeelint. 2013-09-27 11:03:23 +08:00
Cheng Zhao
f3eef6cc2e Do not warn about 80 columns in coffeelint, it's not required. 2013-09-27 11:01:40 +08:00
Cheng Zhao
11f387743f Add wrapper script for coffeelint. 2013-09-27 10:49:55 +08:00
Cheng Zhao
561857d640 Add coffeelint to dependencies. 2013-09-27 10:44:16 +08:00
Cheng Zhao
3b3585f575 Skip the check for lib.github. 2013-09-27 10:43:10 +08:00
Cheng Zhao
6be716c6e8 Run pylint in cibuild. 2013-09-27 10:22:13 +08:00
Cheng Zhao
2b923b988c Add wrapper script for pylint. 2013-09-27 10:21:49 +08:00
Cheng Zhao
ef8a05be38 💄 Fix violations against pylint. 2013-09-27 10:21:27 +08:00
Cheng Zhao
c029ff2055 Merge pull request #103 from atom/releases-api
Upload atom-shell's binaries with Releases API
2013-09-26 18:46:35 -07:00
Cheng Zhao
e376850552 💄 Fix cpplint warnings. 2013-09-27 09:26:36 +08:00
Cheng Zhao
1ce61c7845 Get the body of release with current $EDITOR. 2013-09-27 09:10:22 +08:00
Cheng Zhao
68a3fd6f05 Publish the release after the uploading is end. 2013-09-26 22:02:09 +08:00
Cheng Zhao
ce012043fa Upload both atom-shell and node's headers. 2013-09-26 21:20:38 +08:00
Cheng Zhao
ae70d5cb64 Silence the output of upload script. 2013-09-26 20:58:51 +08:00
Cheng Zhao
db359ae75c Upload the asset after release note is created. 2013-09-26 20:32:11 +08:00
Cheng Zhao
3586565bba Handle the assets uploading in the GitHub API library. 2013-09-26 20:31:17 +08:00
Cheng Zhao
fe67ecd7fd 💄 Find the release even when commit isn't tagged. 2013-09-26 19:54:28 +08:00
Cheng Zhao
33c509b867 Create new release note or get the existing one when uploading. 2013-09-26 19:49:09 +08:00
Cheng Zhao
3edfb7d5c3 Correctly deal with API errors. 2013-09-26 19:48:48 +08:00
Cheng Zhao
eed2b0fd81 Accept still-preview apis. 2013-09-26 16:38:08 +08:00
Cheng Zhao
4c4b8a8486 Add a simple wrapper of GitHub API. 2013-09-26 16:32:39 +08:00
Cheng Zhao
2b9a533d1d Add process.getCurrentStackTrace(), returning V8::getCurrentStackTrace(). 2013-09-26 13:31:17 +08:00
Cheng Zhao
b3a2302283 Dumpv 0.5.1. 2013-09-26 11:30:16 +08:00
Cheng Zhao
6bee435170 Destroy the event object immediately after the reply is sent, fixes #102. 2013-09-26 11:28:53 +08:00
Cheng Zhao
5480cf58c2 Add spec for destroying synchronous event. 2013-09-26 11:27:09 +08:00
Cheng Zhao
65176761f4 Dump v0.5.0. 2013-09-25 16:51:55 +08:00
Cheng Zhao
cf75e4ac49 Move atom_event_processing_window to browser/ui. 2013-09-25 16:51:55 +08:00
Cheng Zhao
ac68589291 cocoa: Don't use Chrome's UnderlayOpenGLHostingWindow.
The UnderlayOpenGLHostingWindow would add a semi-transparent layer under
the window, I'm not very sure what does this class exactly do, but
removing it seems no harm to the renderer.

Fixes atom/atom#877.
2013-09-25 16:51:33 +08:00
Cheng Zhao
bc95cac3ed 💄 Same indent. 2013-09-25 16:18:33 +08:00
Cheng Zhao
eed8f6cabc Remove the CustomFrameView, it's no longer needed. 2013-09-25 15:40:22 +08:00
Cheng Zhao
6aefb0f76f Merge pull request #101 from atom/no-blocking-browser
Make the browser non-blocking
2013-09-24 16:48:29 -07:00
Cheng Zhao
14de58a6b7 Calling asynchronous functions in renderer now doesn't block browser. 2013-09-24 18:01:12 +08:00
Cheng Zhao
085f0a2544 win: Implement asynchronous ShowMessageBox. 2013-09-24 16:11:23 +08:00
Cheng Zhao
4000734504 win: Add dummy implementation for asynchronous open/save dialog. 2013-09-24 14:47:39 +08:00
Cheng Zhao
1b5e22f9c4 Default template parameter is not supported on Windows. 2013-09-24 14:41:44 +08:00
Cheng Zhao
53c6d51d56 win: Accept parent window in ShowOpenDialog. 2013-09-24 10:13:43 +08:00
Cheng Zhao
ac76017702 Merge branch 'master' into no-blocking-browser 2013-09-24 10:09:35 +08:00
Cheng Zhao
9927b4bf4c Merge pull request #93 from atom/file-dialog
Implement file dialogs API on Windows
2013-09-23 19:08:00 -07:00
Cheng Zhao
11ca836afc Use the convient V8 wrapper in all files. 2013-09-24 09:41:54 +08:00
Cheng Zhao
a824c88352 Use same name convention in string16_conversions. 2013-09-23 23:00:58 +08:00
Cheng Zhao
8fdd3b3044 Use FromV8Arguments in atom_api_dialog.cc. 2013-09-23 22:52:48 +08:00
Cheng Zhao
1e5e0194bd Add convient function for converting args from V8 Arguments. 2013-09-23 22:48:55 +08:00
Cheng Zhao
a0d1a7620c Put FromV8Value and ToV8Value to a new header. 2013-09-23 21:30:54 +08:00
Cheng Zhao
770a0068a3 Simplify conversions between native types and v8 types. 2013-09-23 21:12:40 +08:00
Cheng Zhao
26f0e49c9a Make dialog.showSaveDialog accept a callback. 2013-09-23 20:08:49 +08:00
Cheng Zhao
c7637c78d1 mac: Add asynchronous ShowSaveDialog. 2013-09-23 20:08:32 +08:00
Cheng Zhao
30ca085fd8 Make dialog.showSaveDialog accept no parent window. 2013-09-23 19:59:00 +08:00
Cheng Zhao
e824b6c910 💄 Pick duplicate code together. 2013-09-23 19:42:07 +08:00
Cheng Zhao
43b492c641 mac: make ShowSaveDialog accept no parent window. 2013-09-23 19:36:52 +08:00
Cheng Zhao
c95cfc9540 Make dialog.showOpenDialog accept callback. 2013-09-23 19:23:49 +08:00
Cheng Zhao
d3dd2b4332 mac: Add asynchronous ShowOpenDialog. 2013-09-23 19:22:36 +08:00
Cheng Zhao
7e86ee37f3 💄 cpplint. 2013-09-23 17:27:32 +08:00
Cheng Zhao
f444e9dc74 💄 CoffeeScript is cute. 2013-09-23 16:51:00 +08:00
Cheng Zhao
76ac8f2719 Enable taking window as parameter in dialog.showOpenDialog. 2013-09-23 16:36:33 +08:00
Cheng Zhao
a4262bc39d mac: Make ShowOpenDialog able to be shown as sheet. 2013-09-23 16:27:22 +08:00
Cheng Zhao
85d6588661 Make dialog.showMessageBox asynchronous. 2013-09-23 14:29:55 +08:00
Cheng Zhao
b70722feb6 mac: Implement async ShowMessageBox. 2013-09-22 18:47:00 +08:00
Cheng Zhao
bfe59480e3 Add header for asynchronous version of ShowMessageBox. 2013-09-22 17:11:09 +08:00
Cheng Zhao
68bdad9a23 Add spec for ipc.sendSync. 2013-09-22 12:06:41 +08:00
Cheng Zhao
761b9d22c8 Do not reply sync messages when window is closed. 2013-09-22 10:44:18 +08:00
Cheng Zhao
1e4762ce92 Do not store the event.returnValue. 2013-09-22 10:03:47 +08:00
Cheng Zhao
d443b36446 Send reply for sync messages when event.returnValue is set. 2013-09-22 09:52:58 +08:00
Cheng Zhao
ef4b36d621 Use string16 instead of std::string when sending IPC messages.
The underlying V8::String is represented in UTF18, by using string16 in
IPC messages we can avoid the overhead of encode conversion.
2013-09-20 22:55:42 +08:00
Cheng Zhao
ef5a4b5fe0 Pass synchronous messages by JSON string.
We are going to use IPC_MESSAGE_HANDLER_DELAY_REPLY to handle
synchronous messages but DictionaryValue is not copyable, so we pass the
JSON string instead.
2013-09-20 22:32:59 +08:00
Cheng Zhao
07b5039c64 Make sure all sync messages get a return value. 2013-09-20 21:39:07 +08:00
Cheng Zhao
a9c824eba1 Use event.returnValue instead of event.result in atom-shell's code.
event.result is still kept for backward compatible.
2013-09-20 21:37:47 +08:00
Cheng Zhao
b225a59a15 Prefer event.returnValue to event.result for sync messages. 2013-09-20 21:37:00 +08:00
Cheng Zhao
50b5272354 Dump v0.4.9. 2013-09-20 18:50:18 +08:00
Cheng Zhao
8879334468 Merge pull request #100 from atom/fix-protocol-crash
Fix crash when using protocol module on startup.
2013-09-20 03:49:33 -07:00
Cheng Zhao
2be1145a9e Guard against using protocol module too early. 2013-09-20 18:45:53 +08:00
Cheng Zhao
e65220adb0 doc: Mention when protocol module is safe to use. 2013-09-20 18:36:16 +08:00
Cheng Zhao
92e157de30 Fix crash when using protocol module on startup.
The job factory was not created before any request was sent, so when the
app used the protocol module on startup it would cause a crash.
2013-09-20 18:32:05 +08:00
Cheng Zhao
c908cae72c Dump v0.4.8. 2013-09-20 16:55:43 +08:00
Cheng Zhao
3f357f184d Use custom url request getter to setup request job factory. 2013-09-20 16:47:47 +08:00
Cheng Zhao
3fdec5c6e3 win: Implement ShowOpenDialog. 2013-09-19 22:28:18 +08:00
Cheng Zhao
6fced224c7 win: Open dialog and save dialog can have different options. 2013-09-18 22:27:40 +08:00
Cheng Zhao
9ed64548d4 💄 Fix comparing extension. 2013-09-18 22:24:46 +08:00
Cheng Zhao
575fe06f29 win: Append extension to save dialog's result according to the selected filter. 2013-09-18 22:21:28 +08:00
Cheng Zhao
6cb2ece285 win: Make common part of ShowSaveDialog a independet class. 2013-09-18 21:42:14 +08:00
Cheng Zhao
29e071a1ad win: Rewrite ShowSaveDialog with IFileSaveDialog. 2013-09-18 20:28:56 +08:00
Cheng Zhao
9e9579a858 Remove dialog hack for Windows XP. 2013-09-18 16:19:32 +08:00
Paul Betts
9849844e89 Merge pull request #92 from atom/paulcbetts-patch-1
Need PathService on Win32
2013-09-17 13:35:12 -07:00
Paul Betts
c578a2cbc2 Need PathService on Win32
This was accidentally left out of 8708d061
2013-09-17 11:53:31 -07:00
Cheng Zhao
583d34b9f7 Dump v0.4.7. 2013-09-13 10:12:02 +08:00
Steve Smith
a2c3690592 Merge pull request #91 from atom/rounded-corner
Round whole frame in Frameless mode
2013-09-12 08:43:30 -07:00
Steve Smith
7a21ae831f Skip the whole AtomFramelessWindow.
Just round the web view and set the bounds to the window, not the main
view.
2013-09-12 11:20:38 -04:00
Cheng Zhao
8708d0611a mac: Force using "Atom" as application name in framework bundle path. 2013-09-12 17:51:45 +08:00
Cheng Zhao
ef92cd8b45 mac: Makes sure MainMenu.nib is alwasys loaded from Atom.framework. 2013-09-12 17:16:33 +08:00
Cheng Zhao
8cb624d828 Dump v0.4.6. 2013-09-12 16:10:11 +08:00
Cheng Zhao
cec640f572 mac: Always use "Atom" as name when find helper process. Fixes #89. 2013-09-12 15:42:36 +08:00
Cheng Zhao
7a1365673e Remove code which are used for borderless window. 2013-09-12 15:13:56 +08:00
Cheng Zhao
6c098deb57 💄 Fix cpplint warnings. 2013-09-12 13:03:57 +08:00
Steve Smith
cf4a566290 Just round the top also and use a standard window.
Using borderless window causes too many issues. Smaller, less
window-like shadows being the most annoying.
2013-09-11 22:02:42 -04:00
Steve Smith
aabba3c641 Fix view autoresizing. 2013-09-11 17:25:42 -04:00
Steve Smith
8f31bf8615 Get radius working with frameless window.
Right now it's set as a constant `AtomWindowCornerRadius`, but it could
be set to a variable.
2013-09-11 16:23:17 -04:00
Cheng Zhao
5d49fc4bee WIP: rounded corner of frameless window. 2013-09-11 18:10:28 +08:00
Cheng Zhao
f38eb1b66f mac: Import chromium's CustomFrameView code. 2013-09-11 13:46:36 +08:00
Cheng Zhao
a567ba08ea Hide the fullscreen button when leaving fullscreen mode. Fixes #88. 2013-09-11 13:05:08 +08:00
Cheng Zhao
91d54a74e1 doc: Metion the frameless-window-demo. 2013-09-09 20:17:47 +08:00
Cheng Zhao
da9cce3f2d Dump v0.4.5. 2013-09-09 16:13:01 +08:00
Cheng Zhao
92241b91ce doc: Separate pages into sub directories. 2013-09-09 15:49:13 +08:00
Cheng Zhao
6b81070f67 doc: Add titles for all pages. 2013-09-09 15:35:57 +08:00
Cheng Zhao
3715dd2a20 💄 Remove a mistyped character. 2013-09-09 15:27:19 +08:00
Cheng Zhao
eb6fa98ed0 Merge pull request #85 from atom/frameless-window
Add frameless window support, fixes #72.
2013-09-09 00:24:20 -07:00
Cheng Zhao
8ddb85774a doc: Add titles for browser-window and frameless-window. 2013-09-09 15:19:09 +08:00
Cheng Zhao
8caf5fac06 doc: Document frameless window. 2013-09-09 14:52:46 +08:00
Cheng Zhao
cc62978ac3 win: Add NativeWindowFramelessView as non-client view. 2013-09-09 14:30:07 +08:00
Cheng Zhao
f833423a2f win: Save draggable region. 2013-09-09 12:12:17 +08:00
Cheng Zhao
3c0671c179 Quit when all windows are closed if running an app by passing it in command line. 2013-09-09 10:54:08 +08:00
Cheng Zhao
a00bf3e1e1 Print stack when got error on startup. 2013-09-09 10:49:28 +08:00
Cheng Zhao
ce487fe1da Make sure child scripts are quit after specs are done. 2013-09-09 09:53:08 +08:00
Cheng Zhao
a73aea3bda Update apm: set both HOME and USERPROFILE in environment under Windows. 2013-09-09 09:24:54 +08:00
Cheng Zhao
b9d994dca2 Make sure the cursor doesn't drift away when dragging window. 2013-09-06 12:12:17 +08:00
Cheng Zhao
b7c2295a1c Don't use setMouseDownCanMoveWindow to implement draggable area.
It would not work when we have the in-window devtools.
2013-09-06 11:54:52 +08:00
Cheng Zhao
da2ded5453 Implement frameless window on OS X.
Most of the code came from Chromium's packaged app window.
2013-09-05 23:52:29 +08:00
Cheng Zhao
a5eb9ea08f Add has_frame_ attribute for NativeWindow. 2013-09-05 21:43:47 +08:00
Cheng Zhao
4223867dbc Send and receive the AtomViewHostMsg_UpdateDraggableRegions message. 2013-09-05 20:06:54 +08:00
Cheng Zhao
40273cf37d Add IPC messages and structs for passing draggable regions. 2013-09-05 19:46:12 +08:00
Cheng Zhao
bc9c95d77d 💄 fix the protocol module spec on OS X. 2013-09-05 18:28:48 +08:00
Cheng Zhao
6a322f8bd6 Update apm for node v0.10.18. 2013-09-05 15:41:44 +08:00
Cheng Zhao
e7bc368785 Dump version to v0.4.4. 2013-09-05 15:17:05 +08:00
Cheng Zhao
aad0c8e996 Update node to v0.10.18. 2013-09-05 15:15:13 +08:00
Cheng Zhao
bf4756fdfb Pass PATH environment in the child_process.fork spec.
The uv_spawn under Windows requires the PATH environment variable to be
there, otherwise it would throw a 203 system error, it should be a bug
of node.
2013-09-05 14:55:22 +08:00
Cheng Zhao
8acd6d6c8a 💄 fix spec failure caused by win32 path delimiter. 2013-09-05 12:24:08 +08:00
Cheng Zhao
256215b749 Use base::Environment to replace getenv. 2013-09-05 12:18:19 +08:00
Cheng Zhao
a3e5b21118 Merge pull request #84 from atom/nested-fork
Use environment variable to detect whether to run as node.

Fixed # 83.
2013-09-04 18:55:20 -07:00
Cheng Zhao
84a3eb5411 Also fix nested child_process.fork on Windows. 2013-09-05 09:49:22 +08:00
Cheng Zhao
e17da272f4 Make child_process.fork work when options.env is set. 2013-09-05 09:47:32 +08:00
Cheng Zhao
88bdff5832 Use environment variable to detect whether to run as node. 2013-09-05 09:22:24 +08:00
Cheng Zhao
ae18a90f7e Add test case for #83. 2013-09-05 09:21:39 +08:00
Cheng Zhao
3b7dd85d3f Merge pull request #65 from atom/custom-protocol
Support custom protocols
2013-09-04 03:33:09 -07:00
Cheng Zhao
128d9c78db Add documentation for protocol module. 2013-09-03 18:22:40 +08:00
Cheng Zhao
c7fed48c4a Emit erros when getting errors in IO thread. 2013-09-03 17:21:10 +08:00
Cheng Zhao
7737708fdd Add protocol interceptor API. 2013-09-03 16:50:10 +08:00
Cheng Zhao
9ba08d5e67 💄 fix reversed flag for updating latest version. 2013-09-02 18:17:06 +08:00
Cheng Zhao
6c3dc9e526 Dump v0.4.3. 2013-09-02 17:59:17 +08:00
Cheng Zhao
75a24a2e67 Update specs to match the documents. 2013-09-02 16:54:54 +08:00
Cheng Zhao
893309aa8a 💄 fix the window specs. 2013-09-02 16:47:53 +08:00
Cheng Zhao
f17864372e Use setTimeout instead of setImmediate in fixtures.
The setImmediate is implemented in node and may have unexpected affects.
2013-09-02 16:46:08 +08:00
Cheng Zhao
610ac5b045 Revert "💄 for the beforeunload handler."
Restore the previous behavior of beforeunload handler.

This reverts commit b1f30c1eb6.
2013-09-02 16:39:00 +08:00
Cheng Zhao
cfb957a603 Add specs for the beforeunload handler. 2013-09-02 16:28:36 +08:00
Cheng Zhao
335db788a5 Add InterceptProtocol AtomURLRequestJobFactory. 2013-08-30 21:15:46 +08:00
Cheng Zhao
d8cd3d78ff Make ReadRawData a public member, so there is no need to detect types. 2013-08-30 20:49:27 +08:00
Cheng Zhao
2a462cc2b7 💄 fix cpplint warning. 2013-08-30 20:24:42 +08:00
Cheng Zhao
df30f130d3 Separate logics between low level URLRequestJob and js calls. 2013-08-30 20:02:17 +08:00
Cheng Zhao
24e613c827 Separate URLRequestStringJob from atom_api_protocol. 2013-08-30 16:16:41 +08:00
Cheng Zhao
7df256f8dc Move atom_url_request_job_factory to browser/net. 2013-08-30 16:10:36 +08:00
Cheng Zhao
2000f88c84 Allow passing a fallback protocol handler for request jobs. 2013-08-30 15:48:57 +08:00
Cheng Zhao
db890feb51 Don't pollute console with error stack. 2013-08-30 13:04:21 +08:00
Cheng Zhao
738cbd4080 💄 Fix protocol specs. 2013-08-30 13:04:02 +08:00
Cheng Zhao
11221979e5 Disable overriding built-in protocols with protocol.registerProtocol. 2013-08-30 12:51:15 +08:00
Cheng Zhao
72c604f741 Custom the implementation of url request job factory.
It's needed for interceptor API.
2013-08-30 12:04:51 +08:00
Cheng Zhao
04910b8391 Skelecton for interceptor APIs. 2013-08-30 10:15:15 +08:00
Cheng Zhao
4bdd1b88ad Wrap passed 'url' and 'referrer' in an 'request' object. 2013-08-29 21:12:48 +08:00
Cheng Zhao
abd3e86fb1 💄 2013-08-29 21:06:22 +08:00
Cheng Zhao
c2fd43c3e8 Add spec for protocol.isHandledProtocol. 2013-08-29 20:57:09 +08:00
Cheng Zhao
261f50701a Add 'registered' and 'unregistered' events for protocol module.
This is only used for writing specs.
2013-08-29 20:56:25 +08:00
Cheng Zhao
bc4201f911 Make protocol module an EventEmitter. 2013-08-29 20:38:04 +08:00
Cheng Zhao
6915f020d9 Add protocol.isHandledProtocol API. 2013-08-29 20:22:52 +08:00
Cheng Zhao
799d9ada7d Make sure referrer is sent to the protocol handler. 2013-08-27 11:37:06 +08:00
Cheng Zhao
15ba32b489 Only redirect output to browser when running in CI. 2013-08-25 20:54:15 +08:00
Cheng Zhao
0f6617ec26 Make sure protocol module's specs do not pollute main.js. 2013-08-25 20:45:34 +08:00
Cheng Zhao
9e16e41bb3 Enable creating object from remote object's member. 2013-08-25 20:44:52 +08:00
Cheng Zhao
c86acc4cd7 Add remote.createFunctionWithReturnValue API. 2013-08-25 17:22:36 +08:00
Cheng Zhao
d88676bf65 💄 2013-08-25 16:49:54 +08:00
Cheng Zhao
d56a7d75de Use jQuery instead of zepto.
zepto always fails when requesting custom protocols, 💩.
2013-08-25 16:23:40 +08:00
Cheng Zhao
244d7eaf17 Allow returning file for custom protocol. 2013-08-25 16:06:29 +08:00
Cheng Zhao
1ed77371c0 Enable customing mime type and charset when returning reqeust string job. 2013-08-25 15:07:07 +08:00
Cheng Zhao
912bac698c Allow returning string in custom protocols. 2013-08-25 12:36:06 +08:00
Cheng Zhao
8464fb4f64 Pass weak pointers when posting tasks to other threads. 2013-08-24 20:32:12 +08:00
Cheng Zhao
0b01e49cd3 💄 2013-08-24 20:21:46 +08:00
Cheng Zhao
8cd7ccdc0d Call the JS handler to get the type of job. 2013-08-24 20:18:12 +08:00
Cheng Zhao
214df5ef69 Use zepto in the specs. 2013-08-24 20:15:31 +08:00
Cheng Zhao
b7c9f8ba1c The request should go through UI thread. 2013-08-24 19:46:38 +08:00
Cheng Zhao
f63661256f Return AdapterRequestJob when creating job. 2013-08-24 19:33:23 +08:00
Cheng Zhao
33279b1a2f Actually set and remove protocol handlers in IO thread.. 2013-08-24 17:59:34 +08:00
Cheng Zhao
96c173217f Remember registered schemes. 2013-08-24 16:38:19 +08:00
Cheng Zhao
b9cbfb8103 Skelecton for the protocol module. 2013-08-24 15:26:10 +08:00
248 changed files with 9238 additions and 3048 deletions

6
.gitmodules vendored
View File

@@ -4,12 +4,12 @@
[submodule "vendor/node"]
path = vendor/node
url = https://github.com/atom/node.git
[submodule "vendor/gyp"]
path = vendor/gyp
url = https://github.com/svn2github/gyp.git
[submodule "vendor/depot_tools"]
path = vendor/depot_tools
url = https://chromium.googlesource.com/chromium/tools/depot_tools.git
[submodule "vendor/apm"]
path = vendor/apm
url = https://github.com/atom/apm.git
[submodule "vendor/breakpad"]
path = vendor/breakpad
url = https://github.com/atom/chromium-breakpad.git

View File

@@ -1,6 +1,6 @@
# Atom Shell
Native layer for the [Atom](https://github.com/github/atom).
Native layer for the [Atom editor](https://github.com/atom/atom).
## Features

View File

@@ -2,27 +2,55 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "app/atom_main.h"
#include <stdlib.h>
#include <string.h>
#include "content/public/app/content_main.h"
#if defined(OS_WIN)
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <windows.h>
#include <shellapi.h>
#include "app/atom_main_delegate.h"
#include "base/environment.h"
#include "common/crash_reporter/win/crash_service_main.h"
#include "content/public/app/startup_helper_win.h"
#include "sandbox/win/src/sandbox_types.h"
#else // defined(OS_WIN)
#include "app/atom_library_main.h"
#endif // defined(OS_MACOSX) || defined(OS_LINUX)
// Declaration of node::Start.
namespace node {
int Start(int argc, char *argv[]);
}
#if defined(OS_WIN)
#include <windows.h> // NOLINT
#include <shellapi.h> // NOLINT
#include "app/atom_main_delegate.h"
#include "content/public/app/startup_helper_win.h"
#include "sandbox/win/src/sandbox_types.h"
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
int argc = 0;
wchar_t** wargv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
if (argc > 1 && wcscmp(wargv[1], L"--atom-child_process-fork") == 0) {
scoped_ptr<base::Environment> env(base::Environment::Create());
// Make output work in console if we are not in cygiwn.
std::string os;
if (env->GetVar("OS", &os) && os != "cygwin") {
AttachConsole(ATTACH_PARENT_PROCESS);
FILE* dontcare;
freopen_s(&dontcare, "CON", "w", stdout);
freopen_s(&dontcare, "CON", "w", stderr);
freopen_s(&dontcare, "CON", "r", stdin);
}
std::string node_indicator, crash_service_indicator;
if (env->GetVar("ATOM_SHELL_INTERNAL_RUN_AS_NODE", &node_indicator) &&
node_indicator == "1") {
// Convert argv to to UTF8
char** argv = new char*[argc];
for (int i = 0; i < argc; i++) {
@@ -57,8 +85,11 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
}
}
// Now that conversion is done, we can finally start.
argv[1] = argv[0];
return node::Start(argc - 1, argv + 1);
return node::Start(argc, argv);
} else if (env->GetVar("ATOM_SHELL_INTERNAL_CRASH_SERVICE",
&crash_service_indicator) &&
crash_service_indicator == "1") {
return crash_service::Main(cmd);
}
sandbox::SandboxInterfaceInfo sandbox_info = {0};
@@ -69,15 +100,12 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
#else // defined(OS_WIN)
#include "app/atom_library_main.h"
int main(int argc, const char* argv[]) {
if (argc > 1 && strcmp(argv[1], "--atom-child_process-fork") == 0) {
argv[1] = argv[0];
return node::Start(argc - 1, const_cast<char**>(argv + 1));
}
char* node_indicator = getenv("ATOM_SHELL_INTERNAL_RUN_AS_NODE");
if (node_indicator != NULL && strcmp(node_indicator, "1") == 0)
return node::Start(argc, const_cast<char**>(argv));
return AtomMain(argc, argv);
}
#endif
#endif // defined(OS_MACOSX) || defined(OS_LINUX)

5
app/atom_main.h Normal file
View File

@@ -0,0 +1,5 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/public/app/content_main.h"

View File

@@ -9,6 +9,8 @@
#include "browser/atom_browser_client.h"
#include "content/public/common/content_switches.h"
#include "renderer/atom_renderer_client.h"
#include "ui/base/resource/resource_bundle.h"
#include "base/path_service.h"
namespace atom {
@@ -21,28 +23,57 @@ AtomMainDelegate::~AtomMainDelegate() {
bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
// Disable logging out to debug.log on Windows
#if defined(OS_WIN)
logging::InitLogging(
L"debug.log",
logging::LoggingSettings settings;
#if defined(DEBUG)
logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG ,
settings.logging_dest = logging::LOG_TO_ALL;
settings.log_file = L"debug.log";
settings.lock_log = logging::LOCK_LOG_FILE;
settings.delete_old = logging::DELETE_OLD_LOG_FILE;
#else
logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
#endif // defined(NDEBUG)
logging::LOCK_LOG_FILE,
logging::DELETE_OLD_LOG_FILE,
logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS);
logging::SetLogItems(true, false, true, false);
settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
#endif
settings.dcheck_state =
logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS;
logging::InitLogging(settings);
#endif // defined(OS_WIN)
// Logging with pid and timestamp.
logging::SetLogItems(true, false, true, false);
return brightray::MainDelegate::BasicStartupComplete(exit_code);
}
void AtomMainDelegate::PreSandboxStartup() {
brightray::MainDelegate::PreSandboxStartup();
#if defined(OS_MACOSX)
OverrideChildProcessPath();
OverrideFrameworkBundlePath();
#endif
InitializeResourceBundle();
CommandLine* command_line = CommandLine::ForCurrentProcess();
// Disable renderer sandbox for most of node's functions.
CommandLine* command_line = CommandLine::ForCurrentProcess();
command_line->AppendSwitch(switches::kNoSandbox);
// Disable accelerated compositing since it caused a lot of troubles (black
// devtools, screen flashes) and needed lots of effort to make it right.
command_line->AppendSwitch(switches::kDisableAcceleratedCompositing);
// Add a flag to mark the end of switches added by atom-shell.
command_line->AppendSwitch("no-more-switches");
}
void AtomMainDelegate::InitializeResourceBundle() {
base::FilePath path;
#if defined(OS_MACOSX)
path = GetResourcesPakFilePath();
#else
base::FilePath pak_dir;
PathService::Get(base::DIR_MODULE, &pak_dir);
path = pak_dir.Append(FILE_PATH_LITERAL("content_shell.pak"));
#endif
ui::ResourceBundle::InitSharedInstanceWithPakPath(path);
}
content::ContentBrowserClient* AtomMainDelegate::CreateContentBrowserClient() {

View File

@@ -17,6 +17,13 @@ class AtomMainDelegate : public brightray::MainDelegate {
protected:
virtual bool BasicStartupComplete(int* exit_code) OVERRIDE;
virtual void PreSandboxStartup() OVERRIDE;
virtual void InitializeResourceBundle();
#if defined(OS_MACOSX)
virtual base::FilePath GetResourcesPakFilePath();
virtual void OverrideChildProcessPath();
virtual void OverrideFrameworkBundlePath();
#endif
private:
virtual content::ContentBrowserClient* CreateContentBrowserClient() OVERRIDE;

View File

@@ -0,0 +1,48 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "app/atom_main_delegate.h"
#import "base/mac/bundle_locations.h"
#import "base/mac/foundation_util.h"
#import "base/mac/mac_util.h"
#include "base/command_line.h"
#include "base/path_service.h"
#include "base/strings/sys_string_conversions.h"
#include "content/public/common/content_paths.h"
#include "content/public/common/content_switches.h"
#include "vendor/brightray/common/application_info.h"
#include "vendor/brightray/common/mac/main_application_bundle.h"
namespace atom {
namespace {
base::FilePath GetFrameworksPath() {
return brightray::MainApplicationBundlePath().Append("Contents")
.Append("Frameworks");
}
} // namespace
base::FilePath AtomMainDelegate::GetResourcesPakFilePath() {
NSString* path = [base::mac::FrameworkBundle()
pathForResource:@"content_shell" ofType:@"pak"];
return base::mac::NSStringToFilePath(path);
}
void AtomMainDelegate::OverrideFrameworkBundlePath() {
base::mac::SetOverrideFrameworkBundlePath(
GetFrameworksPath().Append("Atom Framework.framework"));
}
void AtomMainDelegate::OverrideChildProcessPath() {
base::FilePath helper_path = GetFrameworksPath().Append("Atom Helper.app")
.Append("Contents")
.Append("MacOS")
.Append("Atom Helper");
PathService::Override(content::CHILD_PROCESS_EXE, helper_path);
}
} // namespace atom

BIN
app/win/atom.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 KiB

Binary file not shown.

View File

@@ -1,9 +1,10 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by brightray_example.rc
#define IDR_MAINFRAME 1
// Next default values for new objects
//
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101

166
atom.gyp
View File

@@ -2,8 +2,10 @@
'variables': {
'project_name': 'atom',
'product_name': 'Atom',
'framework_name': 'Atom Framework',
'app_sources': [
'app/atom_main.cc',
'app/atom_main.h',
],
'bundle_sources': [
'browser/mac/atom.icns',
@@ -13,39 +15,39 @@
'browser/api/lib/atom-delegate.coffee',
'browser/api/lib/auto-updater.coffee',
'browser/api/lib/browser-window.coffee',
'browser/api/lib/crash-reporter.coffee',
'browser/api/lib/dialog.coffee',
'browser/api/lib/ipc.coffee',
'browser/api/lib/menu.coffee',
'browser/api/lib/menu-item.coffee',
'browser/api/lib/power-monitor.coffee',
'browser/atom/atom.coffee',
'browser/atom/objects-registry.coffee',
'browser/atom/rpc-server.coffee',
'browser/api/lib/protocol.coffee',
'browser/lib/init.coffee',
'browser/lib/objects-registry.coffee',
'browser/lib/rpc-server.coffee',
'common/api/lib/callbacks-registry.coffee',
'common/api/lib/clipboard.coffee',
'common/api/lib/crash-reporter.coffee',
'common/api/lib/id-weak-map.coffee',
'common/api/lib/screen.coffee',
'common/api/lib/shell.coffee',
'renderer/lib/init.coffee',
'renderer/api/lib/ipc.coffee',
'renderer/api/lib/remote.coffee',
],
'lib_sources': [
'app/atom_main_delegate.cc',
'app/atom_main_delegate.h',
'app/atom_main_delegate_mac.mm',
'browser/api/atom_api_app.cc',
'browser/api/atom_api_app.h',
'browser/api/atom_api_auto_updater.cc',
'browser/api/atom_api_auto_updater.h',
'browser/api/atom_api_browser_ipc.cc',
'browser/api/atom_api_browser_ipc.h',
'browser/api/atom_api_crash_reporter.h',
'browser/api/atom_api_crash_reporter.cc',
'browser/api/atom_api_dialog.cc',
'browser/api/atom_api_dialog.h',
'browser/api/atom_api_event.cc',
'browser/api/atom_api_event.h',
'browser/api/atom_api_event_emitter.cc',
'browser/api/atom_api_event_emitter.h',
'browser/api/atom_api_menu.cc',
'browser/api/atom_api_menu.h',
'browser/api/atom_api_menu_mac.h',
@@ -54,6 +56,8 @@
'browser/api/atom_api_menu_win.h',
'browser/api/atom_api_power_monitor.cc',
'browser/api/atom_api_power_monitor.h',
'browser/api/atom_api_protocol.cc',
'browser/api/atom_api_protocol.h',
'browser/api/atom_api_window.cc',
'browser/api/atom_api_window.h',
'browser/api/atom_browser_bindings.cc',
@@ -75,8 +79,6 @@
'browser/atom_browser_main_parts.cc',
'browser/atom_browser_main_parts.h',
'browser/atom_browser_main_parts_mac.mm',
'browser/atom_event_processing_window.h',
'browser/atom_event_processing_window.mm',
'browser/atom_javascript_dialog_manager.cc',
'browser/atom_javascript_dialog_manager.h',
'browser/browser.cc',
@@ -84,9 +86,6 @@
'browser/browser_mac.mm',
'browser/browser_win.cc',
'browser/browser_observer.h',
'browser/crash_reporter.h',
'browser/crash_reporter_mac.mm',
'browser/crash_reporter_win.cc',
'browser/native_window.cc',
'browser/native_window.h',
'browser/native_window_mac.h',
@@ -94,10 +93,20 @@
'browser/native_window_win.cc',
'browser/native_window_win.h',
'browser/native_window_observer.h',
'browser/net/adapter_request_job.cc',
'browser/net/adapter_request_job.h',
'browser/net/atom_url_request_context_getter.cc',
'browser/net/atom_url_request_context_getter.h',
'browser/net/atom_url_request_job_factory.cc',
'browser/net/atom_url_request_job_factory.h',
'browser/net/url_request_string_job.cc',
'browser/net/url_request_string_job.h',
'browser/ui/accelerator_util.cc',
'browser/ui/accelerator_util.h',
'browser/ui/accelerator_util_mac.mm',
'browser/ui/accelerator_util_win.cc',
'browser/ui/atom_event_processing_window.h',
'browser/ui/atom_event_processing_window.mm',
'browser/ui/atom_menu_controller_mac.h',
'browser/ui/atom_menu_controller_mac.mm',
'browser/ui/file_dialog.h',
@@ -119,8 +128,14 @@
'common/api/api_messages.h',
'common/api/atom_api_clipboard.cc',
'common/api/atom_api_clipboard.h',
'common/api/atom_api_crash_reporter.cc',
'common/api/atom_api_crash_reporter.h',
'common/api/atom_api_event_emitter.cc',
'common/api/atom_api_event_emitter.h',
'common/api/atom_api_id_weak_map.cc',
'common/api/atom_api_id_weak_map.h',
'common/api/atom_api_screen.cc',
'common/api/atom_api_screen.h',
'common/api/atom_api_shell.cc',
'common/api/atom_api_shell.h',
'common/api/atom_api_v8_util.cc',
@@ -130,6 +145,18 @@
'common/api/atom_extensions.h',
'common/api/object_life_monitor.cc',
'common/api/object_life_monitor.h',
'common/crash_reporter/crash_reporter.cc',
'common/crash_reporter/crash_reporter.h',
'common/crash_reporter/crash_reporter_mac.h',
'common/crash_reporter/crash_reporter_mac.mm',
'common/crash_reporter/crash_reporter_win.cc',
'common/crash_reporter/crash_reporter_win.h',
'common/crash_reporter/win/crash_service.cc',
'common/crash_reporter/win/crash_service.h',
'common/crash_reporter/win/crash_service_main.cc',
'common/crash_reporter/win/crash_service_main.h',
'common/draggable_region.cc',
'common/draggable_region.h',
'common/node_bindings.cc',
'common/node_bindings.h',
'common/node_bindings_mac.cc',
@@ -141,8 +168,12 @@
'common/platform_util.h',
'common/platform_util_mac.mm',
'common/platform_util_win.cc',
'common/v8_value_converter_impl.cc',
'common/v8_value_converter_impl.h',
'common/swap_or_assign.h',
'common/v8/node_common.h',
'common/v8/scoped_persistent.h',
'common/v8/native_type_conversions.h',
'common/v8/v8_value_converter.cc',
'common/v8/v8_value_converter.h',
'renderer/api/atom_api_renderer_ipc.cc',
'renderer/api/atom_api_renderer_ipc.h',
'renderer/api/atom_renderer_bindings.cc',
@@ -160,6 +191,7 @@
['OS=="win"', {
'app_sources': [
'app/win/resource.h',
'app/win/atom.ico',
'app/win/atom.rc',
'<(libchromiumcontent_src_dir)/content/app/startup_helper_win.cc',
],
@@ -170,9 +202,6 @@
'-change',
'@loader_path/../Frameworks/Sparkle.framework/Versions/A/Sparkle',
'@rpath/Sparkle.framework/Versions/A/Sparkle',
'-change',
'@executable_path/../Frameworks/Quincy.framework/Versions/A/Quincy',
'@rpath/Quincy.framework/Versions/A/Quincy',
'${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}'
],
'atom_source_root': '<!(python tools/atom_source_root.py)',
@@ -232,9 +261,8 @@
'destination': '<(PRODUCT_DIR)/<(product_name).app/Contents/Frameworks',
'files': [
'<(PRODUCT_DIR)/<(product_name) Helper.app',
'<(PRODUCT_DIR)/<(product_name).framework',
'<(PRODUCT_DIR)/<(framework_name).framework',
'frameworks/Sparkle.framework',
'frameworks/Quincy.framework',
],
},
{
@@ -290,13 +318,13 @@
],
}], # OS=="win"
],
},
}, # target <(project_name)
{
'target_name': '<(project_name)_lib',
'type': 'static_library',
'dependencies': [
'vendor/brightray/brightray.gyp:brightray',
'vendor/node/node.gyp:node',
'vendor/node/node.gyp:node_lib',
],
'sources': [
'<@(lib_sources)',
@@ -304,6 +332,14 @@
'include_dirs': [
'.',
'vendor',
# Include directories for uv and node.
'vendor/node/src',
'vendor/node/deps/http_parser',
'vendor/node/deps/uv/include',
# The `node.h` is using `#include"v8.h"`.
'vendor/brightray/vendor/download/libchromiumcontent/src/v8/include',
# The `node.h` is using `#include"ares.h"`.
'vendor/node/deps/cares/include',
],
'direct_dependent_settings': {
'include_dirs': [
@@ -320,12 +356,22 @@
'-limm32.lib',
'-loleacc.lib',
'-lComdlg32.lib',
'-lWininet.lib',
'<(atom_source_root)/<(libchromiumcontent_library_dir)/chromiumviews.lib',
],
},
'dependencies': [
'vendor/breakpad/breakpad.gyp:breakpad_handler',
'vendor/breakpad/breakpad.gyp:breakpad_sender',
],
}],
['OS=="mac"', {
'dependencies': [
'vendor/breakpad/breakpad.gyp:breakpad',
],
}],
],
},
}, # target <(product_name)_lib
{
'target_name': 'generated_sources',
'type': 'none',
@@ -365,14 +411,70 @@
],
},
],
},
}, # target generated_sources
{
'target_name': '<(project_name)_dump_symbols',
'type': 'none',
'dependencies': [
'<(project_name)',
],
'conditions': [
['OS=="mac"', {
'dependencies': [
'vendor/breakpad/breakpad.gyp:dump_syms',
],
'actions': [
{
'action_name': 'Dump Symbols',
'inputs': [
'<(PRODUCT_DIR)/<(product_name).app/Contents/MacOS/<(product_name)',
],
'outputs': [
'<(PRODUCT_DIR)/Atom-Shell.breakpad.syms',
],
'action': [
'python',
'tools/mac/generate_breakpad_symbols.py',
'--build-dir=<(PRODUCT_DIR)',
'--binary=<(PRODUCT_DIR)/<(product_name).app/Contents/MacOS/<(product_name)',
'--symbols-dir=<(PRODUCT_DIR)/Atom-Shell.breakpad.syms',
'--libchromiumcontent-dir=<(libchromiumcontent_library_dir)',
'--clear',
'--jobs=16',
],
},
],
}], # OS=="mac"
['OS=="win"', {
'actions': [
{
'action_name': 'Dump Symbols',
'inputs': [
'<(PRODUCT_DIR)/<(project_name).exe',
],
'outputs': [
'<(PRODUCT_DIR)/Atom-Shell.breakpad.syms',
],
'action': [
'python',
'tools/win/generate_breakpad_symbols.py',
'--symbols-dir=<(PRODUCT_DIR)/Atom-Shell.breakpad.syms',
'--jobs=16',
'<(PRODUCT_DIR)',
'<(libchromiumcontent_library_dir)',
],
},
],
}], # OS=="win"
],
}, # target <(project_name>_dump_symbols
],
'conditions': [
['OS=="mac"', {
'targets': [
{
'target_name': '<(project_name)_framework',
'product_name': '<(product_name)',
'product_name': '<(framework_name)',
'type': 'shared_library',
'dependencies': [
'<(project_name)_lib',
@@ -392,7 +494,6 @@
'libraries': [
'$(SDKROOT)/System/Library/Frameworks/Carbon.framework',
'frameworks/Sparkle.framework',
'frameworks/Quincy.framework',
],
},
'mac_bundle': 1,
@@ -404,7 +505,7 @@
'LIBRARY_SEARCH_PATHS': [
'<(libchromiumcontent_library_dir)',
],
'LD_DYLIB_INSTALL_NAME': '@rpath/<(product_name).framework/<(product_name)',
'LD_DYLIB_INSTALL_NAME': '@rpath/<(framework_name).framework/<(framework_name)',
'LD_RUNPATH_SEARCH_PATHS': [
'@loader_path/Libraries',
],
@@ -414,12 +515,19 @@
},
'copies': [
{
'destination': '<(PRODUCT_DIR)/<(product_name).framework/Versions/A/Libraries',
'destination': '<(PRODUCT_DIR)/<(framework_name).framework/Versions/A/Libraries',
'files': [
'<(libchromiumcontent_library_dir)/ffmpegsumo.so',
'<(libchromiumcontent_library_dir)/libchromiumcontent.dylib',
],
},
{
'destination': '<(PRODUCT_DIR)/<(framework_name).framework/Versions/A/Resources',
'files': [
'<(PRODUCT_DIR)/Inspector',
'<(PRODUCT_DIR)/crash_report_sender.app',
],
},
],
'postbuilds': [
{
@@ -432,7 +540,7 @@
'postbuild_name': 'Add symlinks for framework subdirectories',
'action': [
'tools/mac/create-framework-subdir-symlinks.sh',
'<(product_name)',
'<(framework_name)',
'Libraries',
'Frameworks',
],

View File

@@ -7,7 +7,9 @@
#include "base/values.h"
#include "base/command_line.h"
#include "browser/browser.h"
#include "vendor/node/src/node.h"
#include "common/v8/native_type_conversions.h"
#include "common/v8/node_common.h"
namespace atom {
@@ -47,103 +49,99 @@ void App::OnWillFinishLaunching() {
}
void App::OnFinishLaunching() {
Emit("finish-launching");
Emit("ready");
}
// static
v8::Handle<v8::Value> App::New(const v8::Arguments &args) {
v8::HandleScope scope;
void App::New(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::HandleScope scope(args.GetIsolate());
if (!args.IsConstructCall())
return node::ThrowError("Require constructor call");
new App(args.This());
return args.This();
}
// static
v8::Handle<v8::Value> App::Quit(const v8::Arguments &args) {
v8::HandleScope scope;
void App::Quit(const v8::FunctionCallbackInfo<v8::Value>& args) {
Browser::Get()->Quit();
return v8::Undefined();
}
// static
v8::Handle<v8::Value> App::Exit(const v8::Arguments &args) {
v8::HandleScope scope;
void App::Exit(const v8::FunctionCallbackInfo<v8::Value>& args) {
exit(args[0]->IntegerValue());
return v8::Undefined();
}
// static
v8::Handle<v8::Value> App::Terminate(const v8::Arguments &args) {
v8::HandleScope scope;
void App::Terminate(const v8::FunctionCallbackInfo<v8::Value>& args) {
Browser::Get()->Terminate();
return v8::Undefined();
}
// static
v8::Handle<v8::Value> App::Focus(const v8::Arguments &args) {
v8::HandleScope scope;
void App::Focus(const v8::FunctionCallbackInfo<v8::Value>& args) {
Browser::Get()->Focus();
return v8::Undefined();
}
// static
v8::Handle<v8::Value> App::GetVersion(const v8::Arguments &args) {
v8::HandleScope scope;
std::string version(Browser::Get()->GetVersion());
return v8::String::New(version.data(), version.size());
void App::GetVersion(const v8::FunctionCallbackInfo<v8::Value>& args) {
args.GetReturnValue().Set(ToV8Value(Browser::Get()->GetVersion()));
}
// static
v8::Handle<v8::Value> App::AppendSwitch(const v8::Arguments &args) {
v8::HandleScope scope;
if (!args[0]->IsString())
void App::SetVersion(const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string version;
if (!FromV8Arguments(args, &version))
return node::ThrowError("Bad argument");
Browser::Get()->SetVersion(version);
}
// static
void App::GetName(const v8::FunctionCallbackInfo<v8::Value>& args) {
return args.GetReturnValue().Set(ToV8Value(Browser::Get()->GetName()));
}
// static
void App::SetName(const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string name;
if (!FromV8Arguments(args, &name))
return node::ThrowError("Bad argument");
Browser::Get()->SetName(name);
}
// static
void App::AppendSwitch(const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string switch_string;
if (!FromV8Arguments(args, &switch_string))
return node::ThrowError("Bad argument");
std::string switch_string(*v8::String::Utf8Value(args[0]));
if (args.Length() == 1) {
CommandLine::ForCurrentProcess()->AppendSwitch(switch_string);
} else {
std::string value(*v8::String::Utf8Value(args[1]));
std::string value = FromV8Value(args[1]);
CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switch_string, value);
}
return v8::Undefined();
}
// static
v8::Handle<v8::Value> App::AppendArgument(const v8::Arguments &args) {
v8::HandleScope scope;
if (!args[0]->IsString())
void App::AppendArgument(const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string value;
if (!FromV8Arguments(args, &value))
return node::ThrowError("Bad argument");
std::string value(*v8::String::Utf8Value(args[0]));
CommandLine::ForCurrentProcess()->AppendArg(value);
return v8::Undefined();
}
#if defined(OS_MACOSX)
// static
v8::Handle<v8::Value> App::DockBounce(const v8::Arguments& args) {
std::string type(*v8::String::Utf8Value(args[0]));
void App::DockBounce(const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string type;
if (!FromV8Arguments(args, &type))
return node::ThrowError("Bad argument");
int request_id = -1;
if (type == "critical")
@@ -153,35 +151,32 @@ v8::Handle<v8::Value> App::DockBounce(const v8::Arguments& args) {
else
return node::ThrowTypeError("Invalid bounce type");
return v8::Integer::New(request_id);
args.GetReturnValue().Set(request_id);
}
// static
v8::Handle<v8::Value> App::DockCancelBounce(const v8::Arguments& args) {
Browser::Get()->DockCancelBounce(args[0]->IntegerValue());
return v8::Undefined();
void App::DockCancelBounce(const v8::FunctionCallbackInfo<v8::Value>& args) {
Browser::Get()->DockCancelBounce(FromV8Value(args[0]));
}
// static
v8::Handle<v8::Value> App::DockSetBadgeText(const v8::Arguments& args) {
std::string label(*v8::String::Utf8Value(args[0]));
Browser::Get()->DockSetBadgeText(label);
return v8::Undefined();
void App::DockSetBadgeText(const v8::FunctionCallbackInfo<v8::Value>& args) {
Browser::Get()->DockSetBadgeText(FromV8Value(args[0]));
}
// static
v8::Handle<v8::Value> App::DockGetBadgeText(const v8::Arguments& args) {
void App::DockGetBadgeText(const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string text(Browser::Get()->DockGetBadgeText());
return v8::String::New(text.data(), text.size());
args.GetReturnValue().Set(ToV8Value(text));
}
#endif // defined(OS_MACOSX)
// static
void App::Initialize(v8::Handle<v8::Object> target) {
v8::HandleScope scope;
v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(App::New);
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(New);
t->InstanceTemplate()->SetInternalFieldCount(1);
t->SetClassName(v8::String::NewSymbol("Application"));
@@ -190,6 +185,9 @@ void App::Initialize(v8::Handle<v8::Object> target) {
NODE_SET_PROTOTYPE_METHOD(t, "terminate", Terminate);
NODE_SET_PROTOTYPE_METHOD(t, "focus", Focus);
NODE_SET_PROTOTYPE_METHOD(t, "getVersion", GetVersion);
NODE_SET_PROTOTYPE_METHOD(t, "setVersion", SetVersion);
NODE_SET_PROTOTYPE_METHOD(t, "getName", GetName);
NODE_SET_PROTOTYPE_METHOD(t, "setName", SetName);
target->Set(v8::String::NewSymbol("Application"), t->GetFunction());

View File

@@ -6,8 +6,8 @@
#define ATOM_BROWSER_API_ATOM_API_APP_H_
#include "base/compiler_specific.h"
#include "browser/api/atom_api_event_emitter.h"
#include "browser/browser_observer.h"
#include "common/api/atom_api_event_emitter.h"
namespace atom {
@@ -33,21 +33,24 @@ class App : public EventEmitter,
virtual void OnFinishLaunching() OVERRIDE;
private:
static v8::Handle<v8::Value> New(const v8::Arguments &args);
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static v8::Handle<v8::Value> Quit(const v8::Arguments &args);
static v8::Handle<v8::Value> Exit(const v8::Arguments &args);
static v8::Handle<v8::Value> Terminate(const v8::Arguments &args);
static v8::Handle<v8::Value> Focus(const v8::Arguments &args);
static v8::Handle<v8::Value> GetVersion(const v8::Arguments &args);
static v8::Handle<v8::Value> AppendSwitch(const v8::Arguments &args);
static v8::Handle<v8::Value> AppendArgument(const v8::Arguments &args);
static void Quit(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Exit(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Terminate(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Focus(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetVersion(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetVersion(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetName(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetName(const v8::FunctionCallbackInfo<v8::Value>& args);
static void AppendSwitch(const v8::FunctionCallbackInfo<v8::Value>& args);
static void AppendArgument(const v8::FunctionCallbackInfo<v8::Value>& args);
#if defined(OS_MACOSX)
static v8::Handle<v8::Value> DockBounce(const v8::Arguments& args);
static v8::Handle<v8::Value> DockCancelBounce(const v8::Arguments& args);
static v8::Handle<v8::Value> DockSetBadgeText(const v8::Arguments& args);
static v8::Handle<v8::Value> DockGetBadgeText(const v8::Arguments& args);
static void DockBounce(const v8::FunctionCallbackInfo<v8::Value>& args);
static void DockCancelBounce(const v8::FunctionCallbackInfo<v8::Value>& args);
static void DockSetBadgeText(const v8::FunctionCallbackInfo<v8::Value>& args);
static void DockGetBadgeText(const v8::FunctionCallbackInfo<v8::Value>& args);
#endif // defined(OS_MACOSX)
DISALLOW_COPY_AND_ASSIGN(App);

View File

@@ -6,6 +6,9 @@
#include "base/values.h"
#include "browser/auto_updater.h"
#include "common/v8/native_type_conversions.h"
#include "common/v8/node_common.h"
namespace atom {
@@ -43,69 +46,63 @@ void AutoUpdater::ReadyForUpdateOnQuit(const std::string& version,
}
// static
v8::Handle<v8::Value> AutoUpdater::New(const v8::Arguments &args) {
v8::HandleScope scope;
void AutoUpdater::New(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::HandleScope handle_scope(args.GetIsolate());
if (!args.IsConstructCall())
return node::ThrowError("Require constructor call");
new AutoUpdater(args.This());
return args.This();
}
// static
v8::Handle<v8::Value> AutoUpdater::SetFeedURL(const v8::Arguments &args) {
auto_updater::AutoUpdater::SetFeedURL(*v8::String::Utf8Value(args[0]));
return v8::Undefined();
void AutoUpdater::SetFeedURL(const v8::FunctionCallbackInfo<v8::Value>& args) {
auto_updater::AutoUpdater::SetFeedURL(FromV8Value(args[0]));
}
// static
v8::Handle<v8::Value> AutoUpdater::SetAutomaticallyChecksForUpdates(
const v8::Arguments &args) {
void AutoUpdater::SetAutomaticallyChecksForUpdates(
const v8::FunctionCallbackInfo<v8::Value>& args) {
auto_updater::AutoUpdater::SetAutomaticallyChecksForUpdates(
args[0]->BooleanValue());
return v8::Undefined();
FromV8Value(args[0]));
}
// static
v8::Handle<v8::Value> AutoUpdater::SetAutomaticallyDownloadsUpdates(
const v8::Arguments &args) {
void AutoUpdater::SetAutomaticallyDownloadsUpdates(
const v8::FunctionCallbackInfo<v8::Value>& args) {
auto_updater::AutoUpdater::SetAutomaticallyDownloadsUpdates(
args[0]->BooleanValue());
return v8::Undefined();
FromV8Value(args[0]));
}
// static
v8::Handle<v8::Value> AutoUpdater::CheckForUpdates(const v8::Arguments &args) {
void AutoUpdater::CheckForUpdates(
const v8::FunctionCallbackInfo<v8::Value>& args) {
auto_updater::AutoUpdater::CheckForUpdates();
return v8::Undefined();
}
// static
v8::Handle<v8::Value> AutoUpdater::CheckForUpdatesInBackground(
const v8::Arguments &args) {
void AutoUpdater::CheckForUpdatesInBackground(
const v8::FunctionCallbackInfo<v8::Value>& args) {
auto_updater::AutoUpdater::CheckForUpdatesInBackground();
return v8::Undefined();
}
// static
v8::Handle<v8::Value> AutoUpdater::ContinueUpdate(const v8::Arguments &args) {
void AutoUpdater::ContinueUpdate(
const v8::FunctionCallbackInfo<v8::Value>& args) {
AutoUpdater* self = AutoUpdater::Unwrap<AutoUpdater>(args.This());
self->continue_update_.Run();
return v8::Undefined();
}
// static
v8::Handle<v8::Value> AutoUpdater::QuitAndInstall(const v8::Arguments &args) {
void AutoUpdater::QuitAndInstall(
const v8::FunctionCallbackInfo<v8::Value>& args) {
AutoUpdater* self = AutoUpdater::Unwrap<AutoUpdater>(args.This());
self->quit_and_install_.Run();
return v8::Undefined();
}
// static
void AutoUpdater::Initialize(v8::Handle<v8::Object> target) {
v8::HandleScope scope;
v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
v8::Local<v8::FunctionTemplate> t(
v8::FunctionTemplate::New(AutoUpdater::New));

View File

@@ -7,8 +7,8 @@
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "browser/api/atom_api_event_emitter.h"
#include "browser/auto_updater_delegate.h"
#include "common/api/atom_api_event_emitter.h"
namespace atom {
@@ -31,19 +31,19 @@ class AutoUpdater : public EventEmitter,
const base::Closure& quit_and_install) OVERRIDE;
private:
static v8::Handle<v8::Value> New(const v8::Arguments &args);
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static v8::Handle<v8::Value> SetFeedURL(const v8::Arguments &args);
static v8::Handle<v8::Value> SetAutomaticallyChecksForUpdates(
const v8::Arguments &args);
static v8::Handle<v8::Value> SetAutomaticallyDownloadsUpdates(
const v8::Arguments &args);
static v8::Handle<v8::Value> CheckForUpdates(const v8::Arguments &args);
static v8::Handle<v8::Value> CheckForUpdatesInBackground(
const v8::Arguments &args);
static void SetFeedURL(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetAutomaticallyChecksForUpdates(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetAutomaticallyDownloadsUpdates(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void CheckForUpdates(const v8::FunctionCallbackInfo<v8::Value>& args);
static void CheckForUpdatesInBackground(
const v8::FunctionCallbackInfo<v8::Value>& args);
static v8::Handle<v8::Value> ContinueUpdate(const v8::Arguments &args);
static v8::Handle<v8::Value> QuitAndInstall(const v8::Arguments &args);
static void ContinueUpdate(const v8::FunctionCallbackInfo<v8::Value>& args);
static void QuitAndInstall(const v8::FunctionCallbackInfo<v8::Value>& args);
base::Closure continue_update_;
base::Closure quit_and_install_;

View File

@@ -4,59 +4,41 @@
#include "browser/api/atom_api_browser_ipc.h"
#include "base/values.h"
#include "common/api/api_messages.h"
#include "common/v8_value_converter_impl.h"
#include "common/v8/node_common.h"
#include "common/v8/native_type_conversions.h"
#include "content/public/browser/render_view_host.h"
#include "vendor/node/src/node.h"
#include "vendor/node/src/node_internals.h"
using content::RenderViewHost;
using content::V8ValueConverter;
namespace atom {
namespace api {
// static
v8::Handle<v8::Value> BrowserIPC::Send(const v8::Arguments &args) {
v8::HandleScope scope;
if (!args[0]->IsString() || !args[1]->IsNumber() || !args[2]->IsNumber())
void BrowserIPC::Send(const v8::FunctionCallbackInfo<v8::Value>& args) {
string16 channel;
int process_id, routing_id;
scoped_ptr<base::Value> arguments;
if (!FromV8Arguments(args, &channel, &process_id, &routing_id, &arguments))
return node::ThrowTypeError("Bad argument");
std::string channel(*v8::String::Utf8Value(args[0]));
int process_id = args[1]->IntegerValue();
int routing_id = args[2]->IntegerValue();
DCHECK(arguments && arguments->IsType(base::Value::TYPE_LIST));
RenderViewHost* render_view_host(RenderViewHost::FromID(
process_id, routing_id));
if (!render_view_host)
return node::ThrowError("Invalid render view host");
// Convert Arguments to Array, so we can use V8ValueConverter to convert it
// to ListValue.
v8::Local<v8::Array> v8_args = v8::Array::New(args.Length() - 3);
for (int i = 0; i < args.Length() - 3; ++i)
v8_args->Set(i, args[i + 3]);
scoped_ptr<V8ValueConverter> converter(new V8ValueConverterImpl());
scoped_ptr<base::Value> arguments(
converter->FromV8Value(v8_args, v8::Context::GetCurrent()));
DCHECK(arguments && arguments->IsType(base::Value::TYPE_LIST));
render_view_host->Send(new AtomViewMsg_Message(
args.GetReturnValue().Set(render_view_host->Send(new AtomViewMsg_Message(
routing_id,
channel,
*static_cast<base::ListValue*>(arguments.get())));
return v8::Undefined();
*static_cast<base::ListValue*>(arguments.get()))));
}
// static
void BrowserIPC::Initialize(v8::Handle<v8::Object> target) {
node::SetMethod(target, "send", Send);
NODE_SET_METHOD(target, "send", Send);
}
} // namespace api

View File

@@ -17,7 +17,7 @@ class BrowserIPC {
static void Initialize(v8::Handle<v8::Object> target);
private:
static v8::Handle<v8::Value> Send(const v8::Arguments &args);
static void Send(const v8::FunctionCallbackInfo<v8::Value>& args);
DISALLOW_IMPLICIT_CONSTRUCTORS(BrowserIPC);
};

View File

@@ -1,47 +0,0 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "browser/api/atom_api_crash_reporter.h"
#include "browser/crash_reporter.h"
#include "vendor/node/src/node.h"
#include "vendor/node/src/node_internals.h"
namespace atom {
namespace api {
// static
v8::Handle<v8::Value> CrashReporter::SetCompanyName(const v8::Arguments &args) {
std::string name(*v8::String::Utf8Value(args[0]));
crash_reporter::CrashReporter::SetCompanyName(name);
return v8::Undefined();
}
// static
v8::Handle<v8::Value> CrashReporter::SetSubmissionURL(
const v8::Arguments &args) {
std::string url(*v8::String::Utf8Value(args[0]));
crash_reporter::CrashReporter::SetSubmissionURL(url);
return v8::Undefined();
}
// static
v8::Handle<v8::Value> CrashReporter::SetAutoSubmit(const v8::Arguments &args) {
crash_reporter::CrashReporter::SetAutoSubmit(args[0]->BooleanValue());
return v8::Undefined();
}
// static
void CrashReporter::Initialize(v8::Handle<v8::Object> target) {
node::SetMethod(target, "setCompanyName", SetCompanyName);
node::SetMethod(target, "setSubmissionUrl", SetSubmissionURL);
node::SetMethod(target, "setAutoSubmit", SetAutoSubmit);
}
} // namespace api
} // namespace atom
NODE_MODULE(atom_browser_crash_reporter, atom::api::CrashReporter::Initialize)

View File

@@ -4,14 +4,12 @@
#include "browser/api/atom_api_dialog.h"
#include <string>
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "browser/api/atom_api_window.h"
#include "base/bind.h"
#include "browser/native_window.h"
#include "browser/ui/file_dialog.h"
#include "browser/ui/message_box.h"
#include "common/v8/node_common.h"
#include "common/v8/native_type_conversions.h"
namespace atom {
@@ -19,18 +17,23 @@ namespace api {
namespace {
base::FilePath V8ValueToFilePath(v8::Handle<v8::Value> path) {
std::string path_string(*v8::String::Utf8Value(path));
return base::FilePath::FromUTF8Unsafe(path_string);
template<typename T>
void CallV8Function(const RefCountedV8Function& callback, T arg) {
v8::Handle<v8::Value> value = ToV8Value(arg);
callback->NewHandle(node_isolate)->Call(
v8::Context::GetCurrent()->Global(), 1, &value);
}
v8::Handle<v8::Value> FilePathToV8Value(const base::FilePath path) {
std::string path_string(path.AsUTF8Unsafe());
return v8::String::New(path_string.data(), path_string.size());
template<typename T>
void CallV8Function2(const RefCountedV8Function& callback, bool result, T arg) {
if (result)
return CallV8Function<T>(callback, arg);
else
return CallV8Function<void*>(callback, NULL);
}
void Initialize(v8::Handle<v8::Object> target) {
v8::HandleScope scope;
v8::HandleScope handle_scope(node_isolate);
NODE_SET_METHOD(target, "showMessageBox", ShowMessageBox);
NODE_SET_METHOD(target, "showOpenDialog", ShowOpenDialog);
@@ -39,87 +42,95 @@ void Initialize(v8::Handle<v8::Object> target) {
} // namespace
v8::Handle<v8::Value> ShowMessageBox(const v8::Arguments &args) {
v8::HandleScope scope;
if (!args[0]->IsNumber() || // type
!args[1]->IsArray() || // buttons
!args[2]->IsString() || // title
!args[3]->IsString() || // message
!args[4]->IsString()) // detail
return node::ThrowTypeError("Bad argument");
NativeWindow* native_window = NULL;
if (args[5]->IsObject()) {
Window* window = Window::Unwrap<Window>(args[5]->ToObject());
if (!window || !window->window())
return node::ThrowError("Invalid window");
native_window = window->window();
}
MessageBoxType type = (MessageBoxType)(args[0]->IntegerValue());
void ShowMessageBox(const v8::FunctionCallbackInfo<v8::Value>& args) {
int type;
std::vector<std::string> buttons;
v8::Handle<v8::Array> v8_buttons = v8::Handle<v8::Array>::Cast(args[1]);
for (uint32_t i = 0; i < v8_buttons->Length(); ++i)
buttons.push_back(*v8::String::Utf8Value(v8_buttons->Get(i)));
std::string title(*v8::String::Utf8Value(args[2]));
std::string message(*v8::String::Utf8Value(args[3]));
std::string detail(*v8::String::Utf8Value(args[4]));
int chosen = atom::ShowMessageBox(
native_window, type, buttons, title, message, detail);
return scope.Close(v8::Integer::New(chosen));
}
v8::Handle<v8::Value> ShowOpenDialog(const v8::Arguments &args) {
v8::HandleScope scope;
if (!args[0]->IsString() || // title
!args[1]->IsString() || // default_path
!args[2]->IsNumber()) // properties
std::string title, message, detail;
if (!FromV8Arguments(args, &type, &buttons, &title, &message, &detail))
return node::ThrowTypeError("Bad argument");
std::string title(*v8::String::Utf8Value(args[0]));
base::FilePath default_path(V8ValueToFilePath(args[1]));
int properties = args[2]->IntegerValue();
NativeWindow* native_window = FromV8Value(args[5]);
std::vector<base::FilePath> paths;
if (!file_dialog::ShowOpenDialog(title, default_path, properties, &paths))
return v8::Undefined();
v8::Handle<v8::Array> result = v8::Array::New(paths.size());
for (size_t i = 0; i < paths.size(); ++i)
result->Set(i, FilePathToV8Value(paths[i]));
return scope.Close(result);
if (!args[6]->IsFunction()) {
int chosen = atom::ShowMessageBox(
native_window,
(MessageBoxType)type,
buttons,
title,
message,
detail);
args.GetReturnValue().Set(chosen);
} else {
RefCountedV8Function callback = FromV8Value(args[6]);
atom::ShowMessageBox(
native_window,
(MessageBoxType)type,
buttons,
title,
message,
detail,
base::Bind(&CallV8Function<int>, callback));
}
}
v8::Handle<v8::Value> ShowSaveDialog(const v8::Arguments &args) {
v8::HandleScope scope;
if (!args[0]->IsObject() || // window
!args[1]->IsString() || // title
!args[2]->IsString()) // default_path
void ShowOpenDialog(const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string title;
base::FilePath default_path;
int properties;
if (!FromV8Arguments(args, &title, &default_path, &properties))
return node::ThrowTypeError("Bad argument");
Window* window = Window::Unwrap<Window>(args[0]->ToObject());
if (!window || !window->window())
return node::ThrowError("Invalid window");
NativeWindow* native_window = FromV8Value(args[3]);
std::string title(*v8::String::Utf8Value(args[1]));
base::FilePath default_path(V8ValueToFilePath(args[2]));
if (!args[4]->IsFunction()) {
std::vector<base::FilePath> paths;
if (!file_dialog::ShowOpenDialog(native_window,
title,
default_path,
properties,
&paths))
return;
base::FilePath path;
if (!file_dialog::ShowSaveDialog(window->window(),
title,
default_path,
&path))
return v8::Undefined();
v8::Handle<v8::Array> result = v8::Array::New(paths.size());
for (size_t i = 0; i < paths.size(); ++i)
result->Set(i, ToV8Value(paths[i]));
return scope.Close(FilePathToV8Value(path));
args.GetReturnValue().Set(result);
} else {
RefCountedV8Function callback = FromV8Value(args[4]);
file_dialog::ShowOpenDialog(
native_window,
title,
default_path,
properties,
base::Bind(&CallV8Function2<const std::vector<base::FilePath>&>,
callback));
}
}
void ShowSaveDialog(const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string title;
base::FilePath default_path;
if (!FromV8Arguments(args, &title, &default_path))
return node::ThrowTypeError("Bad argument");
NativeWindow* native_window = FromV8Value(args[2]);
if (!args[3]->IsFunction()) {
base::FilePath path;
if (file_dialog::ShowSaveDialog(native_window,
title,
default_path,
&path))
args.GetReturnValue().Set(ToV8Value(path));
} else {
RefCountedV8Function callback = FromV8Value(args[3]);
file_dialog::ShowSaveDialog(
native_window,
title,
default_path,
base::Bind(&CallV8Function2<const base::FilePath&>, callback));
}
}
} // namespace api

View File

@@ -11,9 +11,9 @@ namespace atom {
namespace api {
v8::Handle<v8::Value> ShowMessageBox(const v8::Arguments &args);
v8::Handle<v8::Value> ShowOpenDialog(const v8::Arguments &args);
v8::Handle<v8::Value> ShowSaveDialog(const v8::Arguments &args);
void ShowMessageBox(const v8::FunctionCallbackInfo<v8::Value>& args);
void ShowOpenDialog(const v8::FunctionCallbackInfo<v8::Value>& args);
void ShowSaveDialog(const v8::FunctionCallbackInfo<v8::Value>& args);
} // namespace api

View File

@@ -4,56 +4,95 @@
#include "browser/api/atom_api_event.h"
using node::node_isolate;
#include "browser/native_window.h"
#include "common/api/api_messages.h"
#include "common/v8/node_common.h"
#include "common/v8/native_type_conversions.h"
namespace atom {
namespace api {
v8::Persistent<v8::FunctionTemplate> Event::constructor_template_;
ScopedPersistent<v8::Function> Event::constructor_template_;
Event::Event()
: prevent_default_(false) {
: sender_(NULL),
message_(NULL),
prevent_default_(false) {
}
Event::~Event() {
if (sender_ != NULL)
sender_->RemoveObserver(this);
}
// static
v8::Handle<v8::Object> Event::CreateV8Object() {
v8::HandleScope scope;
if (constructor_template_.IsEmpty()) {
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(New);
constructor_template_ = v8::Persistent<v8::FunctionTemplate>::New(
node_isolate, t);
constructor_template_->InstanceTemplate()->SetInternalFieldCount(1);
constructor_template_->SetClassName(v8::String::NewSymbol("Event"));
t->InstanceTemplate()->SetInternalFieldCount(1);
t->SetClassName(v8::String::NewSymbol("Event"));
NODE_SET_PROTOTYPE_METHOD(t, "preventDefault", PreventDefault);
NODE_SET_PROTOTYPE_METHOD(t, "sendReply", SendReply);
NODE_SET_PROTOTYPE_METHOD(t, "destroy", Destroy);
constructor_template_.reset(t->GetFunction());
}
v8::Handle<v8::Object> v8_event =
constructor_template_->GetFunction()->NewInstance(0, NULL);
return scope.Close(v8_event);
v8::Handle<v8::Function> t = constructor_template_.NewHandle(node_isolate);
return t->NewInstance(0, NULL);
}
v8::Handle<v8::Value> Event::New(const v8::Arguments &args) {
void Event::SetSenderAndMessage(NativeWindow* sender, IPC::Message* message) {
DCHECK(!sender_);
DCHECK(!message_);
sender_ = sender;
message_ = message;
sender_->AddObserver(this);
}
void Event::OnWindowClosed() {
sender_ = NULL;
message_ = NULL;
}
// static
void Event::New(const v8::FunctionCallbackInfo<v8::Value>& args) {
Event* event = new Event;
event->Wrap(args.This());
return args.This();
}
v8::Handle<v8::Value> Event::PreventDefault(const v8::Arguments &args) {
// static
void Event::PreventDefault(const v8::FunctionCallbackInfo<v8::Value>& args) {
Event* event = Unwrap<Event>(args.This());
if (event == NULL)
return node::ThrowError("Event is already destroyed");
event->prevent_default_ = true;
}
return v8::Undefined();
// static
void Event::SendReply(const v8::FunctionCallbackInfo<v8::Value>& args) {
Event* event = Unwrap<Event>(args.This());
if (event == NULL)
return node::ThrowError("Event is already destroyed");
if (event->message_ == NULL || event->sender_ == NULL)
return node::ThrowError("Can only send reply to synchronous events");
string16 json = FromV8Value(args[0]);
AtomViewHostMsg_Message_Sync::WriteReplyParams(event->message_, json);
event->sender_->Send(event->message_);
delete event;
}
// static
void Event::Destroy(const v8::FunctionCallbackInfo<v8::Value>& args) {
delete Unwrap<Event>(args.This());
}
} // namespace api

View File

@@ -6,21 +6,32 @@
#define ATOM_BROWSER_ATOM_API_EVENT_H_
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/strings/string16.h"
#include "browser/native_window_observer.h"
#include "common/v8/scoped_persistent.h"
#include "vendor/node/src/node_object_wrap.h"
namespace IPC {
class Message;
}
namespace atom {
class NativeWindow;
namespace api {
class Event : public node::ObjectWrap {
class Event : public node::ObjectWrap,
public NativeWindowObserver {
public:
virtual ~Event();
// Create a V8 Event object.
static v8::Handle<v8::Object> CreateV8Object();
// Accessor to return handle_, this follows Google C++ Style.
v8::Persistent<v8::Object>& handle() { return handle_; }
// Pass the sender and message to be replied.
void SetSenderAndMessage(NativeWindow* sender, IPC::Message* message);
// Whether event.preventDefault() is called.
bool prevent_default() const { return prevent_default_; }
@@ -28,11 +39,21 @@ class Event : public node::ObjectWrap {
protected:
Event();
private:
static v8::Handle<v8::Value> New(const v8::Arguments &args);
static v8::Handle<v8::Value> PreventDefault(const v8::Arguments &args);
// NativeWindowObserver implementations:
virtual void OnWindowClosed() OVERRIDE;
static v8::Persistent<v8::FunctionTemplate> constructor_template_;
private:
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void PreventDefault(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SendReply(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Destroy(const v8::FunctionCallbackInfo<v8::Value>& args);
static ScopedPersistent<v8::Function> constructor_template_;
// Replyer for the synchronous messages.
NativeWindow* sender_;
IPC::Message* message_;
bool prevent_default_;

View File

@@ -4,8 +4,9 @@
#include "browser/api/atom_api_menu.h"
#include "browser/api/atom_api_window.h"
#include "browser/ui/accelerator_util.h"
#include "common/v8/node_common.h"
#include "common/v8/native_type_conversions.h"
#define UNWRAP_MEMNU_AND_CHECK \
Menu* self = ObjectWrap::Unwrap<Menu>(args.This()); \
@@ -18,23 +19,12 @@ namespace api {
namespace {
// Converts a V8 value to a string16.
string16 V8ValueToUTF16(v8::Handle<v8::Value> value) {
v8::String::Value s(value);
return string16(reinterpret_cast<const char16*>(*s), s.length());
}
// Converts string16 to V8 String.
v8::Handle<v8::Value> UTF16ToV8Value(const string16& s) {
return v8::String::New(reinterpret_cast<const uint16_t*>(s.data()), s.size());
}
// Call method of delegate object.
v8::Handle<v8::Value> CallDelegate(v8::Handle<v8::Value> default_value,
v8::Handle<v8::Object> menu,
const char* method,
int command_id) {
v8::HandleScope scope;
v8::HandleScope handle_scope(node_isolate);
v8::Handle<v8::Value> delegate = menu->Get(v8::String::New("delegate"));
if (!delegate->IsObject())
@@ -47,7 +37,7 @@ v8::Handle<v8::Value> CallDelegate(v8::Handle<v8::Value> default_value,
v8::Handle<v8::Value> argv = v8::Integer::New(command_id);
return scope.Close(
return handle_scope.Close(
function->Call(v8::Context::GetCurrent()->Global(), 1, &argv));
}
@@ -62,38 +52,38 @@ Menu::~Menu() {
}
bool Menu::IsCommandIdChecked(int command_id) const {
v8::HandleScope scope;
v8::HandleScope handle_scope(node_isolate);
return CallDelegate(v8::False(),
handle(),
const_cast<Menu*>(this)->handle(),
"isCommandIdChecked",
command_id)->BooleanValue();
}
bool Menu::IsCommandIdEnabled(int command_id) const {
v8::HandleScope scope;
v8::HandleScope handle_scope(node_isolate);
return CallDelegate(v8::True(),
handle(),
const_cast<Menu*>(this)->handle(),
"isCommandIdEnabled",
command_id)->BooleanValue();
}
bool Menu::IsCommandIdVisible(int command_id) const {
v8::HandleScope scope;
v8::HandleScope handle_scope(node_isolate);
return CallDelegate(v8::True(),
handle(),
const_cast<Menu*>(this)->handle(),
"isCommandIdVisible",
command_id)->BooleanValue();
}
bool Menu::GetAcceleratorForCommandId(int command_id,
ui::Accelerator* accelerator) {
v8::HandleScope scope;
v8::HandleScope handle_scope(node_isolate);
v8::Handle<v8::Value> shortcut = CallDelegate(v8::Undefined(),
handle(),
"getAcceleratorForCommandId",
command_id);
if (shortcut->IsString()) {
std::string shortcut_str(*v8::String::Utf8Value(shortcut));
std::string shortcut_str = FromV8Value(shortcut);
return accelerator_util::StringToAccelerator(shortcut_str, accelerator);
}
@@ -101,250 +91,223 @@ bool Menu::GetAcceleratorForCommandId(int command_id,
}
bool Menu::IsItemForCommandIdDynamic(int command_id) const {
v8::HandleScope scope;
v8::HandleScope handle_scope(node_isolate);
return CallDelegate(v8::False(),
handle(),
const_cast<Menu*>(this)->handle(),
"isItemForCommandIdDynamic",
command_id)->BooleanValue();
}
string16 Menu::GetLabelForCommandId(int command_id) const {
v8::HandleScope scope;
return V8ValueToUTF16(CallDelegate(v8::False(),
handle(),
"getLabelForCommandId",
command_id));
v8::HandleScope handle_scope(node_isolate);
return FromV8Value(CallDelegate(v8::False(),
const_cast<Menu*>(this)->handle(),
"getLabelForCommandId",
command_id));
}
string16 Menu::GetSublabelForCommandId(int command_id) const {
v8::HandleScope scope;
return V8ValueToUTF16(CallDelegate(v8::False(),
handle(),
"getSubLabelForCommandId",
command_id));
v8::HandleScope handle_scope(node_isolate);
return FromV8Value(CallDelegate(v8::False(),
const_cast<Menu*>(this)->handle(),
"getSubLabelForCommandId",
command_id));
}
void Menu::ExecuteCommand(int command_id, int event_flags) {
v8::HandleScope scope;
v8::HandleScope handle_scope(node_isolate);
CallDelegate(v8::False(), handle(), "executeCommand", command_id);
}
// static
v8::Handle<v8::Value> Menu::New(const v8::Arguments &args) {
v8::HandleScope scope;
void Menu::New(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::HandleScope handle_scope(args.GetIsolate());
if (!args.IsConstructCall())
return node::ThrowError("Require constructor call");
Menu::Create(args.This());
return args.This();
}
// static
v8::Handle<v8::Value> Menu::InsertItem(const v8::Arguments &args) {
void Menu::InsertItem(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
if (!args[0]->IsNumber() || !args[1]->IsNumber() || !args[2]->IsString())
int index, command_id;
string16 label;
if (!FromV8Arguments(args, &index, &command_id, &label))
return node::ThrowTypeError("Bad argument");
int index = args[0]->IntegerValue();
if (index < 0)
self->model_->AddItem(args[1]->IntegerValue(), V8ValueToUTF16(args[2]));
self->model_->AddItem(command_id, label);
else
self->model_->InsertItemAt(
index, args[1]->IntegerValue(), V8ValueToUTF16(args[2]));
return v8::Undefined();
self->model_->InsertItemAt(index, command_id, label);
}
// static
v8::Handle<v8::Value> Menu::InsertCheckItem(const v8::Arguments &args) {
void Menu::InsertCheckItem(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
if (!args[0]->IsNumber() || !args[1]->IsNumber() || !args[2]->IsString())
int index, command_id;
string16 label;
if (!FromV8Arguments(args, &index, &command_id, &label))
return node::ThrowTypeError("Bad argument");
int index = args[0]->IntegerValue();
int command_id = args[1]->IntegerValue();
if (index < 0)
self->model_->AddCheckItem(command_id, V8ValueToUTF16(args[2]));
self->model_->AddCheckItem(command_id, label);
else
self->model_->InsertCheckItemAt(index, command_id, V8ValueToUTF16(args[2]));
return v8::Undefined();
self->model_->InsertCheckItemAt(index, command_id, label);
}
// static
v8::Handle<v8::Value> Menu::InsertRadioItem(const v8::Arguments &args) {
void Menu::InsertRadioItem(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
if (!args[0]->IsNumber() ||
!args[1]->IsNumber() ||
!args[2]->IsString() ||
!args[3]->IsNumber())
int index, command_id, group_id;
string16 label;
if (!FromV8Arguments(args, &index, &command_id, &label, &group_id))
return node::ThrowTypeError("Bad argument");
int index = args[0]->IntegerValue();
int command_id = args[1]->IntegerValue();
int group_id = args[3]->IntegerValue();
if (index < 0)
self->model_->AddRadioItem(command_id, V8ValueToUTF16(args[2]), group_id);
self->model_->AddRadioItem(command_id, label, group_id);
else
self->model_->InsertRadioItemAt(
index, command_id, V8ValueToUTF16(args[2]), group_id);
return v8::Undefined();
self->model_->InsertRadioItemAt(index, command_id, label, group_id);
}
// static
v8::Handle<v8::Value> Menu::InsertSeparator(const v8::Arguments &args) {
void Menu::InsertSeparator(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
if (!args[0]->IsNumber())
int index;
if (!FromV8Arguments(args, &index))
return node::ThrowTypeError("Bad argument");
int index = args[0]->IntegerValue();
if (index < 0)
self->model_->AddSeparator(ui::NORMAL_SEPARATOR);
else
self->model_->InsertSeparatorAt(index, ui::NORMAL_SEPARATOR);
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Menu::InsertSubMenu(const v8::Arguments &args) {
void Menu::InsertSubMenu(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
if (!args[0]->IsNumber() ||
!args[1]->IsNumber() ||
!args[2]->IsString() ||
!args[3]->IsObject())
int index, command_id;
string16 label;
if (!FromV8Arguments(args, &index, &command_id, &label))
return node::ThrowTypeError("Bad argument");
Menu* submenu = ObjectWrap::Unwrap<Menu>(args[3]->ToObject());
if (!submenu)
return node::ThrowTypeError("The submenu is already destroyed");
int index = args[0]->IntegerValue();
int command_id = args[1]->IntegerValue();
if (index < 0)
self->model_->AddSubMenu(
command_id, V8ValueToUTF16(args[2]), submenu->model_.get());
self->model_->AddSubMenu(command_id, label, submenu->model_.get());
else
self->model_->InsertSubMenuAt(
index, command_id, V8ValueToUTF16(args[2]), submenu->model_.get());
return v8::Undefined();
index, command_id, label, submenu->model_.get());
}
// static
v8::Handle<v8::Value> Menu::SetIcon(const v8::Arguments &args) {
void Menu::SetIcon(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
if (!args[0]->IsNumber() || !args[1]->IsString())
int index;
base::FilePath path;
if (!FromV8Arguments(args, &index, &path))
return node::ThrowTypeError("Bad argument");
// FIXME use webkit_glue's image decoder here.
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Menu::SetSublabel(const v8::Arguments &args) {
void Menu::SetSublabel(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
if (!args[0]->IsNumber() || !args[1]->IsString())
int index;
string16 label;
if (!FromV8Arguments(args, &index, &label))
return node::ThrowTypeError("Bad argument");
self->model_->SetSublabel(args[0]->IntegerValue(), V8ValueToUTF16(args[1]));
return v8::Undefined();
self->model_->SetSublabel(index, label);
}
// static
v8::Handle<v8::Value> Menu::Clear(const v8::Arguments &args) {
void Menu::Clear(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
self->model_->Clear();
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Menu::GetIndexOfCommandId(const v8::Arguments &args) {
void Menu::GetIndexOfCommandId(
const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
int index = args[0]->IntegerValue();
return v8::Integer::New(self->model_->GetIndexOfCommandId(index));
int index = FromV8Value(args[0]);
args.GetReturnValue().Set(self->model_->GetIndexOfCommandId(index));
}
// static
v8::Handle<v8::Value> Menu::GetItemCount(const v8::Arguments &args) {
void Menu::GetItemCount(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
return v8::Integer::New(self->model_->GetItemCount());
args.GetReturnValue().Set(self->model_->GetItemCount());
}
// static
v8::Handle<v8::Value> Menu::GetCommandIdAt(const v8::Arguments &args) {
void Menu::GetCommandIdAt(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
int index = args[0]->IntegerValue();
return v8::Integer::New(self->model_->GetCommandIdAt(index));
int index = FromV8Value(args[0]);
args.GetReturnValue().Set(self->model_->GetCommandIdAt(index));
}
// static
v8::Handle<v8::Value> Menu::GetLabelAt(const v8::Arguments &args) {
void Menu::GetLabelAt(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
int index = args[0]->IntegerValue();
return UTF16ToV8Value(self->model_->GetLabelAt(index));
int index = FromV8Value(args[0]);
args.GetReturnValue().Set(ToV8Value(self->model_->GetLabelAt(index)));
}
// static
v8::Handle<v8::Value> Menu::GetSublabelAt(const v8::Arguments &args) {
void Menu::GetSublabelAt(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
int index = args[0]->IntegerValue();
return UTF16ToV8Value(self->model_->GetSublabelAt(index));
int index = FromV8Value(args[0]);
args.GetReturnValue().Set(ToV8Value(self->model_->GetSublabelAt(index)));
}
// static
v8::Handle<v8::Value> Menu::IsItemCheckedAt(const v8::Arguments &args) {
void Menu::IsItemCheckedAt(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
int index = args[0]->IntegerValue();
return v8::Boolean::New(self->model_->IsItemCheckedAt(index));
int index = FromV8Value(args[0]);
args.GetReturnValue().Set(self->model_->IsItemCheckedAt(index));
}
// static
v8::Handle<v8::Value> Menu::IsEnabledAt(const v8::Arguments &args) {
void Menu::IsEnabledAt(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
return v8::Boolean::New(self->model_->IsEnabledAt(args[0]->IntegerValue()));
int index = FromV8Value(args[0]);
args.GetReturnValue().Set(self->model_->IsEnabledAt(index));
}
// static
v8::Handle<v8::Value> Menu::IsVisibleAt(const v8::Arguments &args) {
void Menu::IsVisibleAt(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
return v8::Boolean::New(self->model_->IsVisibleAt(args[0]->IntegerValue()));
int index = FromV8Value(args[0]);
args.GetReturnValue().Set(self->model_->IsVisibleAt(index));
}
// static
v8::Handle<v8::Value> Menu::Popup(const v8::Arguments &args) {
void Menu::Popup(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_MEMNU_AND_CHECK;
Window* window = Window::Unwrap<Window>(args[0]->ToObject());
if (!window)
return node::ThrowTypeError("Invalid window");
atom::NativeWindow* window;
if (!FromV8Arguments(args, &window))
return node::ThrowTypeError("Bad argument");
self->Popup(window->window());
return v8::Undefined();
self->Popup(window);
}
// static
void Menu::Initialize(v8::Handle<v8::Object> target) {
v8::HandleScope scope;
v8::HandleScope handle_scope(node_isolate);
v8::Local<v8::FunctionTemplate> t(v8::FunctionTemplate::New(Menu::New));
t->InstanceTemplate()->SetInternalFieldCount(1);
@@ -372,6 +335,10 @@ void Menu::Initialize(v8::Handle<v8::Object> target) {
NODE_SET_PROTOTYPE_METHOD(t, "popup", Popup);
#if defined(OS_WIN)
NODE_SET_PROTOTYPE_METHOD(t, "attachToWindow", AttachToWindow);
#endif
target->Set(v8::String::NewSymbol("Menu"), t->GetFunction());
#if defined(OS_MACOSX)

View File

@@ -6,7 +6,7 @@
#define ATOM_BROWSER_API_ATOM_API_MENU_H_
#include "base/memory/scoped_ptr.h"
#include "browser/api/atom_api_event_emitter.h"
#include "common/api/atom_api_event_emitter.h"
#include "ui/base/models/simple_menu_model.h"
namespace atom {
@@ -44,34 +44,38 @@ class Menu : public EventEmitter,
scoped_ptr<ui::SimpleMenuModel> model_;
private:
static v8::Handle<v8::Value> New(const v8::Arguments &args);
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static v8::Handle<v8::Value> InsertItem(const v8::Arguments &args);
static v8::Handle<v8::Value> InsertCheckItem(const v8::Arguments &args);
static v8::Handle<v8::Value> InsertRadioItem(const v8::Arguments &args);
static v8::Handle<v8::Value> InsertSeparator(const v8::Arguments &args);
static v8::Handle<v8::Value> InsertSubMenu(const v8::Arguments &args);
static void InsertItem(const v8::FunctionCallbackInfo<v8::Value>& args);
static void InsertCheckItem(const v8::FunctionCallbackInfo<v8::Value>& args);
static void InsertRadioItem(const v8::FunctionCallbackInfo<v8::Value>& args);
static void InsertSeparator(const v8::FunctionCallbackInfo<v8::Value>& args);
static void InsertSubMenu(const v8::FunctionCallbackInfo<v8::Value>& args);
static v8::Handle<v8::Value> SetIcon(const v8::Arguments &args);
static v8::Handle<v8::Value> SetSublabel(const v8::Arguments &args);
static void SetIcon(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetSublabel(const v8::FunctionCallbackInfo<v8::Value>& args);
static v8::Handle<v8::Value> Clear(const v8::Arguments &args);
static void Clear(const v8::FunctionCallbackInfo<v8::Value>& args);
static v8::Handle<v8::Value> GetIndexOfCommandId(const v8::Arguments &args);
static v8::Handle<v8::Value> GetItemCount(const v8::Arguments &args);
static v8::Handle<v8::Value> GetCommandIdAt(const v8::Arguments &args);
static v8::Handle<v8::Value> GetLabelAt(const v8::Arguments &args);
static v8::Handle<v8::Value> GetSublabelAt(const v8::Arguments &args);
static v8::Handle<v8::Value> IsItemCheckedAt(const v8::Arguments &args);
static v8::Handle<v8::Value> IsEnabledAt(const v8::Arguments &args);
static v8::Handle<v8::Value> IsVisibleAt(const v8::Arguments &args);
static void GetIndexOfCommandId(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetItemCount(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetCommandIdAt(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetLabelAt(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetSublabelAt(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsItemCheckedAt(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsEnabledAt(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsVisibleAt(const v8::FunctionCallbackInfo<v8::Value>& args);
static v8::Handle<v8::Value> Popup(const v8::Arguments &args);
static void Popup(const v8::FunctionCallbackInfo<v8::Value>& args);
#if defined(OS_MACOSX)
static v8::Handle<v8::Value> SetApplicationMenu(const v8::Arguments &args);
static v8::Handle<v8::Value> SendActionToFirstResponder(
const v8::Arguments &args);
#if defined(OS_WIN)
static void AttachToWindow(const v8::FunctionCallbackInfo<v8::Value>& args);
#elif defined(OS_MACOSX)
static void SetApplicationMenu(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void SendActionToFirstResponder(
const v8::FunctionCallbackInfo<v8::Value>& args);
#endif
DISALLOW_COPY_AND_ASSIGN(Menu);

View File

@@ -21,7 +21,7 @@ class MenuMac : public Menu {
protected:
virtual void Popup(NativeWindow* window) OVERRIDE;
scoped_nsobject<AtomMenuController> menu_controller_;
base::scoped_nsobject<AtomMenuController> menu_controller_;
private:
friend class Menu;

View File

@@ -4,10 +4,12 @@
#import "browser/api/atom_api_menu_mac.h"
#include "base/message_loop.h"
#include "base/mac/scoped_sending_event.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/sys_string_conversions.h"
#include "browser/native_window.h"
#include "common/v8/node_common.h"
#include "common/v8/native_type_conversions.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
@@ -23,7 +25,7 @@ MenuMac::~MenuMac() {
}
void MenuMac::Popup(NativeWindow* native_window) {
scoped_nsobject<AtomMenuController> menu_controller(
base::scoped_nsobject<AtomMenuController> menu_controller(
[[AtomMenuController alloc] initWithModel:model_.get()]);
NSWindow* window = native_window->GetNativeWindow();
@@ -45,7 +47,8 @@ void MenuMac::Popup(NativeWindow* native_window) {
{
// Make sure events can be pumped while the menu is up.
MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current());
base::MessageLoop::ScopedNestableTaskAllower allow(
base::MessageLoop::current());
// One of the events that could be pumped is |window.close()|.
// User-initiated event-tracking loops protect against this by
@@ -70,8 +73,8 @@ void MenuMac::SendActionToFirstResponder(const std::string& action) {
}
// static
v8::Handle<v8::Value> Menu::SetApplicationMenu(const v8::Arguments &args) {
v8::HandleScope scope;
void Menu::SetApplicationMenu(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::HandleScope handle_scope(args.GetIsolate());
if (!args[0]->IsObject())
return node::ThrowTypeError("Bad argument");
@@ -80,28 +83,24 @@ v8::Handle<v8::Value> Menu::SetApplicationMenu(const v8::Arguments &args) {
if (!menu)
return node::ThrowError("Menu is destroyed");
scoped_nsobject<AtomMenuController> menu_controller(
base::scoped_nsobject<AtomMenuController> menu_controller(
[[AtomMenuController alloc] initWithModel:menu->model_.get()]);
[NSApp setMainMenu:[menu_controller menu]];
// Ensure the menu_controller_ is destroyed after main menu is set.
menu_controller.swap(menu->menu_controller_);
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Menu::SendActionToFirstResponder(
const v8::Arguments &args) {
v8::HandleScope scope;
void Menu::SendActionToFirstResponder(
const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::HandleScope handle_scope(args.GetIsolate());
if (!args[0]->IsString())
std::string action;
if (!FromV8Arguments(args, &action))
return node::ThrowTypeError("Bad argument");
std::string action(*v8::String::Utf8Value(args[0]));
MenuMac::SendActionToFirstResponder(action);
return v8::Undefined();
}
// static

View File

@@ -4,8 +4,13 @@
#include "browser/api/atom_api_menu_win.h"
#include "browser/native_window_win.h"
#include "browser/ui/win/menu_2.h"
#include "common/v8/native_type_conversions.h"
#include "ui/gfx/point.h"
#include "ui/gfx/screen.h"
#include "common/v8/node_common.h"
namespace atom {
@@ -19,8 +24,24 @@ MenuWin::~MenuWin() {
}
void MenuWin::Popup(NativeWindow* native_window) {
gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
menu_.reset(new atom::Menu2(model_.get()));
menu_->RunContextMenuAt(gfx::Point(0, 0));
menu_->RunContextMenuAt(cursor);
}
// static
void Menu::AttachToWindow(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::HandleScope handle_scope(args.GetIsolate());
Menu* self = ObjectWrap::Unwrap<Menu>(args.This());
if (self == NULL)
return node::ThrowError("Menu is already destroyed");
NativeWindow* native_window;
if (!FromV8Arguments(args, &native_window))
return node::ThrowTypeError("Bad argument");
static_cast<NativeWindowWin*>(native_window)->SetMenu(self->model_.get());
}
// static

View File

@@ -5,6 +5,9 @@
#include "browser/api/atom_api_power_monitor.h"
#include "base/power_monitor/power_monitor.h"
#include "base/power_monitor/power_monitor_device_source.h"
#include "common/v8/node_common.h"
namespace atom {
@@ -35,20 +38,22 @@ void PowerMonitor::OnResume() {
}
// static
v8::Handle<v8::Value> PowerMonitor::New(const v8::Arguments& args) {
v8::HandleScope scope;
void PowerMonitor::New(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::HandleScope handle_scope(args.GetIsolate());
if (!args.IsConstructCall())
return node::ThrowError("Require constructor call");
new PowerMonitor(args.This());
return args.This();
}
// static
void PowerMonitor::Initialize(v8::Handle<v8::Object> target) {
v8::HandleScope scope;
v8::HandleScope handle_scope(node_isolate);
#if defined(OS_MACOSX)
base::PowerMonitorDeviceSource::AllocateSystemIOPorts();
#endif
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(
PowerMonitor::New);

View File

@@ -5,10 +5,9 @@
#ifndef ATOM_BROWSER_API_ATOM_API_POWER_MONITOR_H_
#define ATOM_BROWSER_API_ATOM_API_POWER_MONITOR_H_
#include "browser/api/atom_api_event_emitter.h"
#include "base/compiler_specific.h"
#include "base/power_monitor/power_observer.h"
#include "common/api/atom_api_event_emitter.h"
namespace atom {
@@ -29,7 +28,7 @@ class PowerMonitor : public EventEmitter,
virtual void OnResume() OVERRIDE;
private:
static v8::Handle<v8::Value> New(const v8::Arguments &args);
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
DISALLOW_COPY_AND_ASSIGN(PowerMonitor);
};

View File

@@ -0,0 +1,380 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "browser/api/atom_api_protocol.h"
#include "base/stl_util.h"
#include "browser/atom_browser_context.h"
#include "browser/net/adapter_request_job.h"
#include "browser/net/atom_url_request_context_getter.h"
#include "browser/net/atom_url_request_job_factory.h"
#include "common/v8/native_type_conversions.h"
#include "content/public/browser/browser_thread.h"
#include "net/url_request/url_request_context.h"
#include "common/v8/node_common.h"
namespace atom {
namespace api {
typedef net::URLRequestJobFactory::ProtocolHandler ProtocolHandler;
namespace {
// The protocol module object.
ScopedPersistent<v8::Object> g_protocol_object;
// Registered protocol handlers.
typedef std::map<std::string, RefCountedV8Function> HandlersMap;
static HandlersMap g_handlers;
static const char* kEarlyUseProtocolError = "This method can only be used"
"after the application has finished launching.";
// Emit an event for the protocol module.
void EmitEventInUI(const std::string& event, const std::string& parameter) {
v8::HandleScope handle_scope(node_isolate);
v8::Handle<v8::Value> argv[] = {
ToV8Value(event),
ToV8Value(parameter),
};
node::MakeCallback(g_protocol_object.NewHandle(node_isolate),
"emit", 2, argv);
}
// Convert the URLRequest object to V8 object.
v8::Handle<v8::Object> ConvertURLRequestToV8Object(
const net::URLRequest* request) {
v8::Local<v8::Object> obj = v8::Object::New();
obj->Set(ToV8Value("method"), ToV8Value(request->method()));
obj->Set(ToV8Value("url"), ToV8Value(request->url().spec()));
obj->Set(ToV8Value("referrer"), ToV8Value(request->referrer()));
return obj;
}
// Get the job factory.
AtomURLRequestJobFactory* GetRequestJobFactory() {
return AtomBrowserContext::Get()->url_request_context_getter()->job_factory();
}
class CustomProtocolRequestJob : public AdapterRequestJob {
public:
CustomProtocolRequestJob(ProtocolHandler* protocol_handler,
net::URLRequest* request,
net::NetworkDelegate* network_delegate)
: AdapterRequestJob(protocol_handler, request, network_delegate) {
}
// AdapterRequestJob:
virtual void GetJobTypeInUI() OVERRIDE {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
v8::HandleScope handle_scope(node_isolate);
// Call the JS handler.
v8::Handle<v8::Value> argv[] = {
ConvertURLRequestToV8Object(request()),
};
RefCountedV8Function callback = g_handlers[request()->url().scheme()];
v8::Handle<v8::Value> result = callback->NewHandle(node_isolate)->Call(
v8::Context::GetCurrent()->Global(), 1, argv);
// Determine the type of the job we are going to create.
if (result->IsString()) {
std::string data = FromV8Value(result);
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
base::Bind(&AdapterRequestJob::CreateStringJobAndStart,
GetWeakPtr(),
"text/plain",
"UTF-8",
data));
return;
} else if (result->IsObject()) {
v8::Handle<v8::Object> obj = result->ToObject();
std::string name = FromV8Value(obj->GetConstructorName());
if (name == "RequestStringJob") {
std::string mime_type = FromV8Value(obj->Get(
v8::String::New("mimeType")));
std::string charset = FromV8Value(obj->Get(v8::String::New("charset")));
std::string data = FromV8Value(obj->Get(v8::String::New("data")));
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
base::Bind(&AdapterRequestJob::CreateStringJobAndStart,
GetWeakPtr(),
mime_type,
charset,
data));
return;
} else if (name == "RequestFileJob") {
base::FilePath path = FromV8Value(obj->Get(v8::String::New("path")));
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
base::Bind(&AdapterRequestJob::CreateFileJobAndStart,
GetWeakPtr(),
path));
return;
}
}
// Try the default protocol handler if we have.
if (default_protocol_handler()) {
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
base::Bind(&AdapterRequestJob::CreateJobFromProtocolHandlerAndStart,
GetWeakPtr()));
return;
}
// Fallback to the not implemented error.
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
base::Bind(&AdapterRequestJob::CreateErrorJobAndStart,
GetWeakPtr(),
net::ERR_NOT_IMPLEMENTED));
}
};
// Always return the same CustomProtocolRequestJob for all requests, because
// the content API needs the ProtocolHandler to return a job immediately, and
// getting the real job from the JS requires asynchronous calls, so we have
// to create an adapter job first.
// Users can also pass an extra ProtocolHandler as the fallback one when
// registered handler doesn't want to deal with the request.
class CustomProtocolHandler : public ProtocolHandler {
public:
explicit CustomProtocolHandler(ProtocolHandler* protocol_handler = NULL)
: protocol_handler_(protocol_handler) {
}
virtual net::URLRequestJob* MaybeCreateJob(
net::URLRequest* request,
net::NetworkDelegate* network_delegate) const OVERRIDE {
return new CustomProtocolRequestJob(protocol_handler_.get(),
request,
network_delegate);
}
ProtocolHandler* ReleaseDefaultProtocolHandler() {
return protocol_handler_.release();
}
ProtocolHandler* original_handler() { return protocol_handler_.get(); }
private:
scoped_ptr<ProtocolHandler> protocol_handler_;
DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler);
};
} // namespace
// static
void Protocol::RegisterProtocol(
const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string scheme;
RefCountedV8Function callback;
if (!FromV8Arguments(args, &scheme, &callback))
return node::ThrowTypeError("Bad argument");
if (g_handlers.find(scheme) != g_handlers.end() ||
GetRequestJobFactory()->IsHandledProtocol(scheme))
return node::ThrowError("The scheme is already registered");
if (AtomBrowserContext::Get()->url_request_context_getter() == NULL)
return node::ThrowError(kEarlyUseProtocolError);
// Store the handler in a map.
g_handlers[scheme] = callback;
content::BrowserThread::PostTask(content::BrowserThread::IO,
FROM_HERE,
base::Bind(&RegisterProtocolInIO, scheme));
}
// static
void Protocol::UnregisterProtocol(
const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string scheme;
if (!FromV8Arguments(args, &scheme))
return node::ThrowTypeError("Bad argument");
if (AtomBrowserContext::Get()->url_request_context_getter() == NULL)
return node::ThrowError(kEarlyUseProtocolError);
// Erase the handler from map.
HandlersMap::iterator it(g_handlers.find(scheme));
if (it == g_handlers.end())
return node::ThrowError("The scheme has not been registered");
g_handlers.erase(it);
content::BrowserThread::PostTask(content::BrowserThread::IO,
FROM_HERE,
base::Bind(&UnregisterProtocolInIO, scheme));
}
// static
void Protocol::IsHandledProtocol(
const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string scheme;
if (!FromV8Arguments(args, &scheme))
return node::ThrowTypeError("Bad argument");
args.GetReturnValue().Set(GetRequestJobFactory()->IsHandledProtocol(scheme));
}
// static
void Protocol::InterceptProtocol(
const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string scheme;
RefCountedV8Function callback;
if (!FromV8Arguments(args, &scheme, &callback))
return node::ThrowTypeError("Bad argument");
if (!GetRequestJobFactory()->HasProtocolHandler(scheme))
return node::ThrowError("Cannot intercept procotol");
if (ContainsKey(g_handlers, scheme))
return node::ThrowError("Cannot intercept custom procotols");
if (AtomBrowserContext::Get()->url_request_context_getter() == NULL)
return node::ThrowError(kEarlyUseProtocolError);
// Store the handler in a map.
g_handlers[scheme] = callback;
content::BrowserThread::PostTask(content::BrowserThread::IO,
FROM_HERE,
base::Bind(&InterceptProtocolInIO, scheme));
}
// static
void Protocol::UninterceptProtocol(
const v8::FunctionCallbackInfo<v8::Value>& args) {
std::string scheme;
if (!FromV8Arguments(args, &scheme))
return node::ThrowTypeError("Bad argument");
if (AtomBrowserContext::Get()->url_request_context_getter() == NULL)
return node::ThrowError(kEarlyUseProtocolError);
// Erase the handler from map.
HandlersMap::iterator it(g_handlers.find(scheme));
if (it == g_handlers.end())
return node::ThrowError("The scheme has not been registered");
g_handlers.erase(it);
content::BrowserThread::PostTask(content::BrowserThread::IO,
FROM_HERE,
base::Bind(&UninterceptProtocolInIO,
scheme));
}
// static
void Protocol::RegisterProtocolInIO(const std::string& scheme) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
AtomURLRequestJobFactory* job_factory(GetRequestJobFactory());
job_factory->SetProtocolHandler(scheme, new CustomProtocolHandler);
content::BrowserThread::PostTask(content::BrowserThread::UI,
FROM_HERE,
base::Bind(&EmitEventInUI,
"registered",
scheme));
}
// static
void Protocol::UnregisterProtocolInIO(const std::string& scheme) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
AtomURLRequestJobFactory* job_factory(GetRequestJobFactory());
job_factory->SetProtocolHandler(scheme, NULL);
content::BrowserThread::PostTask(content::BrowserThread::UI,
FROM_HERE,
base::Bind(&EmitEventInUI,
"unregistered",
scheme));
}
// static
void Protocol::InterceptProtocolInIO(const std::string& scheme) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
AtomURLRequestJobFactory* job_factory(GetRequestJobFactory());
ProtocolHandler* original_handler = job_factory->GetProtocolHandler(scheme);
if (original_handler == NULL) {
content::BrowserThread::PostTask(
content::BrowserThread::UI,
FROM_HERE,
base::Bind(&EmitEventInUI,
"error",
"There is no protocol handler to intercpet"));
return;
}
job_factory->ReplaceProtocol(scheme,
new CustomProtocolHandler(original_handler));
content::BrowserThread::PostTask(content::BrowserThread::UI,
FROM_HERE,
base::Bind(&EmitEventInUI,
"intercepted",
scheme));
}
// static
void Protocol::UninterceptProtocolInIO(const std::string& scheme) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
AtomURLRequestJobFactory* job_factory(GetRequestJobFactory());
// Check if the protocol handler is intercepted.
CustomProtocolHandler* handler = static_cast<CustomProtocolHandler*>(
job_factory->GetProtocolHandler(scheme));
if (handler->original_handler() == NULL) {
content::BrowserThread::PostTask(
content::BrowserThread::UI,
FROM_HERE,
base::Bind(&EmitEventInUI,
"error",
"The protocol is not intercpeted"));
return;
}
// Reset the protocol handler to the orignal one and delete current
// protocol handler.
ProtocolHandler* original_handler = handler->ReleaseDefaultProtocolHandler();
delete job_factory->ReplaceProtocol(scheme, original_handler);
content::BrowserThread::PostTask(content::BrowserThread::UI,
FROM_HERE,
base::Bind(&EmitEventInUI,
"unintercepted",
scheme));
}
// static
void Protocol::Initialize(v8::Handle<v8::Object> target) {
// Remember the protocol object, used for emitting event later.
g_protocol_object.reset(target);
NODE_SET_METHOD(target, "registerProtocol", RegisterProtocol);
NODE_SET_METHOD(target, "unregisterProtocol", UnregisterProtocol);
NODE_SET_METHOD(target, "isHandledProtocol", IsHandledProtocol);
NODE_SET_METHOD(target, "interceptProtocol", InterceptProtocol);
NODE_SET_METHOD(target, "uninterceptProtocol", UninterceptProtocol);
}
} // namespace api
} // namespace atom
NODE_MODULE(atom_browser_protocol, atom::api::Protocol::Initialize)

View File

@@ -0,0 +1,47 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_API_ATOM_API_PROTOCOL_H_
#define ATOM_BROWSER_API_ATOM_API_PROTOCOL_H_
#include <string>
#include <map>
#include "base/basictypes.h"
#include "v8/include/v8.h"
namespace atom {
namespace api {
class Protocol {
public:
static void Initialize(v8::Handle<v8::Object> target);
private:
static void RegisterProtocol(const v8::FunctionCallbackInfo<v8::Value>& args);
static void UnregisterProtocol(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsHandledProtocol(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void InterceptProtocol(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void UninterceptProtocol(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void RegisterProtocolInIO(const std::string& scheme);
static void UnregisterProtocolInIO(const std::string& scheme);
static void InterceptProtocolInIO(const std::string& scheme);
static void UninterceptProtocolInIO(const std::string& scheme);
DISALLOW_IMPLICIT_CONSTRUCTORS(Protocol);
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_ATOM_API_PROTOCOL_H_

View File

@@ -4,17 +4,19 @@
#include "browser/api/atom_api_window.h"
#include "base/values.h"
#include "base/bind.h"
#include "base/process/kill.h"
#include "browser/native_window.h"
#include "common/v8_value_converter_impl.h"
#include "common/v8/native_type_conversions.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/render_process_host.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
using content::V8ValueConverter;
#include "common/v8/node_common.h"
#include "vendor/node/src/node_buffer.h"
using content::NavigationController;
using node::ObjectWrap;
@@ -27,15 +29,6 @@ namespace atom {
namespace api {
namespace {
// Converts string16 to V8 String.
v8::Handle<v8::String> UTF16ToV8String(const string16& s) {
return v8::String::New(reinterpret_cast<const uint16_t*>(s.data()), s.size());
}
} // namespace
Window::Window(v8::Handle<v8::Object> wrapper, base::DictionaryValue* options)
: EventEmitter(wrapper),
window_(NativeWindow::Create(options)) {
@@ -69,8 +62,9 @@ void Window::WillCloseWindow(bool* prevent_default) {
void Window::OnWindowClosed() {
Emit("closed");
// Free memory immediately when window is closed.
delete this;
// Free memory when native window is closed, the delete is delayed so other
// observers would not get a invalid pointer of NativeWindow.
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
}
void Window::OnWindowBlur() {
@@ -85,583 +79,553 @@ void Window::OnRendererResponsive() {
Emit("responsive");
}
void Window::OnRenderViewDeleted(int process_id, int routing_id) {
base::ListValue args;
args.AppendInteger(process_id);
args.AppendInteger(routing_id);
Emit("render-view-deleted", &args);
}
void Window::OnRendererCrashed() {
Emit("crashed");
}
void Window::OnCapturePageDone(const RefCountedV8Function& callback,
const std::vector<unsigned char>& data) {
v8::HandleScope handle_scope(node_isolate);
v8::Local<v8::Value> buffer = node::Buffer::New(
reinterpret_cast<const char*>(data.data()),
data.size());
callback->NewHandle(node_isolate)->Call(
v8::Context::GetCurrent()->Global(), 1, &buffer);
}
// static
v8::Handle<v8::Value> Window::New(const v8::Arguments &args) {
v8::HandleScope scope;
void Window::New(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::HandleScope handle_scope(args.GetIsolate());
if (!args.IsConstructCall())
return node::ThrowError("Require constructor call");
if (!args[0]->IsObject())
return node::ThrowTypeError("Need options creating Window");
scoped_ptr<V8ValueConverter> converter(new V8ValueConverterImpl());
scoped_ptr<base::Value> options(
converter->FromV8Value(args[0], v8::Context::GetCurrent()));
scoped_ptr<base::Value> options;
if (!FromV8Arguments(args, &options))
return node::ThrowTypeError("Bad argument");
if (!options || !options->IsType(base::Value::TYPE_DICTIONARY))
return node::ThrowTypeError("Invalid options");
return node::ThrowTypeError("Options must be dictionary");
new Window(args.This(), static_cast<base::DictionaryValue*>(options.get()));
return args.This();
// Give js code a chance to do initialization.
node::MakeCallback(args.This(), "_init", 0, NULL);
}
// static
v8::Handle<v8::Value> Window::Destroy(const v8::Arguments &args) {
void Window::Destroy(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
base::ProcessHandle handle = self->window_->GetRenderProcessHandle();
delete self;
return v8::Undefined();
// Make sure the renderer process is terminated, it could happen that the
// renderer process became a zombie.
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(base::IgnoreResult(base::KillProcess), handle, 0, false),
base::TimeDelta::FromMilliseconds(5000));
}
// static
v8::Handle<v8::Value> Window::Close(const v8::Arguments &args) {
void Window::Close(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->Close();
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Window::Focus(const v8::Arguments &args) {
void Window::Focus(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->Focus(args[0]->IsBoolean() ? args[0]->BooleanValue(): true);
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Window::IsFocused(const v8::Arguments &args) {
void Window::IsFocused(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(self->window_->IsFocused());
args.GetReturnValue().Set(self->window_->IsFocused());
}
// static
v8::Handle<v8::Value> Window::Show(const v8::Arguments &args) {
void Window::Show(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->Show();
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Window::Hide(const v8::Arguments &args) {
void Window::Hide(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->Hide();
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Window::Maximize(const v8::Arguments &args) {
void Window::IsVisible(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
return args.GetReturnValue().Set(self->window_->IsVisible());
}
// static
void Window::Maximize(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->Maximize();
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Window::Unmaximize(const v8::Arguments &args) {
void Window::Unmaximize(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->Unmaximize();
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Window::Minimize(const v8::Arguments &args) {
void Window::Minimize(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->Minimize();
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Window::Restore(const v8::Arguments &args) {
void Window::Restore(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->Restore();
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Window::SetFullscreen(const v8::Arguments &args) {
void Window::SetFullscreen(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 1 || !args[0]->IsBoolean())
bool fs;
if (!FromV8Arguments(args, &fs))
return node::ThrowTypeError("Bad argument");
self->window_->SetFullscreen(args[0]->BooleanValue());
return v8::Undefined();
self->window_->SetFullscreen(fs);
}
// static
v8::Handle<v8::Value> Window::IsFullscreen(const v8::Arguments &args) {
void Window::IsFullscreen(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(self->window_->IsFullscreen());
args.GetReturnValue().Set(self->window_->IsFullscreen());
}
// static
v8::Handle<v8::Value> Window::SetSize(const v8::Arguments &args) {
void Window::SetSize(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 2)
int width, height;
if (!FromV8Arguments(args, &width, &height))
return node::ThrowTypeError("Bad argument");
self->window_->SetSize(
gfx::Size(args[0]->IntegerValue(), args[1]->IntegerValue()));
return v8::Undefined();
self->window_->SetSize(gfx::Size(width, height));
}
// static
v8::Handle<v8::Value> Window::GetSize(const v8::Arguments &args) {
void Window::GetSize(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
gfx::Size size = self->window_->GetSize();
v8::Handle<v8::Array> ret = v8::Array::New(2);
ret->Set(0, v8::Integer::New(size.width()));
ret->Set(1, v8::Integer::New(size.height()));
ret->Set(0, ToV8Value(size.width()));
ret->Set(1, ToV8Value(size.height()));
return ret;
args.GetReturnValue().Set(ret);
}
// static
v8::Handle<v8::Value> Window::SetMinimumSize(const v8::Arguments &args) {
void Window::SetMinimumSize(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 2)
int width, height;
if (!FromV8Arguments(args, &width, &height))
return node::ThrowTypeError("Bad argument");
self->window_->SetMinimumSize(
gfx::Size(args[0]->IntegerValue(), args[1]->IntegerValue()));
return v8::Undefined();
self->window_->SetMinimumSize(gfx::Size(width, height));
}
// static
v8::Handle<v8::Value> Window::GetMinimumSize(const v8::Arguments &args) {
void Window::GetMinimumSize(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
gfx::Size size = self->window_->GetMinimumSize();
v8::Handle<v8::Array> ret = v8::Array::New(2);
ret->Set(0, v8::Integer::New(size.width()));
ret->Set(1, v8::Integer::New(size.height()));
ret->Set(0, ToV8Value(size.width()));
ret->Set(1, ToV8Value(size.height()));
return ret;
args.GetReturnValue().Set(ret);
}
// static
v8::Handle<v8::Value> Window::SetMaximumSize(const v8::Arguments &args) {
void Window::SetMaximumSize(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 2)
int width, height;
if (!FromV8Arguments(args, &width, &height))
return node::ThrowTypeError("Bad argument");
self->window_->SetMaximumSize(
gfx::Size(args[0]->IntegerValue(), args[1]->IntegerValue()));
return v8::Undefined();
self->window_->SetMaximumSize(gfx::Size(width, height));
}
// static
v8::Handle<v8::Value> Window::GetMaximumSize(const v8::Arguments &args) {
void Window::GetMaximumSize(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
gfx::Size size = self->window_->GetMaximumSize();
v8::Handle<v8::Array> ret = v8::Array::New(2);
ret->Set(0, v8::Integer::New(size.width()));
ret->Set(1, v8::Integer::New(size.height()));
ret->Set(0, ToV8Value(size.width()));
ret->Set(1, ToV8Value(size.height()));
return ret;
args.GetReturnValue().Set(ret);
}
// static
v8::Handle<v8::Value> Window::SetResizable(const v8::Arguments &args) {
void Window::SetResizable(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 1 || !args[0]->IsBoolean())
bool resizable;
if (!FromV8Arguments(args, &resizable))
return node::ThrowTypeError("Bad argument");
self->window_->SetResizable(args[0]->BooleanValue());
return v8::Undefined();
self->window_->SetResizable(resizable);
}
// static
v8::Handle<v8::Value> Window::IsResizable(const v8::Arguments &args) {
void Window::IsResizable(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(self->window_->IsResizable());
args.GetReturnValue().Set(self->window_->IsResizable());
}
// static
v8::Handle<v8::Value> Window::SetAlwaysOnTop(const v8::Arguments &args) {
void Window::SetAlwaysOnTop(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 1 || !args[0]->IsBoolean())
bool top;
if (!FromV8Arguments(args, &top))
return node::ThrowTypeError("Bad argument");
self->window_->SetAlwaysOnTop(args[0]->BooleanValue());
return v8::Undefined();
self->window_->SetAlwaysOnTop(top);
}
// static
v8::Handle<v8::Value> Window::IsAlwaysOnTop(const v8::Arguments &args) {
void Window::IsAlwaysOnTop(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(self->window_->IsAlwaysOnTop());
args.GetReturnValue().Set(self->window_->IsAlwaysOnTop());
}
// static
v8::Handle<v8::Value> Window::Center(const v8::Arguments &args) {
void Window::Center(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->Center();
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Window::SetPosition(const v8::Arguments &args) {
void Window::SetPosition(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 2)
int x, y;
if (!FromV8Arguments(args, &x, &y))
return node::ThrowTypeError("Bad argument");
self->window_->SetPosition(
gfx::Point(args[0]->IntegerValue(), args[1]->IntegerValue()));
return v8::Undefined();
self->window_->SetPosition(gfx::Point(x, y));
}
// static
v8::Handle<v8::Value> Window::GetPosition(const v8::Arguments &args) {
void Window::GetPosition(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
gfx::Point pos = self->window_->GetPosition();
v8::Handle<v8::Array> ret = v8::Array::New(2);
ret->Set(0, v8::Integer::New(pos.x()));
ret->Set(1, v8::Integer::New(pos.y()));
ret->Set(0, ToV8Value(pos.x()));
ret->Set(1, ToV8Value(pos.y()));
return ret;
args.GetReturnValue().Set(ret);
}
// static
v8::Handle<v8::Value> Window::SetTitle(const v8::Arguments &args) {
void Window::SetTitle(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 1 || !args[0]->IsString())
std::string title;
if (!FromV8Arguments(args, &title))
return node::ThrowTypeError("Bad argument");
self->window_->SetTitle(*v8::String::Utf8Value(args[0]));
return v8::Undefined();
self->window_->SetTitle(title);
}
// static
v8::Handle<v8::Value> Window::GetTitle(const v8::Arguments &args) {
void Window::GetTitle(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
std::string title = self->window_->GetTitle();
return v8::String::New(title.c_str(), title.size());
args.GetReturnValue().Set(ToV8Value(self->window_->GetTitle()));
}
// static
v8::Handle<v8::Value> Window::FlashFrame(const v8::Arguments &args) {
void Window::FlashFrame(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->FlashFrame(
args[0]->IsBoolean() ? args[0]->BooleanValue(): true);
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Window::SetKiosk(const v8::Arguments &args) {
void Window::SetKiosk(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 1 || !args[0]->IsBoolean())
bool kiosk;
if (!FromV8Arguments(args, &kiosk))
return node::ThrowTypeError("Bad argument");
self->window_->SetKiosk(args[0]->BooleanValue());
return v8::Undefined();
self->window_->SetKiosk(kiosk);
}
// static
v8::Handle<v8::Value> Window::IsKiosk(const v8::Arguments &args) {
void Window::IsKiosk(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(self->window_->IsKiosk());
args.GetReturnValue().Set(self->window_->IsKiosk());
}
// static
v8::Handle<v8::Value> Window::OpenDevTools(const v8::Arguments &args) {
void Window::OpenDevTools(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->OpenDevTools();
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Window::CloseDevTools(const v8::Arguments &args) {
void Window::CloseDevTools(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->CloseDevTools();
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Window::InspectElement(const v8::Arguments& args) {
void Window::IsDevToolsOpened(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->InspectElement(args[0]->IntegerValue(),
args[1]->IntegerValue());
return v8::Undefined();
args.GetReturnValue().Set(self->window_->IsDevToolsOpened());
}
// static
v8::Handle<v8::Value> Window::FocusOnWebView(const v8::Arguments &args) {
void Window::InspectElement(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
int x, y;
if (!FromV8Arguments(args, &x, &y))
return node::ThrowTypeError("Bad argument");
self->window_->InspectElement(x, y);
}
// static
void Window::FocusOnWebView(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->FocusOnWebView();
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Window::BlurWebView(const v8::Arguments &args) {
void Window::BlurWebView(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->BlurWebView();
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Window::IsWebViewFocused(const v8::Arguments& args) {
void Window::IsWebViewFocused(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(self->window_->IsWebViewFocused());
args.GetReturnValue().Set(self->window_->IsWebViewFocused());
}
// static
v8::Handle<v8::Value> Window::RestartHangMonitorTimeout(
const v8::Arguments &args) {
void Window::CapturePage(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->RestartHangMonitorTimeout();
gfx::Rect rect;
RefCountedV8Function callback;
if (!FromV8Arguments(args, &rect, &callback) &&
!FromV8Arguments(args, &callback))
return node::ThrowTypeError("Bad argument");
return v8::Undefined();
self->window_->CapturePage(rect, base::Bind(&Window::OnCapturePageDone,
base::Unretained(self),
callback));
}
// static
v8::Handle<v8::Value> Window::GetPageTitle(const v8::Arguments &args) {
void Window::GetPageTitle(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
string16 title = self->window_->GetWebContents()->GetTitle();
return UTF16ToV8String(title);
args.GetReturnValue().Set(ToV8Value(
self->window_->GetWebContents()->GetTitle()));
}
// static
v8::Handle<v8::Value> Window::IsLoading(const v8::Arguments &args) {
void Window::IsLoading(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(self->window_->GetWebContents()->IsLoading());
args.GetReturnValue().Set(self->window_->GetWebContents()->IsLoading());
}
// static
v8::Handle<v8::Value> Window::IsWaitingForResponse(const v8::Arguments &args) {
void Window::IsWaitingForResponse(
const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(
args.GetReturnValue().Set(
self->window_->GetWebContents()->IsWaitingForResponse());
}
// static
v8::Handle<v8::Value> Window::Stop(const v8::Arguments &args) {
void Window::Stop(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->GetWebContents()->Stop();
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Window::GetRoutingID(const v8::Arguments &args) {
void Window::GetRoutingID(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
return v8::Integer::New(self->window_->GetWebContents()->GetRoutingID());
args.GetReturnValue().Set(self->window_->GetWebContents()->GetRoutingID());
}
// static
v8::Handle<v8::Value> Window::GetProcessID(const v8::Arguments &args) {
void Window::GetProcessID(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
return v8::Integer::New(
args.GetReturnValue().Set(
self->window_->GetWebContents()->GetRenderProcessHost()->GetID());
}
// static
v8::Handle<v8::Value> Window::IsCrashed(const v8::Arguments &args) {
void Window::IsCrashed(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(self->window_->GetWebContents()->IsCrashed());
args.GetReturnValue().Set(self->window_->GetWebContents()->IsCrashed());
}
// static
v8::Handle<v8::Value> Window::LoadURL(const v8::Arguments &args) {
void Window::LoadURL(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 1 || !args[0]->IsString())
GURL url;
if (!FromV8Arguments(args, &url))
return node::ThrowTypeError("Bad argument");
NavigationController& controller =
self->window_->GetWebContents()->GetController();
controller.LoadURL(GURL(*v8::String::Utf8Value(args[0])),
content::Referrer(),
content::PAGE_TRANSITION_AUTO_TOPLEVEL,
std::string());
return v8::Undefined();
content::NavigationController::LoadURLParams params(url);
params.transition_type = content::PAGE_TRANSITION_TYPED;
params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
controller.LoadURLWithParams(params);
}
// static
v8::Handle<v8::Value> Window::GetURL(const v8::Arguments &args) {
void Window::GetURL(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
NavigationController& controller =
self->window_->GetWebContents()->GetController();
std::string url;
GURL url;
if (controller.GetActiveEntry())
url = controller.GetActiveEntry()->GetVirtualURL().spec();
url = controller.GetActiveEntry()->GetVirtualURL();
return v8::String::New(url.c_str(), url.size());
args.GetReturnValue().Set(ToV8Value(url));
}
// static
v8::Handle<v8::Value> Window::CanGoBack(const v8::Arguments &args) {
void Window::CanGoBack(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
NavigationController& controller =
self->window_->GetWebContents()->GetController();
return v8::Boolean::New(controller.CanGoBack());
args.GetReturnValue().Set(controller.CanGoBack());
}
// static
v8::Handle<v8::Value> Window::CanGoForward(const v8::Arguments &args) {
void Window::CanGoForward(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
NavigationController& controller =
self->window_->GetWebContents()->GetController();
return v8::Boolean::New(controller.CanGoForward());
args.GetReturnValue().Set(controller.CanGoForward());
}
// static
v8::Handle<v8::Value> Window::CanGoToOffset(const v8::Arguments &args) {
void Window::CanGoToOffset(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 1)
int offset;
if (!FromV8Arguments(args, &offset))
return node::ThrowTypeError("Bad argument");
NavigationController& controller =
self->window_->GetWebContents()->GetController();
int offset = args[0]->IntegerValue();
return v8::Boolean::New(controller.CanGoToOffset(offset));
args.GetReturnValue().Set(controller.CanGoToOffset(offset));
}
// static
v8::Handle<v8::Value> Window::GoBack(const v8::Arguments &args) {
void Window::GoBack(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
NavigationController& controller =
self->window_->GetWebContents()->GetController();
controller.GoBack();
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Window::GoForward(const v8::Arguments &args) {
void Window::GoForward(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
NavigationController& controller =
self->window_->GetWebContents()->GetController();
controller.GoForward();
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Window::GoToIndex(const v8::Arguments &args) {
void Window::GoToIndex(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 1)
int index;
if (!FromV8Arguments(args, &index))
return node::ThrowTypeError("Bad argument");
NavigationController& controller =
self->window_->GetWebContents()->GetController();
controller.GoToIndex(args[0]->IntegerValue());
return v8::Undefined();
controller.GoToIndex(index);
}
// static
v8::Handle<v8::Value> Window::GoToOffset(const v8::Arguments &args) {
void Window::GoToOffset(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 1)
int offset;
if (!FromV8Arguments(args, &offset))
return node::ThrowTypeError("Bad argument");
NavigationController& controller =
self->window_->GetWebContents()->GetController();
controller.GoToOffset(args[0]->IntegerValue());
return v8::Undefined();
controller.GoToOffset(offset);
}
// static
v8::Handle<v8::Value> Window::Reload(const v8::Arguments &args) {
void Window::Reload(const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
NavigationController& controller =
self->window_->GetWebContents()->GetController();
controller.Reload(args[0]->IsBoolean() ? args[0]->BooleanValue(): false);
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Window::ReloadIgnoringCache(const v8::Arguments &args) {
void Window::ReloadIgnoringCache(
const v8::FunctionCallbackInfo<v8::Value>& args) {
UNWRAP_WINDOW_AND_CHECK;
NavigationController& controller =
self->window_->GetWebContents()->GetController();
controller.ReloadIgnoringCache(
args[0]->IsBoolean() ? args[0]->BooleanValue(): false);
return v8::Undefined();
}
// static
void Window::Initialize(v8::Handle<v8::Object> target) {
v8::HandleScope scope;
v8::HandleScope handle_scope(node_isolate);
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(Window::New);
t->InstanceTemplate()->SetInternalFieldCount(1);
@@ -673,6 +637,7 @@ void Window::Initialize(v8::Handle<v8::Object> target) {
NODE_SET_PROTOTYPE_METHOD(t, "isFocused", IsFocused);
NODE_SET_PROTOTYPE_METHOD(t, "show", Show);
NODE_SET_PROTOTYPE_METHOD(t, "hide", Hide);
NODE_SET_PROTOTYPE_METHOD(t, "isVisible", IsVisible);
NODE_SET_PROTOTYPE_METHOD(t, "maximize", Maximize);
NODE_SET_PROTOTYPE_METHOD(t, "unmaximize", Unmaximize);
NODE_SET_PROTOTYPE_METHOD(t, "minimize", Minimize);
@@ -699,13 +664,12 @@ void Window::Initialize(v8::Handle<v8::Object> target) {
NODE_SET_PROTOTYPE_METHOD(t, "isKiosk", IsKiosk);
NODE_SET_PROTOTYPE_METHOD(t, "openDevTools", OpenDevTools);
NODE_SET_PROTOTYPE_METHOD(t, "closeDevTools", CloseDevTools);
NODE_SET_PROTOTYPE_METHOD(t, "isDevToolsOpened", IsDevToolsOpened);
NODE_SET_PROTOTYPE_METHOD(t, "inspectElement", InspectElement);
NODE_SET_PROTOTYPE_METHOD(t, "focusOnWebView", FocusOnWebView);
NODE_SET_PROTOTYPE_METHOD(t, "blurWebView", BlurWebView);
NODE_SET_PROTOTYPE_METHOD(t, "isWebViewFocused", IsWebViewFocused);
NODE_SET_PROTOTYPE_METHOD(t,
"restartHangMonitorTimeout",
RestartHangMonitorTimeout);
NODE_SET_PROTOTYPE_METHOD(t, "capturePage", CapturePage);
NODE_SET_PROTOTYPE_METHOD(t, "getPageTitle", GetPageTitle);
NODE_SET_PROTOTYPE_METHOD(t, "isLoading", IsLoading);

View File

@@ -5,9 +5,12 @@
#ifndef ATOM_BROWSER_API_ATOM_API_WINDOW_H_
#define ATOM_BROWSER_API_ATOM_API_WINDOW_H_
#include <vector>
#include "base/memory/scoped_ptr.h"
#include "browser/api/atom_api_event_emitter.h"
#include "browser/native_window_observer.h"
#include "common/api/atom_api_event_emitter.h"
#include "common/v8/scoped_persistent.h"
namespace base {
class DictionaryValue;
@@ -41,72 +44,80 @@ class Window : public EventEmitter,
virtual void OnWindowBlur() OVERRIDE;
virtual void OnRendererUnresponsive() OVERRIDE;
virtual void OnRendererResponsive() OVERRIDE;
virtual void OnRenderViewDeleted(int process_id, int routing_id) OVERRIDE;
virtual void OnRendererCrashed() OVERRIDE;
private:
static v8::Handle<v8::Value> New(const v8::Arguments &args);
static v8::Handle<v8::Value> Destroy(const v8::Arguments &args);
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Destroy(const v8::FunctionCallbackInfo<v8::Value>& args);
// APIs for NativeWindow.
static v8::Handle<v8::Value> Close(const v8::Arguments &args);
static v8::Handle<v8::Value> Focus(const v8::Arguments &args);
static v8::Handle<v8::Value> IsFocused(const v8::Arguments &args);
static v8::Handle<v8::Value> Show(const v8::Arguments &args);
static v8::Handle<v8::Value> Hide(const v8::Arguments &args);
static v8::Handle<v8::Value> Maximize(const v8::Arguments &args);
static v8::Handle<v8::Value> Unmaximize(const v8::Arguments &args);
static v8::Handle<v8::Value> Minimize(const v8::Arguments &args);
static v8::Handle<v8::Value> Restore(const v8::Arguments &args);
static v8::Handle<v8::Value> SetFullscreen(const v8::Arguments &args);
static v8::Handle<v8::Value> IsFullscreen(const v8::Arguments &args);
static v8::Handle<v8::Value> SetSize(const v8::Arguments &args);
static v8::Handle<v8::Value> GetSize(const v8::Arguments &args);
static v8::Handle<v8::Value> SetMinimumSize(const v8::Arguments &args);
static v8::Handle<v8::Value> GetMinimumSize(const v8::Arguments &args);
static v8::Handle<v8::Value> SetMaximumSize(const v8::Arguments &args);
static v8::Handle<v8::Value> GetMaximumSize(const v8::Arguments &args);
static v8::Handle<v8::Value> SetResizable(const v8::Arguments &args);
static v8::Handle<v8::Value> IsResizable(const v8::Arguments &args);
static v8::Handle<v8::Value> SetAlwaysOnTop(const v8::Arguments &args);
static v8::Handle<v8::Value> IsAlwaysOnTop(const v8::Arguments &args);
static v8::Handle<v8::Value> Center(const v8::Arguments &args);
static v8::Handle<v8::Value> SetPosition(const v8::Arguments &args);
static v8::Handle<v8::Value> GetPosition(const v8::Arguments &args);
static v8::Handle<v8::Value> SetTitle(const v8::Arguments &args);
static v8::Handle<v8::Value> GetTitle(const v8::Arguments &args);
static v8::Handle<v8::Value> FlashFrame(const v8::Arguments &args);
static v8::Handle<v8::Value> SetKiosk(const v8::Arguments &args);
static v8::Handle<v8::Value> IsKiosk(const v8::Arguments &args);
static v8::Handle<v8::Value> OpenDevTools(const v8::Arguments &args);
static v8::Handle<v8::Value> CloseDevTools(const v8::Arguments &args);
static v8::Handle<v8::Value> InspectElement(const v8::Arguments &args);
static v8::Handle<v8::Value> FocusOnWebView(const v8::Arguments &args);
static v8::Handle<v8::Value> BlurWebView(const v8::Arguments &args);
static v8::Handle<v8::Value> IsWebViewFocused(const v8::Arguments& args);
static v8::Handle<v8::Value> RestartHangMonitorTimeout(
const v8::Arguments &args);
static void Close(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Focus(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsFocused(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Show(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Hide(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsVisible(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Maximize(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Unmaximize(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Minimize(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Restore(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetFullscreen(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsFullscreen(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetSize(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetSize(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetMinimumSize(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetMinimumSize(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetMaximumSize(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetMaximumSize(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetResizable(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsResizable(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetAlwaysOnTop(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsAlwaysOnTop(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Center(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetPosition(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetPosition(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetTitle(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetTitle(const v8::FunctionCallbackInfo<v8::Value>& args);
static void FlashFrame(const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetKiosk(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsKiosk(const v8::FunctionCallbackInfo<v8::Value>& args);
static void OpenDevTools(const v8::FunctionCallbackInfo<v8::Value>& args);
static void CloseDevTools(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsDevToolsOpened(const v8::FunctionCallbackInfo<v8::Value>& args);
static void InspectElement(const v8::FunctionCallbackInfo<v8::Value>& args);
static void FocusOnWebView(const v8::FunctionCallbackInfo<v8::Value>& args);
static void BlurWebView(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsWebViewFocused(const v8::FunctionCallbackInfo<v8::Value>& args);
static void CapturePage(const v8::FunctionCallbackInfo<v8::Value>& args);
// APIs for WebContents.
static v8::Handle<v8::Value> GetPageTitle(const v8::Arguments &args);
static v8::Handle<v8::Value> IsLoading(const v8::Arguments &args);
static v8::Handle<v8::Value> IsWaitingForResponse(const v8::Arguments &args);
static v8::Handle<v8::Value> Stop(const v8::Arguments &args);
static v8::Handle<v8::Value> GetRoutingID(const v8::Arguments &args);
static v8::Handle<v8::Value> GetProcessID(const v8::Arguments &args);
static v8::Handle<v8::Value> IsCrashed(const v8::Arguments &args);
static void GetPageTitle(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsLoading(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsWaitingForResponse(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void Stop(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetRoutingID(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetProcessID(const v8::FunctionCallbackInfo<v8::Value>& args);
static void IsCrashed(const v8::FunctionCallbackInfo<v8::Value>& args);
// APIs for NavigationController.
static v8::Handle<v8::Value> LoadURL(const v8::Arguments &args);
static v8::Handle<v8::Value> GetURL(const v8::Arguments &args);
static v8::Handle<v8::Value> CanGoBack(const v8::Arguments &args);
static v8::Handle<v8::Value> CanGoForward(const v8::Arguments &args);
static v8::Handle<v8::Value> CanGoToOffset(const v8::Arguments &args);
static v8::Handle<v8::Value> GoBack(const v8::Arguments &args);
static v8::Handle<v8::Value> GoForward(const v8::Arguments &args);
static v8::Handle<v8::Value> GoToIndex(const v8::Arguments &args);
static v8::Handle<v8::Value> GoToOffset(const v8::Arguments &args);
static v8::Handle<v8::Value> Reload(const v8::Arguments &args);
static v8::Handle<v8::Value> ReloadIgnoringCache(const v8::Arguments &args);
static void LoadURL(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetURL(const v8::FunctionCallbackInfo<v8::Value>& args);
static void CanGoBack(const v8::FunctionCallbackInfo<v8::Value>& args);
static void CanGoForward(const v8::FunctionCallbackInfo<v8::Value>& args);
static void CanGoToOffset(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GoBack(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GoForward(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GoToIndex(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GoToOffset(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Reload(const v8::FunctionCallbackInfo<v8::Value>& args);
static void ReloadIgnoringCache(
const v8::FunctionCallbackInfo<v8::Value>& args);
// Called when capturePage is done.
void OnCapturePageDone(const RefCountedV8Function& callback,
const std::vector<unsigned char>& data);
scoped_ptr<NativeWindow> window_;

View File

@@ -7,14 +7,11 @@
#include <vector>
#include "base/logging.h"
#include "base/values.h"
#include "common/v8_value_converter_impl.h"
#include "browser/api/atom_api_event.h"
#include "common/v8/native_type_conversions.h"
#include "content/public/browser/browser_thread.h"
#include "vendor/node/src/node.h"
#include "vendor/node/src/node_internals.h"
using content::V8ValueConverter;
using node::node_isolate;
#include "common/v8/node_common.h"
namespace atom {
@@ -24,72 +21,58 @@ AtomBrowserBindings::AtomBrowserBindings() {
AtomBrowserBindings::~AtomBrowserBindings() {
}
void AtomBrowserBindings::AfterLoad() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
v8::HandleScope scope;
v8::Handle<v8::Object> global = node::g_context->Global();
v8::Handle<v8::Object> atom =
global->Get(v8::String::New("__atom"))->ToObject();
DCHECK(!atom.IsEmpty());
browser_main_parts_ = v8::Persistent<v8::Object>::New(
node_isolate,
atom->Get(v8::String::New("browserMainParts"))->ToObject());
DCHECK(!browser_main_parts_.IsEmpty());
}
void AtomBrowserBindings::OnRendererMessage(int process_id,
int routing_id,
const std::string& channel,
const string16& channel,
const base::ListValue& args) {
v8::HandleScope scope;
v8::HandleScope handle_scope(node_isolate);
v8::Handle<v8::Context> context = v8::Context::GetCurrent();
scoped_ptr<V8ValueConverter> converter(new V8ValueConverterImpl());
scoped_ptr<V8ValueConverter> converter(new V8ValueConverter);
// process.emit(channel, 'message', process_id, routing_id);
std::vector<v8::Handle<v8::Value>> arguments;
arguments.reserve(3 + args.GetSize());
arguments.push_back(v8::String::New(channel.c_str(), channel.size()));
arguments.push_back(ToV8Value(channel));
const base::Value* value;
if (args.Get(0, &value))
arguments.push_back(converter->ToV8Value(value, context));
arguments.push_back(converter->ToV8Value(value, global_env->context()));
arguments.push_back(v8::Integer::New(process_id));
arguments.push_back(v8::Integer::New(routing_id));
for (size_t i = 1; i < args.GetSize(); i++) {
const base::Value* value;
if (args.Get(i, &value))
arguments.push_back(converter->ToV8Value(value, context));
arguments.push_back(converter->ToV8Value(value, global_env->context()));
}
node::MakeCallback(node::process, "emit", arguments.size(), &arguments[0]);
node::MakeCallback(global_env->process_object(),
"emit",
arguments.size(),
&arguments[0]);
}
void AtomBrowserBindings::OnRendererMessageSync(
int process_id,
int routing_id,
const std::string& channel,
const string16& channel,
const base::ListValue& args,
base::DictionaryValue* result) {
v8::HandleScope scope;
NativeWindow* sender,
IPC::Message* message) {
v8::HandleScope handle_scope(node_isolate);
v8::Handle<v8::Context> context = v8::Context::GetCurrent();
scoped_ptr<V8ValueConverter> converter(new V8ValueConverter);
scoped_ptr<V8ValueConverter> converter(new V8ValueConverterImpl());
v8::Handle<v8::Object> event = v8::Object::New();
// Create the event object.
v8::Handle<v8::Object> event = api::Event::CreateV8Object();
api::Event::Unwrap<api::Event>(event)->SetSenderAndMessage(sender, message);
// process.emit(channel, 'sync-message', event, process_id, routing_id);
std::vector<v8::Handle<v8::Value>> arguments;
arguments.reserve(3 + args.GetSize());
arguments.push_back(v8::String::New(channel.c_str(), channel.size()));
arguments.push_back(ToV8Value(channel));
const base::Value* value;
if (args.Get(0, &value))
arguments.push_back(converter->ToV8Value(value, context));
arguments.push_back(converter->ToV8Value(value, global_env->context()));
arguments.push_back(event);
arguments.push_back(v8::Integer::New(process_id));
arguments.push_back(v8::Integer::New(routing_id));
@@ -97,15 +80,13 @@ void AtomBrowserBindings::OnRendererMessageSync(
for (size_t i = 1; i < args.GetSize(); i++) {
const base::Value* value;
if (args.Get(i, &value))
arguments.push_back(converter->ToV8Value(value, context));
arguments.push_back(converter->ToV8Value(value, global_env->context()));
}
node::MakeCallback(node::process, "emit", arguments.size(), &arguments[0]);
scoped_ptr<base::Value> base_event(converter->FromV8Value(event, context));
DCHECK(base_event && base_event->IsType(base::Value::TYPE_DICTIONARY));
result->Swap(static_cast<base::DictionaryValue*>(base_event.get()));
node::MakeCallback(global_env->process_object(),
"emit",
arguments.size(),
&arguments[0]);
}
} // namespace atom

View File

@@ -5,46 +5,42 @@
#ifndef ATOM_BROWSER_API_ATOM_BROWSER_BINDINGS_
#define ATOM_BROWSER_API_ATOM_BROWSER_BINDINGS_
#include <string>
#include "base/strings/string16.h"
#include "common/api/atom_bindings.h"
#include "common/v8/scoped_persistent.h"
namespace base {
class DictionaryValue;
class ListValue;
}
namespace IPC {
class Message;
}
namespace atom {
class NativeWindow;
class AtomBrowserBindings : public AtomBindings {
public:
AtomBrowserBindings();
virtual ~AtomBrowserBindings();
// Called when the node.js main script has been loaded.
virtual void AfterLoad();
// Called when received a message from renderer.
void OnRendererMessage(int process_id,
int routing_id,
const std::string& channel,
const string16& channel,
const base::ListValue& args);
// Called when received a synchronous message from renderer.
void OnRendererMessageSync(int process_id,
int routing_id,
const std::string& channel,
const string16& channel,
const base::ListValue& args,
base::DictionaryValue* result);
// The require('atom').browserMainParts object.
v8::Handle<v8::Object> browser_main_parts() {
return browser_main_parts_;
}
NativeWindow* sender,
IPC::Message* message);
private:
v8::Persistent<v8::Object> browser_main_parts_;
DISALLOW_COPY_AND_ASSIGN(AtomBrowserBindings);
};

View File

@@ -1,6 +1,7 @@
bindings = process.atomBinding 'app'
EventEmitter = require('events').EventEmitter
bindings = process.atomBinding 'app'
Application = bindings.Application
Application::__proto__ = EventEmitter.prototype
@@ -9,16 +10,25 @@ app = new Application
app.getHomeDir = ->
process.env[if process.platform is 'win32' then 'USERPROFILE' else 'HOME']
app.setApplicationMenu = (menu) ->
require('menu').setApplicationMenu menu
app.getApplicationMenu = ->
require('menu').getApplicationMenu()
app.commandLine =
appendSwitch: bindings.appendSwitch,
appendArgument: bindings.appendArgument
if process.platform is 'darwin'
app.dock =
bounce: (type = 'informational') -> bindings.dockBounce type
bounce: (type='informational') -> bindings.dockBounce type
cancelBounce: bindings.dockCancelBounce
setBadge: bindings.dockSetBadgeText
getBadge: bindings.dockGetBadgeText
# Support old event name.
app.once 'ready', -> app.emit 'finish-launching'
# Only one App object pemitted.
module.exports = app

View File

@@ -1 +1,6 @@
module.exports = global.__atom
module.exports =
browserMainParts:
preMainMessageLoopRun: ->
setImmediate ->
module.exports.browserMainParts.preMainMessageLoopRun()

View File

@@ -1,28 +1,56 @@
EventEmitter = require('events').EventEmitter
v8Util = process.atomBinding 'v8_util'
objectsRegistry = require '../../atom/objects-registry.js'
IDWeakMap = require 'id-weak-map'
app = require 'app'
BrowserWindow = process.atomBinding('window').BrowserWindow
BrowserWindow::__proto__ = EventEmitter.prototype
# Store all created windows in the weak map.
BrowserWindow.windows = new IDWeakMap
BrowserWindow::_init = ->
# Simulate the application menu on platforms other than OS X.
if process.platform isnt 'darwin'
menu = app.getApplicationMenu()
@setMenu menu if menu?
# Remember the window.
id = BrowserWindow.windows.add this
# Remove the window from weak map immediately when it's destroyed, since we
# could be iterating windows before GC happended.
@once 'destroyed', ->
BrowserWindow.windows.remove id if BrowserWindow.windows.has id
# Tell the rpc server that a render view has been deleted and we need to
# release all objects owned by it.
@on 'render-view-deleted', (event, processId, routingId) ->
process.emit 'ATOM_BROWSER_RELEASE_RENDER_VIEW', processId, routingId
BrowserWindow::toggleDevTools = ->
opened = v8Util.getHiddenValue this, 'devtoolsOpened'
if opened
@closeDevTools()
v8Util.setHiddenValue this, 'devtoolsOpened', false
else
@openDevTools()
v8Util.setHiddenValue this, 'devtoolsOpened', true
if @isDevToolsOpened() then @closeDevTools() else @openDevTools()
BrowserWindow::restart = ->
@loadUrl(@getUrl())
BrowserWindow::setMenu = (menu) ->
throw new Error('BrowserWindow.setMenu is only available on Windows') unless process.platform is 'win32'
throw new TypeError('Invalid menu') unless menu?.constructor?.name is 'Menu'
@menu = menu # Keep a reference of menu in case of GC.
@menu.attachToWindow this
BrowserWindow.getAllWindows = ->
windows = BrowserWindow.windows
windows.get key for key in windows.keys()
BrowserWindow.getFocusedWindow = ->
windows = objectsRegistry.getAllWindows()
windows = BrowserWindow.getAllWindows()
return window for window in windows when window.isFocused()
BrowserWindow.fromProcessIdAndRoutingId = (processId, routingId) ->
windows = objectsRegistry.getAllWindows()
windows = BrowserWindow.getAllWindows()
return window for window in windows when window.getProcessId() == processId and
window.getRoutingId() == routingId

View File

@@ -1 +0,0 @@
module.exports = process.atomBinding 'crash_reporter'

View File

@@ -1,4 +1,5 @@
binding = process.atomBinding 'dialog'
v8Util = process.atomBinding 'v8_util'
BrowserWindow = require 'browser-window'
fileDialogProperties =
@@ -7,48 +8,71 @@ fileDialogProperties =
messageBoxTypes = ['none', 'info', 'warning']
module.exports =
showOpenDialog: (options) ->
options = title: 'Open', properties: ['openFile'] unless options?
options.properties = options.properties ? ['openFile']
showOpenDialog: (window, options, callback) ->
unless window?.constructor is BrowserWindow
# Shift.
callback = options
options = window
window = null
options ?= title: 'Open', properties: ['openFile']
options.properties ?= ['openFile']
throw new TypeError('Properties need to be array') unless Array.isArray options.properties
properties = 0
for prop, value of fileDialogProperties
properties |= value if prop in options.properties
options.title = options.title ? ''
options.defaultPath = options.defaultPath ? ''
options.title ?= ''
options.defaultPath ?= ''
binding.showOpenDialog options.title, options.defaultPath, properties
binding.showOpenDialog String(options.title),
String(options.defaultPath),
properties,
window,
callback
showSaveDialog: (window, options) ->
throw new TypeError('Invalid window') unless window?.constructor is BrowserWindow
options = title: 'Save' unless options?
options.title = options.title ? ''
options.defaultPath = options.defaultPath ? ''
binding.showSaveDialog window, options.title, options.defaultPath
showMessageBox: (window, options) ->
if window? and window.constructor isnt BrowserWindow
showSaveDialog: (window, options, callback) ->
unless window?.constructor is BrowserWindow
# Shift.
callback = options
options = window
window = null
options = type: 'none' unless options?
options.type = options.type ? 'none'
options ?= title: 'Save'
options.title ?= ''
options.defaultPath ?= ''
binding.showSaveDialog String(options.title),
String(options.defaultPath),
window,
callback
showMessageBox: (window, options, callback) ->
unless window?.constructor is BrowserWindow
# Shift.
callback = options
options = window
window = null
options ?= type: 'none'
options.type ?= 'none'
options.type = messageBoxTypes.indexOf options.type
throw new TypeError('Invalid message box type') unless options.type > -1
throw new TypeError('Buttons need to be array') unless Array.isArray options.buttons
options.title = options.title ? ''
options.message = options.message ? ''
options.detail = options.detail ? ''
options.title ?= ''
options.message ?= ''
options.detail ?= ''
binding.showMessageBox options.type,
options.buttons,
String(options.title),
String(options.message),
String(options.detail),
window
window,
callback
# Mark standard asynchronous functions.
v8Util.setHiddenValue f, 'asynchronous', true for k, f of module.exports

View File

@@ -8,14 +8,19 @@ sendWrap = (channel, processId, routingId, args...) ->
processId = window.getProcessId()
routingId = window.getRoutingId()
send channel, processId, routingId, args...
send channel, processId, routingId, [args...]
class Ipc extends EventEmitter
constructor: ->
process.on 'ATOM_INTERNAL_MESSAGE', (args...) =>
@emit(args...)
process.on 'ATOM_INTERNAL_MESSAGE_SYNC', (args...) =>
@emit(args...)
process.on 'ATOM_INTERNAL_MESSAGE_SYNC', (channel, event, args...) =>
set = (value) -> event.sendReply JSON.stringify(value)
Object.defineProperty event, 'returnValue', {set}
Object.defineProperty event, 'result', {set}
@emit(channel, event, args...)
send: (processId, routingId, args...) ->
@sendChannel(processId, routingId, 'message', args...)

View File

@@ -1,3 +1,5 @@
BrowserWindow = require 'browser-window'
nextCommandId = 0
class MenuItem
@@ -26,7 +28,7 @@ class MenuItem
@commandId = ++nextCommandId
@click = =>
if typeof click is 'function'
click.apply this, arguments
click this, BrowserWindow.getFocusedWindow()
else if typeof @selector is 'string'
Menu.sendActionToFirstResponder @selector

View File

@@ -1,6 +1,5 @@
BrowserWindow = require 'browser-window'
EventEmitter = require('events').EventEmitter
IDWeakMap = require 'id-weak-map'
MenuItem = require 'menu-item'
bindings = process.atomBinding 'menu'
@@ -39,13 +38,22 @@ Menu::insert = (pos, item) ->
getAcceleratorForCommandId: (commandId) => @commandsMap[commandId]?.accelerator
executeCommand: (commandId) =>
activeItem = @commandsMap[commandId]
activeItem.click(activeItem) if activeItem?
activeItem.click() if activeItem?
@items.splice pos, 0, item
@commandsMap[item.commandId] = item
applicationMenu = null
Menu.setApplicationMenu = (menu) ->
throw new TypeError('Invalid menu') unless menu?.constructor is Menu
bindings.setApplicationMenu menu
applicationMenu = menu # Keep a reference.
if process.platform is 'darwin'
bindings.setApplicationMenu menu
else
windows = BrowserWindow.getAllWindows()
w.setMenu menu for w in windows
Menu.getApplicationMenu = -> applicationMenu
Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder

View File

@@ -0,0 +1,20 @@
protocol = process.atomBinding 'protocol'
EventEmitter = require('events').EventEmitter
protocol[key] = value for key, value of EventEmitter.prototype
protocol.RequestStringJob =
class RequestStringJob
constructor: ({mimeType, charset, data}) ->
if typeof data isnt 'string' and not data instanceof Buffer
throw new TypeError('Data should be string or Buffer')
@mimeType = mimeType ? 'text/plain'
@charset = charset ? 'UTF-8'
@data = String data
protocol.RequestFileJob =
class RequestFileJob
constructor: (@path) ->
module.exports = protocol

View File

@@ -1,63 +0,0 @@
fs = require 'fs'
path = require 'path'
if process.platform is 'win32'
# Redirect node's console to use our own implementations, since node can not
# handle output when running as GUI program.
console.log = console.error = console.warn = process.log
process.stdout.write = process.stderr.write = process.log
# Always returns EOF for stdin stream.
Readable = require('stream').Readable
stdin = new Readable
stdin.push null
process.__defineGetter__ 'stdin', -> stdin
# Provide default Content API implementations.
atom = {}
atom.browserMainParts =
preMainMessageLoopRun: ->
# This is the start of the whole application, usually we should initialize
# the main window here.
# Store atom object in global scope, apps can just override methods of it to
# implement various logics.
global.__atom = atom
# Add browser/api/lib to require's search paths,
# which contains javascript part of Atom's built-in libraries.
globalPaths = require('module').globalPaths
globalPaths.push path.join process.resourcesPath, 'browser', 'api', 'lib'
# And also common/api/lib
globalPaths.push path.join process.resourcesPath, 'common', 'api', 'lib'
# Don't quit on fatal error.
process.on 'uncaughtException', (error) ->
# Show error in GUI.
message = error.stack ? "#{error.name}: #{error.message}"
require('dialog').showMessageBox
type: 'warning'
title: 'An javascript error occured in the browser'
message: 'uncaughtException'
detail: message
buttons: ['OK']
# Load the RPC server.
require './rpc-server.js'
# Now we try to load app's package.json.
packageJson = null
packagePath = path.join process.resourcesPath, 'app'
try
# First we try to load process.resourcesPath/app
packageJson = JSON.parse(fs.readFileSync(path.join(packagePath, 'package.json')))
catch error
# If not found then we load browser/default_app
packagePath = path.join process.resourcesPath, 'browser', 'default_app'
packageJson = JSON.parse(fs.readFileSync(path.join(packagePath, 'package.json')))
# Finally load app's main.js and transfer control to C++.
require path.join(packagePath, packageJson.main)

View File

@@ -1,82 +0,0 @@
BrowserWindow = require 'browser-window'
IDWeakMap = require 'id-weak-map'
v8Util = process.atomBinding 'v8_util'
class ObjectsStore
@stores = {}
constructor: ->
@nextId = 0
@objects = []
getNextId: ->
++@nextId
add: (obj) ->
id = @getNextId()
@objects[id] = obj
id
has: (id) ->
@objects[id]?
remove: (id) ->
throw new Error("Invalid key #{id} for ObjectsStore") unless @has id
delete @objects[id]
get: (id) ->
throw new Error("Invalid key #{id} for ObjectsStore") unless @has id
@objects[id]
@forRenderView: (processId, routingId) ->
key = "#{processId}_#{routingId}"
@stores[key] = new ObjectsStore unless @stores[key]?
@stores[key]
@releaseForRenderView: (processId, routingId) ->
key = "#{processId}_#{routingId}"
delete @stores[key]
# Objects in weak map will be not referenced (so we won't leak memory), and
# every object created in browser will have a unique id in weak map.
objectsWeakMap = new IDWeakMap
objectsWeakMap.add = (obj) ->
id = IDWeakMap::add.call this, obj
v8Util.setHiddenValue obj, 'atomId', id
id
windowsWeakMap = new IDWeakMap
process.on 'ATOM_BROWSER_INTERNAL_NEW', (obj) ->
# Remember all windows.
if obj.constructor is BrowserWindow
id = windowsWeakMap.add obj
obj.on 'destroyed', ->
windowsWeakMap.remove id
exports.add = (processId, routingId, obj) ->
# Some native objects may already been added to objectsWeakMap, be care not
# to add it twice.
objectsWeakMap.add obj unless v8Util.getHiddenValue obj, 'atomId'
id = v8Util.getHiddenValue obj, 'atomId'
# Store and reference the object, then return the storeId which points to
# where the object is stored. The caller can later dereference the object
# with the storeId.
store = ObjectsStore.forRenderView processId, routingId
storeId = store.add obj
[id, storeId]
exports.get = (id) ->
objectsWeakMap.get id
exports.getAllWindows = () ->
keys = windowsWeakMap.keys()
windowsWeakMap.get key for key in keys
exports.remove = (processId, routingId, storeId) ->
ObjectsStore.forRenderView(processId, routingId).remove storeId
exports.clear = (processId, routingId) ->
ObjectsStore.releaseForRenderView processId, routingId

View File

@@ -4,8 +4,10 @@
#include "browser/atom_browser_client.h"
#include "browser/atom_browser_context.h"
#include "browser/atom_browser_main_parts.h"
#include "webkit/glue/webpreferences.h"
#include "browser/net/atom_url_request_context_getter.h"
#include "webkit/common/webpreferences.h"
namespace atom {
@@ -15,6 +17,13 @@ AtomBrowserClient::AtomBrowserClient() {
AtomBrowserClient::~AtomBrowserClient() {
}
net::URLRequestContextGetter* AtomBrowserClient::CreateRequestContext(
content::BrowserContext* browser_context,
content::ProtocolHandlerMap* protocol_handlers) {
return static_cast<AtomBrowserContext*>(browser_context)->
CreateRequestContext(protocol_handlers);
}
void AtomBrowserClient::OverrideWebkitPrefs(
content::RenderViewHost* render_view_host,
const GURL& url,

View File

@@ -15,6 +15,9 @@ class AtomBrowserClient : public brightray::BrowserClient {
virtual ~AtomBrowserClient();
protected:
net::URLRequestContextGetter* CreateRequestContext(
content::BrowserContext* browser_context,
content::ProtocolHandlerMap* protocol_handlers) OVERRIDE;
virtual void OverrideWebkitPrefs(content::RenderViewHost* render_view_host,
const GURL& url,
WebPreferences* prefs) OVERRIDE;

View File

@@ -5,15 +5,73 @@
#include "browser/atom_browser_context.h"
#include "browser/atom_browser_main_parts.h"
#include "browser/net/atom_url_request_context_getter.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/resource_context.h"
#include "vendor/brightray/browser/network_delegate.h"
namespace atom {
AtomBrowserContext::AtomBrowserContext() {
using content::BrowserThread;
class AtomResourceContext : public content::ResourceContext {
public:
AtomResourceContext() : getter_(NULL) {}
void set_url_request_context_getter(AtomURLRequestContextGetter* getter) {
getter_ = getter;
}
protected:
virtual net::HostResolver* GetHostResolver() OVERRIDE {
DCHECK(getter_);
return getter_->host_resolver();
}
virtual net::URLRequestContext* GetRequestContext() OVERRIDE {
DCHECK(getter_);
return getter_->GetURLRequestContext();
}
virtual bool AllowMicAccess(const GURL& origin) OVERRIDE {
return true;
}
virtual bool AllowCameraAccess(const GURL& origin) OVERRIDE {
return true;
}
private:
AtomURLRequestContextGetter* getter_;
DISALLOW_COPY_AND_ASSIGN(AtomResourceContext);
};
AtomBrowserContext::AtomBrowserContext()
: resource_context_(new AtomResourceContext) {
}
AtomBrowserContext::~AtomBrowserContext() {
}
AtomURLRequestContextGetter* AtomBrowserContext::CreateRequestContext(
content::ProtocolHandlerMap* protocol_handlers) {
DCHECK(!url_request_getter_);
url_request_getter_ = new AtomURLRequestContextGetter(
GetPath(),
BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::IO),
BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::FILE),
CreateNetworkDelegate().Pass(),
protocol_handlers);
resource_context_->set_url_request_context_getter(url_request_getter_.get());
return url_request_getter_.get();
}
content::ResourceContext* AtomBrowserContext::GetResourceContext() {
return resource_context_.get();
}
// static
AtomBrowserContext* AtomBrowserContext::Get() {
return static_cast<AtomBrowserContext*>(

View File

@@ -10,14 +10,34 @@
namespace atom {
class AtomResourceContext;
class AtomURLRequestContextGetter;
class AtomBrowserContext : public brightray::BrowserContext {
public:
AtomBrowserContext();
virtual ~AtomBrowserContext();
// Returns the browser context singleton.
static AtomBrowserContext* Get();
// Creates or returns the request context.
AtomURLRequestContextGetter* CreateRequestContext(
content::ProtocolHandlerMap*);
AtomURLRequestContextGetter* url_request_context_getter() const {
DCHECK(url_request_getter_);
return url_request_getter_.get();
}
protected:
// content::BrowserContext implementations:
virtual content::ResourceContext* GetResourceContext() OVERRIDE;
private:
scoped_ptr<AtomResourceContext> resource_context_;
scoped_refptr<AtomURLRequestContextGetter> url_request_getter_;
DISALLOW_COPY_AND_ASSIGN(AtomBrowserContext);
};

View File

@@ -4,14 +4,18 @@
#include "browser/atom_browser_main_parts.h"
#include "base/power_monitor/power_monitor.h"
#include "browser/api/atom_browser_bindings.h"
#include "browser/atom_browser_client.h"
#include "browser/atom_browser_context.h"
#include "browser/browser.h"
#include "common/node_bindings.h"
#include "vendor/node/src/node.h"
#include "vendor/node/src/node_internals.h"
#include "net/proxy/proxy_resolver_v8.h"
#if defined(OS_WIN)
#include "ui/gfx/win/dpi.h"
#endif
#include "common/v8/node_common.h"
namespace atom {
@@ -42,39 +46,35 @@ brightray::BrowserContext* AtomBrowserMainParts::CreateBrowserContext() {
void AtomBrowserMainParts::PostEarlyInitialization() {
brightray::BrowserMainParts::PostEarlyInitialization();
#if defined(OS_MACOSX)
base::PowerMonitor::AllocateSystemIOPorts();
#endif
node_bindings_->Initialize();
v8::V8::Initialize();
// Create context.
v8::HandleScope handle_scope(node_isolate);
v8::Local<v8::Context> context = v8::Context::New(node_isolate);
// Create the global environment.
global_env = node_bindings_->CreateEnvironment(context);
// Wrap whole process in one global context.
node::g_context->Enter();
context->Enter();
atom_bindings_->BindTo(node::process);
node_bindings_->Load();
atom_bindings_->AfterLoad();
// Add atom-shell extended APIs.
atom_bindings_->BindTo(global_env->process_object());
}
void AtomBrowserMainParts::PreMainMessageLoopRun() {
node_bindings_->PrepareMessageLoop();
brightray::BrowserMainParts::PreMainMessageLoopRun();
{
v8::HandleScope scope;
v8::Context::Scope context_scope(node::g_context);
v8::Handle<v8::Value> args;
node::MakeCallback(atom_bindings_->browser_main_parts(),
"preMainMessageLoopRun",
0, &args);
}
node_bindings_->PrepareMessageLoop();
node_bindings_->RunMessageLoop();
// Make sure the url request job factory is created before the
// will-finish-launching event.
static_cast<content::BrowserContext*>(AtomBrowserContext::Get())->
GetRequestContext();
#if !defined(OS_MACOSX)
// The corresponding call in OS X is in AtomApplicationDelegate.
Browser::Get()->WillFinishLaunching();
@@ -82,4 +82,19 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
#endif
}
int AtomBrowserMainParts::PreCreateThreads() {
// Note that we are overriding the PreCreateThreads of brightray, since we
// are integrating node in browser, we can just be sure that an V8 instance
// would be prepared, while the ProxyResolverV8::CreateIsolate() would
// try to create a V8 isolate, which messed everything on Windows, so we
// have to override and call RememberDefaultIsolate on Windows instead.
net::ProxyResolverV8::RememberDefaultIsolate();
#if defined(OS_WIN)
gfx::EnableHighDPISupport();
#endif
return 0;
}
} // namespace atom

View File

@@ -30,6 +30,7 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
// Implementations of content::BrowserMainParts.
virtual void PostEarlyInitialization() OVERRIDE;
virtual void PreMainMessageLoopRun() OVERRIDE;
virtual int PreCreateThreads() OVERRIDE;
#if defined(OS_MACOSX)
virtual void PreMainMessageLoopStart() OVERRIDE;
virtual void PostDestroyThreads() OVERRIDE;

View File

@@ -4,9 +4,11 @@
#include "browser/atom_browser_main_parts.h"
#import "base/mac/bundle_locations.h"
#include "base/files/file_path.h"
#import "base/mac/foundation_util.h"
#import "browser/atom_application_mac.h"
#import "browser/atom_application_delegate_mac.h"
#import "vendor/brightray/common/mac/main_application_bundle.h"
namespace atom {
@@ -17,10 +19,14 @@ void AtomBrowserMainParts::PreMainMessageLoopStart() {
AtomApplicationDelegate* delegate = [AtomApplicationDelegate alloc];
[NSApp setDelegate:delegate];
auto infoDictionary = base::mac::OuterBundle().infoDictionary;
NSString *mainNibName = [infoDictionary objectForKey:@"NSMainNibFile"];
auto mainNib = [[NSNib alloc] initWithNibNamed:mainNibName bundle:base::mac::FrameworkBundle()];
base::FilePath frameworkPath = brightray::MainApplicationBundlePath()
.Append("Contents")
.Append("Frameworks")
.Append("Atom Framework.framework");
NSBundle* frameworkBundle = [NSBundle
bundleWithPath:base::mac::FilePathToNSString(frameworkPath)];
NSNib* mainNib = [[NSNib alloc] initWithNibNamed:@"MainMenu"
bundle:frameworkBundle];
[mainNib instantiateWithOwner:application topLevelObjects:nil];
[mainNib release];

View File

@@ -4,7 +4,7 @@
#include "browser/atom_javascript_dialog_manager.h"
#include "base/utf_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
namespace atom {
@@ -13,7 +13,8 @@ void AtomJavaScriptDialogManager::RunBeforeUnloadDialog(
const string16& message_text,
bool is_reload,
const DialogClosedCallback& callback) {
bool prevent_reload = !message_text.empty() ||
bool prevent_reload = message_text.empty() ||
message_text == ASCIIToUTF16("false");
callback.Run(!prevent_reload, message_text);
}

View File

@@ -26,7 +26,9 @@ class AtomJavaScriptDialogManager : public content::JavaScriptDialogManager {
const string16& message_text,
bool is_reload,
const DialogClosedCallback& callback) OVERRIDE;
virtual void ResetJavaScriptState(
virtual void CancelActiveAndPendingDialogs(
content::WebContents* web_contents) OVERRIDE {}
virtual void WebContentsDestroyed(
content::WebContents* web_contents) OVERRIDE {}
};

View File

@@ -33,6 +33,34 @@ void Browser::Quit() {
window_list->CloseAllWindows();
}
std::string Browser::GetVersion() const {
if (version_override_.empty()) {
std::string version = GetExecutableFileVersion();
if (!version.empty())
return version;
}
return version_override_;
}
void Browser::SetVersion(const std::string& version) {
version_override_ = version;
}
std::string Browser::GetName() const {
if (name_override_.empty()) {
std::string name = GetExecutableFileProductName();
if (!name.empty())
return name;
}
return name_override_;
}
void Browser::SetName(const std::string& name) {
name_override_ = name;
}
bool Browser::OpenFile(const std::string& file_path) {
bool prevent_default = false;
FOR_EACH_OBSERVER(BrowserObserver,

View File

@@ -31,7 +31,16 @@ class Browser : public WindowListObserver {
void Focus();
// Returns the version of the executable (or bundle).
std::string GetVersion();
std::string GetVersion() const;
// Overrides the application version.
void SetVersion(const std::string& version);
// Returns the application's name, default is just Atom-Shell.
std::string GetName() const;
// Overrides the application name.
void SetName(const std::string& name);
#if defined(OS_MACOSX)
// Bounce the dock icon.
@@ -68,6 +77,12 @@ class Browser : public WindowListObserver {
bool is_quiting() const { return is_quiting_; }
protected:
// Returns the version of application bundle or executable file.
std::string GetExecutableFileVersion() const;
// Returns the name of application bundle or executable file.
std::string GetExecutableFileProductName() const;
// Send the will-quit message and then terminate the application.
void NotifyAndTerminate();
@@ -84,6 +99,9 @@ class Browser : public WindowListObserver {
// Observers of the browser.
ObserverList<BrowserObserver> observers_;
std::string version_override_;
std::string name_override_;
DISALLOW_COPY_AND_ASSIGN(Browser);
};

View File

@@ -19,12 +19,18 @@ void Browser::Focus() {
[[AtomApplication sharedApplication] activateIgnoringOtherApps:YES];
}
std::string Browser::GetVersion() {
std::string Browser::GetExecutableFileVersion() const {
NSDictionary* infoDictionary = base::mac::OuterBundle().infoDictionary;
NSString *version = [infoDictionary objectForKey:@"CFBundleVersion"];
return base::SysNSStringToUTF8(version);
}
std::string Browser::GetExecutableFileProductName() const {
NSDictionary* infoDictionary = base::mac::OuterBundle().infoDictionary;
NSString *version = [infoDictionary objectForKey:@"CFBundleName"];
return base::SysNSStringToUTF8(version);
}
void Browser::CancelQuit() {
[[AtomApplication sharedApplication] replyToApplicationShouldTerminate:NO];
}

View File

@@ -12,6 +12,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
#include "common/atom_version.h"
namespace atom {
@@ -43,7 +44,7 @@ void Browser::Focus() {
EnumWindows(&WindowsEnumerationHandler, reinterpret_cast<LPARAM>(&pid));
}
std::string Browser::GetVersion() {
std::string Browser::GetExecutableFileVersion() const {
base::FilePath path;
if (PathService::Get(base::FILE_EXE, &path)) {
scoped_ptr<FileVersionInfo> version_info(
@@ -51,7 +52,18 @@ std::string Browser::GetVersion() {
return UTF16ToUTF8(version_info->product_version());
}
return "";
return ATOM_VERSION_STRING;
}
std::string Browser::GetExecutableFileProductName() const {
base::FilePath path;
if (PathService::Get(base::FILE_EXE, &path)) {
scoped_ptr<FileVersionInfo> version_info(
FileVersionInfo::CreateFileVersionInfo(path));
return UTF16ToUTF8(version_info->product_name());
}
return "Atom-Shell";
}
void Browser::CancelQuit() {

View File

@@ -1,26 +0,0 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_CRASH_REPORTER_H_
#define ATOM_BROWSER_CRASH_REPORTER_H_
#include <string>
#include "base/basictypes.h"
namespace crash_reporter {
class CrashReporter {
public:
static void SetCompanyName(const std::string& name);
static void SetSubmissionURL(const std::string& url);
static void SetAutoSubmit(bool yes);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(CrashReporter);
};
} // namespace crash_reporter
#endif // ATOM_BROWSER_CRASH_REPORTER_H_

View File

@@ -1,31 +0,0 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "browser/crash_reporter.h"
#import <Quincy/BWQuincyManager.h>
#include "base/strings/sys_string_conversions.h"
namespace crash_reporter {
// static
void CrashReporter::SetCompanyName(const std::string& name) {
BWQuincyManager *manager = [BWQuincyManager sharedQuincyManager];
[manager setCompanyName:base::SysUTF8ToNSString(name)];
}
// static
void CrashReporter::SetSubmissionURL(const std::string& url) {
BWQuincyManager *manager = [BWQuincyManager sharedQuincyManager];
[manager setSubmissionURL:base::SysUTF8ToNSString(url)];
}
// static
void CrashReporter::SetAutoSubmit(bool yes) {
BWQuincyManager *manager = [BWQuincyManager sharedQuincyManager];
[manager setAutoSubmitCrashReport:yes];
}
} // namespace crash_reporter

View File

@@ -1,22 +0,0 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "browser/crash_reporter.h"
namespace crash_reporter {
// static
void CrashReporter::SetCompanyName(const std::string& name) {
}
// static
void CrashReporter::SetSubmissionURL(const std::string& url) {
}
// static
void CrashReporter::SetAutoSubmit(bool yes) {
}
} // namespace crash_reporter

View File

@@ -1,6 +1,5 @@
var app = require('app');
var dialog = require('dialog');
var delegate = require('atom-delegate');
var ipc = require('ipc');
var Menu = require('menu');
var MenuItem = require('menu-item');
@@ -18,7 +17,7 @@ app.on('open-url', function(event, url) {
dialog.showMessageBox({message: url, buttons: ['OK']});
});
app.on('finish-launching', function() {
app.on('ready', function() {
app.commandLine.appendSwitch('js-flags', '--harmony_collections');
mainWindow = new BrowserWindow({ width: 800, height: 600 });
@@ -31,7 +30,6 @@ app.on('finish-launching', function() {
});
mainWindow.on('closed', function() {
console.log('closed');
mainWindow = null;
});
@@ -39,129 +37,167 @@ app.on('finish-launching', function() {
console.log('unresponsive');
});
var template = [
{
label: 'Atom Shell',
submenu: [
{
label: 'About Atom Shell',
selector: 'orderFrontStandardAboutPanel:'
},
{
type: 'separator'
},
{
label: 'Hide Atom Shell',
accelerator: 'Command+H',
selector: 'hide:'
},
{
label: 'Hide Others',
accelerator: 'Command+Shift+H',
selector: 'hideOtherApplications:'
},
{
label: 'Show All',
selector: 'unhideAllApplications:'
},
{
type: 'separator'
},
{
label: 'Quit',
accelerator: 'Command+Q',
click: function() { app.quit(); }
},
]
},
{
label: 'Edit',
submenu: [
{
label: 'Undo',
accelerator: 'Command+Z',
selector: 'undo:'
},
{
label: 'Redo',
accelerator: 'Shift+Command+Z',
selector: 'redo:'
},
{
type: 'separator'
},
{
label: 'Cut',
accelerator: 'Command+X',
selector: 'cut:'
},
{
label: 'Copy',
accelerator: 'Command+C',
selector: 'copy:'
},
{
label: 'Paste',
accelerator: 'Command+V',
selector: 'paste:'
},
{
label: 'Select All',
accelerator: 'Command+A',
selector: 'selectAll:'
},
]
},
{
label: 'View',
submenu: [
{
label: 'Reload',
accelerator: 'Command+R',
click: function() { BrowserWindow.getFocusedWindow().restart(); }
},
{
label: 'Enter Fullscreen',
click: function() { BrowserWindow.getFocusedWindow().setFullscreen(true); }
},
{
label: 'Toggle DevTools',
accelerator: 'Alt+Command+I',
click: function() { BrowserWindow.getFocusedWindow().toggleDevTools(); }
},
]
},
{
label: 'Window',
submenu: [
{
label: 'Minimize',
accelerator: 'Command+M',
selector: 'performMiniaturize:'
},
{
label: 'Close',
accelerator: 'Command+W',
selector: 'performClose:'
},
{
type: 'separator'
},
{
label: 'Bring All to Front',
selector: 'arrangeInFront:'
},
]
},
];
if (process.platform == 'darwin') {
var template = [
{
label: 'Atom Shell',
submenu: [
{
label: 'About Atom Shell',
selector: 'orderFrontStandardAboutPanel:'
},
{
type: 'separator'
},
{
label: 'Hide Atom Shell',
accelerator: 'Command+H',
selector: 'hide:'
},
{
label: 'Hide Others',
accelerator: 'Command+Shift+H',
selector: 'hideOtherApplications:'
},
{
label: 'Show All',
selector: 'unhideAllApplications:'
},
{
type: 'separator'
},
{
label: 'Quit',
accelerator: 'Command+Q',
click: function() { app.quit(); }
},
]
},
{
label: 'Edit',
submenu: [
{
label: 'Undo',
accelerator: 'Command+Z',
selector: 'undo:'
},
{
label: 'Redo',
accelerator: 'Shift+Command+Z',
selector: 'redo:'
},
{
type: 'separator'
},
{
label: 'Cut',
accelerator: 'Command+X',
selector: 'cut:'
},
{
label: 'Copy',
accelerator: 'Command+C',
selector: 'copy:'
},
{
label: 'Paste',
accelerator: 'Command+V',
selector: 'paste:'
},
{
label: 'Select All',
accelerator: 'Command+A',
selector: 'selectAll:'
},
]
},
{
label: 'View',
submenu: [
{
label: 'Reload',
accelerator: 'Command+R',
click: function() { BrowserWindow.getFocusedWindow().restart(); }
},
{
label: 'Enter Fullscreen',
click: function() { BrowserWindow.getFocusedWindow().setFullscreen(true); }
},
{
label: 'Toggle DevTools',
accelerator: 'Alt+Command+I',
click: function() { BrowserWindow.getFocusedWindow().toggleDevTools(); }
},
]
},
{
label: 'Window',
submenu: [
{
label: 'Minimize',
accelerator: 'Command+M',
selector: 'performMiniaturize:'
},
{
label: 'Close',
accelerator: 'Command+W',
selector: 'performClose:'
},
{
type: 'separator'
},
{
label: 'Bring All to Front',
selector: 'arrangeInFront:'
},
]
},
];
menu = Menu.buildFromTemplate(template);
if (process.platform == 'darwin')
menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
} else {
var template = [
{
label: 'File',
submenu: [
{
label: 'Open',
accelerator: 'Command+O',
},
{
label: 'Close',
accelerator: 'Command+W',
click: function() { mainWindow.close(); }
},
]
},
{
label: 'View',
submenu: [
{
label: 'Reload',
accelerator: 'Command+R',
click: function() { mainWindow.restart(); }
},
{
label: 'Enter Fullscreen',
click: function() { mainWindow.setFullscreen(true); }
},
{
label: 'Toggle DevTools',
accelerator: 'Alt+Command+I',
click: function() { mainWindow.toggleDevTools(); }
},
]
},
];
menu = Menu.buildFromTemplate(template);
mainWindow.setMenu(menu);
}
ipc.on('message', function(processId, routingId, type) {
console.log(type);
if (type == 'menu')
menu.popup(mainWindow);
});

View File

@@ -1,6 +1,15 @@
var argv = require('optimist').argv;
var app = require('app');
var dialog = require('dialog');
var path = require('path');
var optimist = require('optimist');
// Quit when all windows are closed and no other one is listening to this.
app.on('window-all-closed', function() {
if (app.listeners('window-all-closed').length == 1)
app.quit();
});
var argv = optimist(process.argv.slice(1)).argv;
// Start the specified app if there is one specified in command line, otherwise
// start the default app.
@@ -9,12 +18,16 @@ if (argv._.length > 0) {
require(path.resolve(argv._[0]));
} catch(e) {
if (e.code == 'MODULE_NOT_FOUND') {
console.error(e.stack);
console.error('Specified app is invalid');
process.exit(1);
} else {
throw e;
}
}
} else if (argv.version) {
console.log('v' + process.versions['atom-shell']);
process.exit(0);
} else {
require('./default_app.js');
}

View File

@@ -1,5 +1,5 @@
{
"name": "atom",
"name": "atom-shell-default-app",
"version": "0.1.0",
"main": "main.js",
"dependencies": {

72
browser/lib/init.coffee Normal file
View File

@@ -0,0 +1,72 @@
fs = require 'fs'
path = require 'path'
# Expose information of current process.
process.__atom_type = 'browser'
process.resourcesPath = path.resolve process.argv[1], '..', '..', '..'
# We modified the original process.argv to let node.js load the atom.js,
# we need to restore it here.
process.argv.splice 1, 1
# Add browser/api/lib to require's search paths,
# which contains javascript part of Atom's built-in libraries.
globalPaths = require('module').globalPaths
globalPaths.push path.join process.resourcesPath, 'browser', 'api', 'lib'
# And also common/api/lib
globalPaths.push path.join process.resourcesPath, 'common', 'api', 'lib'
# Do loading in next tick since we still need some initialize work before
# native bindings can work.
setImmediate ->
if process.platform is 'win32'
# Redirect node's console to use our own implementations, since node can not
# handle console output when running as GUI program.
console.log = console.error = console.warn = process.log
process.stdout.write = process.stderr.write = process.log
# Always returns EOF for stdin stream.
Readable = require('stream').Readable
stdin = new Readable
stdin.push null
process.__defineGetter__ 'stdin', -> stdin
# Don't quit on fatal error.
process.on 'uncaughtException', (error) ->
# Show error in GUI.
message = error.stack ? "#{error.name}: #{error.message}"
require('dialog').showMessageBox
type: 'warning'
title: 'An javascript error occured in the browser'
message: 'uncaughtException'
detail: message
buttons: ['OK']
# Load the RPC server.
require './rpc-server.js'
# Now we try to load app's package.json.
packageJson = null
packagePath = path.join process.resourcesPath, 'app'
try
# First we try to load process.resourcesPath/app
packageJson = JSON.parse(fs.readFileSync(path.join(packagePath, 'package.json')))
catch error
# If not found then we load browser/default_app
packagePath = path.join process.resourcesPath, 'browser', 'default_app'
packageJson = JSON.parse(fs.readFileSync(path.join(packagePath, 'package.json')))
# Set application's version.
app = require 'app'
app.setVersion packageJson.version if packageJson.version?
# Set application's name.
if packageJson.productName?
app.setName packageJson.productName
else if packageJson.name?
app.setName packageJson.name
# Finally load app's main.js and transfer control to C++.
require path.join(packagePath, packageJson.main)

View File

@@ -0,0 +1,84 @@
EventEmitter = require('events').EventEmitter
IDWeakMap = require 'id-weak-map'
v8Util = process.atomBinding 'v8_util'
# Class to reference all objects.
class ObjectsStore
@stores = {}
constructor: ->
@nextId = 0
@objects = []
getNextId: ->
++@nextId
add: (obj) ->
id = @getNextId()
@objects[id] = obj
id
has: (id) ->
@objects[id]?
remove: (id) ->
throw new Error("Invalid key #{id} for ObjectsStore") unless @has id
delete @objects[id]
get: (id) ->
throw new Error("Invalid key #{id} for ObjectsStore") unless @has id
@objects[id]
@forRenderView: (processId, routingId) ->
key = "#{processId}_#{routingId}"
@stores[key] = new ObjectsStore unless @stores[key]?
@stores[key]
@releaseForRenderView: (processId, routingId) ->
key = "#{processId}_#{routingId}"
delete @stores[key]
class ObjectsRegistry extends EventEmitter
constructor: ->
@setMaxListeners Number.MAX_VALUE
# Objects in weak map will be not referenced (so we won't leak memory), and
# every object created in browser will have a unique id in weak map.
@objectsWeakMap = new IDWeakMap
@objectsWeakMap.add = (obj) ->
id = IDWeakMap::add.call this, obj
v8Util.setHiddenValue obj, 'atomId', id
id
# Register a new object, the object would be kept referenced until you release
# it explicitly.
add: (processId, routingId, obj) ->
# Some native objects may already been added to objectsWeakMap, be care not
# to add it twice.
@objectsWeakMap.add obj unless v8Util.getHiddenValue obj, 'atomId'
id = v8Util.getHiddenValue obj, 'atomId'
# Store and reference the object, then return the storeId which points to
# where the object is stored. The caller can later dereference the object
# with the storeId.
# We use a difference key because the same object can be referenced for
# multiple times by the same renderer view.
store = ObjectsStore.forRenderView processId, routingId
storeId = store.add obj
[id, storeId]
# Get an object according to its id.
get: (id) ->
@objectsWeakMap.get id
# Remove an object according to its storeId.
remove: (processId, routingId, storeId) ->
ObjectsStore.forRenderView(processId, routingId).remove storeId
# Clear all references to objects from renderer view.
clear: (processId, routingId) ->
@emit "release-renderer-view-#{processId}-#{routingId}"
ObjectsStore.releaseForRenderView processId, routingId
module.exports = new ObjectsRegistry

View File

@@ -44,42 +44,63 @@ unwrapArgs = (processId, routingId, args) ->
when 'remote-object' then objectsRegistry.get meta.id
when 'array' then unwrapArgs processId, routingId, meta.value
when 'object'
ret = {}
ret = v8Util.createObjectWithName meta.name
for member in meta.members
ret[member.name] = metaToValue(member.value)
ret
when 'function-with-return-value'
returnValue = metaToValue meta.value
-> returnValue
when 'function'
rendererReleased = false
objectsRegistry.once "release-renderer-view-#{processId}-#{routingId}", ->
rendererReleased = true
ret = ->
throw new Error('Calling a callback of released renderer view') if rendererReleased
ipc.sendChannel processId, routingId, 'ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(processId, routingId, arguments)
v8Util.setDestructor ret, ->
return if rendererReleased
ipc.sendChannel processId, routingId, 'ATOM_RENDERER_RELEASE_CALLBACK', meta.id
ret
else throw new TypeError("Unknown type: #{meta.type}")
args.map metaToValue
# Call a function and send reply asynchronously if it's a an asynchronous
# style function and the caller didn't pass a callback.
callFunction = (event, processId, routingId, func, caller, args) ->
if v8Util.getHiddenValue(func, 'asynchronous') and typeof args[args.length - 1] isnt 'function'
args.push (ret) ->
event.returnValue = valueToMeta processId, routingId, ret
func.apply caller, args
else
ret = func.apply caller, args
event.returnValue = valueToMeta processId, routingId, ret
# Send by BrowserWindow when its render view is deleted.
process.on 'ATOM_BROWSER_RELEASE_RENDER_VIEW', (processId, routingId) ->
objectsRegistry.clear processId, routingId
ipc.on 'ATOM_BROWSER_REQUIRE', (event, processId, routingId, module) ->
try
event.result = valueToMeta processId, routingId, require(module)
event.returnValue = valueToMeta processId, routingId, require(module)
catch e
event.result = errorToMeta e
event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_GLOBAL', (event, processId, routingId, name) ->
try
event.result = valueToMeta processId, routingId, global[name]
event.returnValue = valueToMeta processId, routingId, global[name]
catch e
event.result = errorToMeta e
ipc.on 'ATOM_BROWSER_RELEASE_RENDER_VIEW', (event, processId, routingId) ->
objectsRegistry.clear processId, routingId
event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_CURRENT_WINDOW', (event, processId, routingId) ->
try
BrowserWindow = require 'browser-window'
window = BrowserWindow.fromProcessIdAndRoutingId processId, routingId
event.result = valueToMeta processId, routingId, window
event.returnValue = valueToMeta processId, routingId, window
catch e
event.result = errorToMeta e
event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_CONSTRUCTOR', (event, processId, routingId, id, args) ->
try
@@ -88,41 +109,50 @@ ipc.on 'ATOM_BROWSER_CONSTRUCTOR', (event, processId, routingId, id, args) ->
# Call new with array of arguments.
# http://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible
obj = new (Function::bind.apply(constructor, [null].concat(args)))
event.result = valueToMeta processId, routingId, obj
event.returnValue = valueToMeta processId, routingId, obj
catch e
event.result = errorToMeta e
event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_FUNCTION_CALL', (event, processId, routingId, id, args) ->
try
args = unwrapArgs processId, routingId, args
func = objectsRegistry.get id
ret = func.apply global, args
event.result = valueToMeta processId, routingId, ret
callFunction event, processId, routingId, func, global, args
catch e
event.result = errorToMeta e
event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, processId, routingId, id, method, args) ->
try
args = unwrapArgs processId, routingId, args
constructor = objectsRegistry.get(id)[method]
# Call new with array of arguments.
obj = new (Function::bind.apply(constructor, [null].concat(args)))
event.returnValue = valueToMeta processId, routingId, obj
catch e
event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_MEMBER_CALL', (event, processId, routingId, id, method, args) ->
try
args = unwrapArgs processId, routingId, args
obj = objectsRegistry.get id
ret = obj[method].apply(obj, args)
event.result = valueToMeta processId, routingId, ret
callFunction event, processId, routingId, obj[method], obj, args
catch e
event.result = errorToMeta e
event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_MEMBER_SET', (event, processId, routingId, id, name, value) ->
try
obj = objectsRegistry.get id
obj[name] = value
event.returnValue = null
catch e
event.result = errorToMeta e
event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_MEMBER_GET', (event, processId, routingId, id, name) ->
try
obj = objectsRegistry.get id
event.result = valueToMeta processId, routingId, obj[name]
event.returnValue = valueToMeta processId, routingId, obj[name]
catch e
event.result = errorToMeta e
event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_DEREFERENCE', (processId, routingId, storeId) ->
objectsRegistry.remove processId, routingId, storeId

View File

@@ -11,7 +11,7 @@
<key>CFBundleIconFile</key>
<string>atom.icns</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<string>0.8.3</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>

View File

@@ -6,8 +6,10 @@
#include <string>
#include "base/message_loop.h"
#include "base/utf_string_conversions.h"
#include "base/file_util.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "brightray/browser/inspectable_web_contents.h"
#include "brightray/browser/inspectable_web_contents_view.h"
@@ -15,6 +17,7 @@
#include "browser/atom_browser_context.h"
#include "browser/atom_browser_main_parts.h"
#include "browser/atom_javascript_dialog_manager.h"
#include "browser/browser.h"
#include "browser/window_list.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/invalidate_type.h"
@@ -25,12 +28,16 @@
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/common/renderer_preferences.h"
#include "common/api/api_messages.h"
#include "common/atom_version.h"
#include "common/options_switches.h"
#include "ipc/ipc_message_macros.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
#include "webkit/common/user_agent/user_agent_util.h"
using content::NavigationEntry;
@@ -39,14 +46,32 @@ namespace atom {
NativeWindow::NativeWindow(content::WebContents* web_contents,
base::DictionaryValue* options)
: content::WebContentsObserver(web_contents),
has_frame_(true),
is_closed_(false),
not_responding_(false),
weak_factory_(this),
inspectable_web_contents_(
brightray::InspectableWebContents::Create(web_contents)) {
options->GetBoolean(switches::kFrame, &has_frame_);
std::string icon;
if (options->GetString(switches::kIcon, &icon)) {
if (!SetIcon(icon))
LOG(ERROR) << "Failed to set icon to " << icon;
}
web_contents->SetDelegate(this);
WindowList::AddWindow(this);
// Override the user agent to contain application and atom-shell's version.
Browser* browser = Browser::Get();
std::string product_name = base::StringPrintf(
"%s/%s Atom-Shell/" ATOM_VERSION_STRING,
browser->GetName().c_str(),
browser->GetVersion().c_str());
web_contents->GetMutableRendererPrefs()->user_agent_override =
webkit_glue::BuildUserAgentFromProduct(product_name);
// Get notified of title updated message.
registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED,
content::Source<content::WebContents>(web_contents));
@@ -138,6 +163,10 @@ void NativeWindow::CloseDevTools() {
inspectable_web_contents()->GetView()->CloseDevTools();
}
bool NativeWindow::IsDevToolsOpened() {
return inspectable_web_contents()->IsDevToolsViewShowing();
}
void NativeWindow::InspectElement(int x, int y) {
OpenDevTools();
content::RenderViewHost* rvh = GetWebContents()->GetRenderViewHost();
@@ -158,8 +187,41 @@ bool NativeWindow::IsWebViewFocused() {
return GetWebContents()->GetRenderViewHost()->GetView()->HasFocus();
}
void NativeWindow::RestartHangMonitorTimeout() {
GetWebContents()->GetRenderViewHost()->RestartHangMonitorTimeout();
bool NativeWindow::SetIcon(const std::string& str_path) {
base::FilePath path = base::FilePath::FromUTF8Unsafe(str_path);
// Read the file from disk.
std::string file_contents;
if (path.empty() || !base::ReadFileToString(path, &file_contents))
return false;
// Decode the bitmap using WebKit's image decoder.
const unsigned char* data =
reinterpret_cast<const unsigned char*>(file_contents.data());
scoped_ptr<SkBitmap> decoded(new SkBitmap());
gfx::PNGCodec::Decode(data, file_contents.length(), decoded.get());
if (decoded->empty())
return false; // Unable to decode.
icon_ = gfx::Image::CreateFrom1xBitmap(*decoded.release());
return true;
}
base::ProcessHandle NativeWindow::GetRenderProcessHandle() {
return GetWebContents()->GetRenderProcessHost()->GetHandle();
}
void NativeWindow::CapturePage(const gfx::Rect& rect,
const CapturePageCallback& callback) {
gfx::Rect flipped_y_rect = rect;
flipped_y_rect.set_y(-rect.y());
GetWebContents()->GetRenderViewHost()->CopyFromBackingStore(
flipped_y_rect,
gfx::Size(),
base::Bind(&NativeWindow::OnCapturePageDone,
weak_factory_.GetWeakPtr(),
callback));
}
void NativeWindow::CloseWebContents() {
@@ -174,6 +236,21 @@ void NativeWindow::CloseWebContents() {
content::WebContents* web_contents(GetWebContents());
// Assume the window is not responding if it doesn't cancel the close and is
// not closed in 500ms, in this way we can quickly show the unresponsive
// dialog when the window is busy executing some script withouth waiting for
// the unresponsive timeout.
if (window_unresposive_closure_.IsCancelled()) {
window_unresposive_closure_.Reset(
base::Bind(&NativeWindow::RendererUnresponsive,
weak_factory_.GetWeakPtr(),
web_contents));
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
window_unresposive_closure_.callback(),
base::TimeDelta::FromMilliseconds(500));
}
if (web_contents->NeedToFireBeforeUnload())
web_contents->GetRenderViewHost()->FirePageBeforeUnload(false);
else
@@ -188,6 +265,14 @@ void NativeWindow::NotifyWindowClosed() {
if (is_closed_)
return;
// The OnRenderViewDeleted is not called when the WebContents is destroyed
// directly (e.g. when closing the window), so we make sure it's always
// emitted to users by sending it before window is closed..
FOR_EACH_OBSERVER(NativeWindowObserver, observers_,
OnRenderViewDeleted(
GetWebContents()->GetRenderProcessHost()->GetID(),
GetWebContents()->GetRoutingID()));
is_closed_ = true;
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowClosed());
@@ -198,24 +283,6 @@ void NativeWindow::NotifyWindowBlur() {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowBlur());
}
// Window opened by window.open.
void NativeWindow::WebContentsCreated(
content::WebContents* source_contents,
int64 source_frame_id,
const string16& frame_name,
const GURL& target_url,
content::WebContents* new_contents) {
LOG(WARNING) << "Please use node-style Window API to create window, "
"using window.open has very strict constrains.";
scoped_ptr<base::DictionaryValue> options(new base::DictionaryValue);
options->SetInteger(switches::kWidth, 800);
options->SetInteger(switches::kHeight, 600);
NativeWindow* window = Create(new_contents, options.get());
window->InitFromOptions(options.get());
}
content::JavaScriptDialogManager* NativeWindow::GetJavaScriptDialogManager() {
if (!dialog_manager_)
dialog_manager_.reset(new AtomJavaScriptDialogManager);
@@ -230,6 +297,9 @@ void NativeWindow::BeforeUnloadFired(content::WebContents* tab,
if (!proceed)
WindowList::WindowCloseCancelled(this);
// When the "beforeunload" callback is fired the window is certainly live.
window_unresposive_closure_.Cancel();
}
void NativeWindow::RequestToLockMouse(content::WebContents* web_contents,
@@ -272,6 +342,9 @@ void NativeWindow::CloseContents(content::WebContents* source) {
CloseImmediately();
NotifyWindowClosed();
// Do not sent "unresponsive" event after window is closed.
window_unresposive_closure_.Cancel();
}
bool NativeWindow::IsPopupOrPanel(const content::WebContents* source) const {
@@ -280,41 +353,48 @@ bool NativeWindow::IsPopupOrPanel(const content::WebContents* source) const {
}
void NativeWindow::RendererUnresponsive(content::WebContents* source) {
not_responding_ = true;
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&NativeWindow::RendererUnresponsiveDelayed,
base::Unretained(this)),
base::TimeDelta::FromSeconds(1));
window_unresposive_closure_.Cancel();
if (!HasModalDialog())
FOR_EACH_OBSERVER(NativeWindowObserver,
observers_,
OnRendererUnresponsive());
}
void NativeWindow::RendererResponsive(content::WebContents* source) {
not_responding_ = false;
window_unresposive_closure_.Cancel();
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnRendererResponsive());
}
void NativeWindow::RenderViewDeleted(content::RenderViewHost* rvh) {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_,
OnRenderViewDeleted(rvh->GetProcess()->GetID(),
rvh->GetRoutingID()));
}
void NativeWindow::RenderProcessGone(base::TerminationStatus status) {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnRendererCrashed());
}
void NativeWindow::BeforeUnloadFired(const base::TimeTicks& proceed_time) {
// Do nothing, we override this method just to avoid compilation error since
// there are two virtual functions named BeforeUnloadFired.
}
bool NativeWindow::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(NativeWindow, message)
IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage)
IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message_Sync, OnRendererMessageSync)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync,
OnRendererMessageSync)
IPC_MESSAGE_HANDLER(AtomViewHostMsg_UpdateDraggableRegions,
UpdateDraggableRegions)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void NativeWindow::RenderViewGone(base::TerminationStatus status) {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnRendererCrashed());
}
void NativeWindow::RendererUnresponsiveDelayed() {
if (not_responding_)
FOR_EACH_OBSERVER(NativeWindowObserver,
observers_,
OnRendererUnresponsive());
}
void NativeWindow::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
@@ -335,7 +415,16 @@ void NativeWindow::Observe(int type,
}
}
void NativeWindow::OnRendererMessage(const std::string& channel,
void NativeWindow::OnCapturePageDone(const CapturePageCallback& callback,
bool succeed,
const SkBitmap& bitmap) {
std::vector<unsigned char> data;
if (succeed)
gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, true, &data);
callback.Run(data);
}
void NativeWindow::OnRendererMessage(const string16& channel,
const base::ListValue& args) {
AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessage(
GetWebContents()->GetRenderProcessHost()->GetID(),
@@ -344,15 +433,16 @@ void NativeWindow::OnRendererMessage(const std::string& channel,
args);
}
void NativeWindow::OnRendererMessageSync(const std::string& channel,
void NativeWindow::OnRendererMessageSync(const string16& channel,
const base::ListValue& args,
base::DictionaryValue* result) {
IPC::Message* reply_msg) {
AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessageSync(
GetWebContents()->GetRenderProcessHost()->GetID(),
GetWebContents()->GetRoutingID(),
channel,
args,
result);
this,
reply_msg);
}
} // namespace atom

View File

@@ -6,13 +6,16 @@
#define ATOM_BROWSER_NATIVE_WINDOW_H_
#include "base/basictypes.h"
#include "base/cancelable_callback.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "browser/native_window_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/web_contents_observer.h"
#include "ui/gfx/image/image.h"
#include "vendor/brightray/browser/default_web_contents_delegate.h"
namespace base {
@@ -35,14 +38,22 @@ class Rect;
class Size;
}
namespace IPC {
class Message;
}
namespace atom {
class AtomJavaScriptDialogManager;
struct DraggableRegion;
class NativeWindow : public brightray::DefaultWebContentsDelegate,
public content::WebContentsObserver,
public content::NotificationObserver {
public:
typedef base::Callback<void(const std::vector<unsigned char>& buffer)>
CapturePageCallback;
virtual ~NativeWindow();
// Create window with existing WebContents.
@@ -64,6 +75,7 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
virtual bool IsFocused() = 0;
virtual void Show() = 0;
virtual void Hide() = 0;
virtual bool IsVisible() = 0;
virtual void Maximize() = 0;
virtual void Unmaximize() = 0;
virtual void Minimize() = 0;
@@ -88,16 +100,29 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
virtual void FlashFrame(bool flash) = 0;
virtual void SetKiosk(bool kiosk) = 0;
virtual bool IsKiosk() = 0;
virtual bool HasModalDialog() = 0;
virtual gfx::NativeWindow GetNativeWindow() = 0;
virtual bool IsClosed() const { return is_closed_; }
virtual void OpenDevTools();
virtual void CloseDevTools();
virtual bool IsDevToolsOpened();
virtual void InspectElement(int x, int y);
virtual void FocusOnWebView();
virtual void BlurWebView();
virtual bool IsWebViewFocused();
virtual void RestartHangMonitorTimeout();
virtual bool SetIcon(const std::string& path);
// Returns the process handle of render process, useful for killing the
// render process manually
virtual base::ProcessHandle GetRenderProcessHandle();
// Captures the page with |rect|, |callback| would be called when capturing is
// done.
virtual void CapturePage(const gfx::Rect& rect,
const CapturePageCallback& callback);
// The same with closing a tab in a real browser.
//
@@ -114,6 +139,8 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
observers_.RemoveObserver(obs);
}
bool has_frame() const { return has_frame_; }
protected:
explicit NativeWindow(content::WebContents* web_contents,
base::DictionaryValue* options);
@@ -125,12 +152,11 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
void NotifyWindowClosed();
void NotifyWindowBlur();
// Called when the window needs to update its draggable region.
virtual void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) = 0;
// Implementations of content::WebContentsDelegate.
virtual void WebContentsCreated(content::WebContents* source_contents,
int64 source_frame_id,
const string16& frame_name,
const GURL& target_url,
content::WebContents* new_contents) OVERRIDE;
virtual content::JavaScriptDialogManager*
GetJavaScriptDialogManager() OVERRIDE;
virtual void BeforeUnloadFired(content::WebContents* tab,
@@ -152,7 +178,9 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
virtual void RendererResponsive(content::WebContents* source) OVERRIDE;
// Implementations of content::WebContentsObserver.
virtual void RenderViewGone(base::TerminationStatus status) OVERRIDE;
virtual void RenderViewDeleted(content::RenderViewHost*) OVERRIDE;
virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE;
virtual void BeforeUnloadFired(const base::TimeTicks& proceed_time) OVERRIDE;
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
// Implementations of content::NotificationObserver
@@ -160,15 +188,24 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE;
private:
void RendererUnresponsiveDelayed();
// Whether window has standard frame.
bool has_frame_;
void OnRendererMessage(const std::string& channel,
// Window icon.
gfx::Image icon_;
private:
// Called when CapturePage has done.
void OnCapturePageDone(const CapturePageCallback& callback,
bool succeed,
const SkBitmap& bitmap);
void OnRendererMessage(const string16& channel,
const base::ListValue& args);
void OnRendererMessageSync(const std::string& channel,
void OnRendererMessageSync(const string16& channel,
const base::ListValue& args,
base::DictionaryValue* result);
IPC::Message* reply_msg);
// Notification manager.
content::NotificationRegistrar registrar_;
@@ -179,8 +216,11 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
// The windows has been closed.
bool is_closed_;
// The window is not responding.
bool not_responding_;
// Closure that would be called when window is unresponsive when closing,
// it should be cancelled when we can prove that the window is responsive.
base::CancelableClosure window_unresposive_closure_;
base::WeakPtrFactory<NativeWindow> weak_factory_;
scoped_ptr<AtomJavaScriptDialogManager> dialog_manager_;
scoped_ptr<brightray::InspectableWebContents> inspectable_web_contents_;

View File

@@ -10,6 +10,8 @@
#include "base/memory/scoped_ptr.h"
#include "browser/native_window.h"
class SkRegion;
namespace atom {
class NativeWindowMac : public NativeWindow {
@@ -26,6 +28,7 @@ class NativeWindowMac : public NativeWindow {
virtual bool IsFocused() OVERRIDE;
virtual void Show() OVERRIDE;
virtual void Hide() OVERRIDE;
virtual bool IsVisible() OVERRIDE;
virtual void Maximize() OVERRIDE;
virtual void Unmaximize() OVERRIDE;
virtual void Minimize() OVERRIDE;
@@ -50,13 +53,28 @@ class NativeWindowMac : public NativeWindow {
virtual void FlashFrame(bool flash) OVERRIDE;
virtual void SetKiosk(bool kiosk) OVERRIDE;
virtual bool IsKiosk() OVERRIDE;
virtual bool HasModalDialog() OVERRIDE;
virtual gfx::NativeWindow GetNativeWindow() OVERRIDE;
NSWindow*& window() { return window_; }
void NotifyWindowBlur() { NativeWindow::NotifyWindowBlur(); }
// Returns true if |point| in local Cocoa coordinate system falls within
// the draggable region.
bool IsWithinDraggableRegion(NSPoint point) const;
// Called to handle a mouse event.
void HandleMouseEvent(NSEvent* event);
// Clip web view to rounded corner.
void ClipWebView();
NSWindow*& window() { return window_; }
SkRegion* draggable_region() const { return draggable_region_.get(); }
protected:
virtual void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) OVERRIDE;
// Implementations of content::WebContentsDelegate.
virtual void HandleKeyboardEvent(
content::WebContents*,
@@ -65,6 +83,9 @@ class NativeWindowMac : public NativeWindow {
private:
void InstallView();
void UninstallView();
void InstallDraggableRegionViews();
void UpdateDraggableRegionsForCustomDrag(
const std::vector<DraggableRegion>& regions);
NSWindow* window_;
@@ -72,6 +93,18 @@ class NativeWindowMac : public NativeWindow {
NSInteger attention_request_id_; // identifier from requestUserAttention
// For system drag, the whole window is draggable and the non-draggable areas
// have to been explicitly excluded.
std::vector<gfx::Rect> system_drag_exclude_areas_;
// For custom drag, the whole window is non-draggable and the draggable region
// has to been explicitly provided.
scoped_ptr<SkRegion> draggable_region_; // used in custom drag.
// Mouse location since the last mouse event, in screen coordinates. This is
// used in custom drag to compute the window movement.
NSPoint last_mouse_offset_;
DISALLOW_COPY_AND_ASSIGN(NativeWindowMac);
};

View File

@@ -11,17 +11,25 @@
#define BASE_MAC_FOUNDATION_UTIL_H_
#include "base/mac/mac_util.h"
#include "base/mac/scoped_nsobject.h"
#include "base/strings/sys_string_conversions.h"
#include "base/values.h"
#import "browser/atom_event_processing_window.h"
#import "browser/ui/atom_event_processing_window.h"
#include "brightray/browser/inspectable_web_contents.h"
#include "brightray/browser/inspectable_web_contents_view.h"
#include "common/draggable_region.h"
#include "common/options_switches.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
#include "content/public/browser/render_view_host.h"
static const CGFloat kAtomWindowCornerRadius = 4.0;
@interface NSView (PrivateMethods)
- (CGFloat)roundedCornerRadius;
@end
@interface AtomNSWindowDelegate : NSObject<NSWindowDelegate> {
@private
atom::NativeWindowMac* shell_;
@@ -41,6 +49,11 @@
shell_->NotifyWindowBlur();
}
- (void)windowDidResize:(NSNotification*)otification {
if (!shell_->has_frame())
shell_->ClipWebView();
}
- (void)windowWillClose:(NSNotification*)notification {
shell_->window() = nil;
[self autorelease];
@@ -54,10 +67,17 @@
return NO;
}
- (void)windowDidExitFullScreen:(NSNotification*)notification {
if (!shell_->has_frame()) {
NSWindow* window = shell_->GetNativeWindow();
[[window standardWindowButton:NSWindowFullScreenButton] setHidden:YES];
}
}
@end
@interface AtomNSWindow : AtomEventProcessingWindow {
@private
@protected
atom::NativeWindowMac* shell_;
}
- (void)setShell:(atom::NativeWindowMac*)shell;
@@ -80,6 +100,41 @@
@end
@interface ControlRegionView : NSView {
@private
atom::NativeWindowMac* shellWindow_; // Weak; owns self.
}
@end
@implementation ControlRegionView
- (id)initWithShellWindow:(atom::NativeWindowMac*)shellWindow {
if ((self = [super init]))
shellWindow_ = shellWindow;
return self;
}
- (BOOL)mouseDownCanMoveWindow {
return NO;
}
- (NSView*)hitTest:(NSPoint)aPoint {
if (!shellWindow_->IsWithinDraggableRegion(aPoint)) {
return nil;
}
return self;
}
- (void)mouseDown:(NSEvent*)event {
shellWindow_->HandleMouseEvent(event);
}
- (void)mouseDragged:(NSEvent*)event {
shellWindow_->HandleMouseEvent(event);
}
@end
namespace atom {
NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
@@ -87,27 +142,30 @@ NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
: NativeWindow(web_contents, options),
is_kiosk_(false),
attention_request_id_(0) {
int width, height;
int width = 800, height = 600;
options->GetInteger(switches::kWidth, &width);
options->GetInteger(switches::kHeight, &height);
NSRect main_screen_rect = [[[NSScreen screens] objectAtIndex:0] frame];
NSRect cocoa_bounds = NSMakeRect(
(NSWidth(main_screen_rect) - width) / 2,
(NSHeight(main_screen_rect) - height) / 2,
round((NSWidth(main_screen_rect) - width) / 2) ,
round((NSHeight(main_screen_rect) - height) / 2),
width,
height);
NSUInteger style_mask = NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSResizableWindowMask |
NSTexturedBackgroundWindowMask;
AtomNSWindow* atom_window = [[AtomNSWindow alloc]
AtomNSWindow* atomWindow;
atomWindow = [[AtomNSWindow alloc]
initWithContentRect:cocoa_bounds
styleMask:style_mask
styleMask:NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSResizableWindowMask |
NSTexturedBackgroundWindowMask
backing:NSBackingStoreBuffered
defer:YES];
[atom_window setShell:this];
window_ = atom_window;
[atomWindow setShell:this];
window_ = atomWindow;
[window() setDelegate:[[AtomNSWindowDelegate alloc] initWithShell:this]];
// Disable fullscreen button when 'fullscreen' is specified to false.
@@ -119,6 +177,9 @@ NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
[window() setCollectionBehavior:collectionBehavior];
}
NSView* view = inspectable_web_contents()->GetView()->GetNativeView();
[view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
InstallView();
}
@@ -149,7 +210,10 @@ void NativeWindowMac::Move(const gfx::Rect& pos) {
}
void NativeWindowMac::Focus(bool focus) {
if (focus && [window() isVisible]) {
if (!IsVisible())
return;
if (focus) {
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
[window() makeKeyAndOrderFront:nil];
} else {
@@ -169,6 +233,10 @@ void NativeWindowMac::Hide() {
[window() orderOut:nil];
}
bool NativeWindowMac::IsVisible() {
return [window() isVisible];
}
void NativeWindowMac::Maximize() {
[window() zoom:nil];
}
@@ -300,7 +368,7 @@ void NativeWindowMac::SetKiosk(bool kiosk) {
if (kiosk) {
NSApplicationPresentationOptions options =
NSApplicationPresentationHideDock +
NSApplicationPresentationHideMenuBar +
NSApplicationPresentationHideMenuBar +
NSApplicationPresentationDisableAppleMenu +
NSApplicationPresentationDisableProcessSwitching +
NSApplicationPresentationDisableForceQuit +
@@ -320,10 +388,51 @@ bool NativeWindowMac::IsKiosk() {
return is_kiosk_;
}
bool NativeWindowMac::HasModalDialog() {
return [window() attachedSheet] != nil;
}
gfx::NativeWindow NativeWindowMac::GetNativeWindow() {
return window();
}
bool NativeWindowMac::IsWithinDraggableRegion(NSPoint point) const {
if (!draggable_region_)
return false;
NSView* webView = GetWebContents()->GetView()->GetNativeView();
NSInteger webViewHeight = NSHeight([webView bounds]);
// |draggable_region_| is stored in local platform-indepdent coordiate system
// while |point| is in local Cocoa coordinate system. Do the conversion
// to match these two.
return draggable_region_->contains(point.x, webViewHeight - point.y);
}
void NativeWindowMac::HandleMouseEvent(NSEvent* event) {
NSPoint current_mouse_location =
[window() convertBaseToScreen:[event locationInWindow]];
if ([event type] == NSLeftMouseDown) {
NSPoint frame_origin = [window() frame].origin;
last_mouse_offset_ = NSMakePoint(
frame_origin.x - current_mouse_location.x,
frame_origin.y - current_mouse_location.y);
} else if ([event type] == NSLeftMouseDragged) {
[window() setFrameOrigin:NSMakePoint(
current_mouse_location.x + last_mouse_offset_.x,
current_mouse_location.y + last_mouse_offset_.y)];
}
}
void NativeWindowMac::UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) {
// Draggable region is not supported for non-frameless window.
if (has_frame_)
return;
UpdateDraggableRegionsForCustomDrag(regions);
InstallDraggableRegionViews();
}
void NativeWindowMac::HandleKeyboardEvent(
content::WebContents*,
const content::NativeWebKeyboardEvent& event) {
@@ -339,16 +448,97 @@ void NativeWindowMac::HandleKeyboardEvent(
void NativeWindowMac::InstallView() {
NSView* view = inspectable_web_contents()->GetView()->GetNativeView();
[view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[view setFrame:[[window() contentView] bounds]];
[[window() contentView] addSubview:view];
if (has_frame_) {
[view setFrame:[[window() contentView] bounds]];
[[window() contentView] addSubview:view];
} else {
NSView* frameView = [[window() contentView] superview];
[view setFrame:[frameView bounds]];
[frameView addSubview:view];
ClipWebView();
[[window() standardWindowButton:NSWindowZoomButton] setHidden:YES];
[[window() standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
[[window() standardWindowButton:NSWindowCloseButton] setHidden:YES];
[[window() standardWindowButton:NSWindowFullScreenButton] setHidden:YES];
}
}
void NativeWindowMac::UninstallView() {
NSView* view = GetWebContents()->GetView()->GetNativeView();
NSView* view = inspectable_web_contents()->GetView()->GetNativeView();
[view removeFromSuperview];
}
void NativeWindowMac::ClipWebView() {
NSView* view = GetWebContents()->GetView()->GetNativeView();
view.wantsLayer = YES;
view.layer.masksToBounds = YES;
view.layer.cornerRadius = kAtomWindowCornerRadius;
}
void NativeWindowMac::InstallDraggableRegionViews() {
DCHECK(!has_frame_);
// All ControlRegionViews should be added as children of the WebContentsView,
// because WebContentsView will be removed and re-added when entering and
// leaving fullscreen mode.
NSView* webView = GetWebContents()->GetView()->GetNativeView();
NSInteger webViewHeight = NSHeight([webView bounds]);
// Remove all ControlRegionViews that are added last time.
// Note that [webView subviews] returns the view's mutable internal array and
// it should be copied to avoid mutating the original array while enumerating
// it.
base::scoped_nsobject<NSArray> subviews([[webView subviews] copy]);
for (NSView* subview in subviews.get())
if ([subview isKindOfClass:[ControlRegionView class]])
[subview removeFromSuperview];
// Create and add ControlRegionView for each region that needs to be excluded
// from the dragging.
for (std::vector<gfx::Rect>::const_iterator iter =
system_drag_exclude_areas_.begin();
iter != system_drag_exclude_areas_.end();
++iter) {
base::scoped_nsobject<NSView> controlRegion(
[[ControlRegionView alloc] initWithShellWindow:this]);
[controlRegion setFrame:NSMakeRect(iter->x(),
webViewHeight - iter->bottom(),
iter->width(),
iter->height())];
[webView addSubview:controlRegion];
}
}
void NativeWindowMac::UpdateDraggableRegionsForCustomDrag(
const std::vector<DraggableRegion>& regions) {
// We still need one ControlRegionView to cover the whole window such that
// mouse events could be captured.
NSView* web_view = GetWebContents()->GetView()->GetNativeView();
gfx::Rect window_bounds(
0, 0, NSWidth([web_view bounds]), NSHeight([web_view bounds]));
system_drag_exclude_areas_.clear();
system_drag_exclude_areas_.push_back(window_bounds);
// Aggregate the draggable areas and non-draggable areas such that hit test
// could be performed easily.
SkRegion* draggable_region = new SkRegion;
for (std::vector<DraggableRegion>::const_iterator iter = regions.begin();
iter != regions.end();
++iter) {
const DraggableRegion& region = *iter;
draggable_region->op(
region.bounds.x(),
region.bounds.y(),
region.bounds.right(),
region.bounds.bottom(),
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
}
draggable_region_.reset(draggable_region);
}
// static
NativeWindow* NativeWindow::Create(content::WebContents* web_contents,
base::DictionaryValue* options) {

View File

@@ -35,6 +35,9 @@ class NativeWindowObserver {
// Called when renderer recovers.
virtual void OnRendererResponsive() {}
// Called when a render view has been deleted.
virtual void OnRenderViewDeleted(int process_id, int routing_id) {}
// Called when renderer has crashed.
virtual void OnRendererCrashed() {}
};

View File

@@ -4,12 +4,24 @@
#include "browser/native_window_win.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "browser/api/atom_api_menu.h"
#include "browser/ui/win/menu_2.h"
#include "browser/ui/win/native_menu_win.h"
#include "common/draggable_region.h"
#include "common/options_switches.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
#include "ui/gfx/path.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/native_widget_win.h"
#include "ui/views/window/client_view.h"
#include "ui/views/window/native_frame_view.h"
@@ -17,24 +29,52 @@ namespace atom {
namespace {
const int kResizeInsideBoundsSize = 5;
const int kResizeAreaCornerSize = 16;
// Wrapper of NativeWidgetWin to handle WM_MENUCOMMAND messages, which are
// triggered by window menus.
class MenuCommandNativeWidget : public views::NativeWidgetWin {
public:
explicit MenuCommandNativeWidget(NativeWindowWin* delegate)
: views::NativeWidgetWin(delegate->window()),
delegate_(delegate) {}
virtual ~MenuCommandNativeWidget() {}
protected:
virtual bool PreHandleMSG(UINT message,
WPARAM w_param,
LPARAM l_param,
LRESULT* result) OVERRIDE {
if (message == WM_MENUCOMMAND) {
delegate_->OnMenuCommand(w_param, reinterpret_cast<HMENU>(l_param));
*result = 0;
return true;
} else {
return false;
}
}
private:
NativeWindowWin* delegate_;
DISALLOW_COPY_AND_ASSIGN(MenuCommandNativeWidget);
};
class NativeWindowClientView : public views::ClientView {
public:
NativeWindowClientView(views::Widget* widget,
views::View* contents_view,
NativeWindowWin* shell)
: views::ClientView(widget, contents_view),
shell_(shell) {
NativeWindowWin* contents_view)
: views::ClientView(widget, contents_view) {
}
virtual ~NativeWindowClientView() {}
virtual bool CanClose() OVERRIDE {
shell_->CloseWebContents();
static_cast<NativeWindowWin*>(contents_view())->CloseWebContents();
return false;
}
private:
NativeWindowWin* shell_;
DISALLOW_COPY_AND_ASSIGN(NativeWindowClientView);
};
@@ -60,6 +100,110 @@ class NativeWindowFrameView : public views::NativeFrameView {
DISALLOW_COPY_AND_ASSIGN(NativeWindowFrameView);
};
class NativeWindowFramelessView : public views::NonClientFrameView {
public:
explicit NativeWindowFramelessView(views::Widget* frame,
NativeWindowWin* shell)
: frame_(frame),
shell_(shell) {
}
virtual ~NativeWindowFramelessView() {}
// views::NonClientFrameView implementations:
virtual gfx::Rect NativeWindowFramelessView::GetBoundsForClientView() const
OVERRIDE {
return bounds();
}
virtual gfx::Rect NativeWindowFramelessView::GetWindowBoundsForClientBounds(
const gfx::Rect& client_bounds) const OVERRIDE {
gfx::Rect window_bounds = client_bounds;
// Enforce minimum size (1, 1) in case that client_bounds is passed with
// empty size. This could occur when the frameless window is being
// initialized.
if (window_bounds.IsEmpty()) {
window_bounds.set_width(1);
window_bounds.set_height(1);
}
return window_bounds;
}
virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE {
if (frame_->IsFullscreen())
return HTCLIENT;
// Check the frame first, as we allow a small area overlapping the contents
// to be used for resize handles.
bool can_ever_resize = frame_->widget_delegate() ?
frame_->widget_delegate()->CanResize() :
false;
// Don't allow overlapping resize handles when the window is maximized or
// fullscreen, as it can't be resized in those states.
int resize_border =
frame_->IsMaximized() || frame_->IsFullscreen() ? 0 :
kResizeInsideBoundsSize;
int frame_component = GetHTComponentForFrame(point,
resize_border,
resize_border,
kResizeAreaCornerSize,
kResizeAreaCornerSize,
can_ever_resize);
if (frame_component != HTNOWHERE)
return frame_component;
// Check for possible draggable region in the client area for the frameless
// window.
if (shell_->draggable_region() &&
shell_->draggable_region()->contains(point.x(), point.y()))
return HTCAPTION;
int client_component = frame_->client_view()->NonClientHitTest(point);
if (client_component != HTNOWHERE)
return client_component;
// Caption is a safe default.
return HTCAPTION;
}
virtual void GetWindowMask(const gfx::Size& size,
gfx::Path* window_mask) OVERRIDE {}
virtual void ResetWindowControls() OVERRIDE {}
virtual void UpdateWindowIcon() OVERRIDE {}
virtual void UpdateWindowTitle() OVERRIDE {}
// views::View implementations:
virtual gfx::Size NativeWindowFramelessView::GetPreferredSize() OVERRIDE {
gfx::Size pref = frame_->client_view()->GetPreferredSize();
gfx::Rect bounds(0, 0, pref.width(), pref.height());
return frame_->non_client_view()->GetWindowBoundsForClientBounds(
bounds).size();
}
virtual gfx::Size GetMinimumSize() OVERRIDE {
return shell_->GetMinimumSize();
}
virtual gfx::Size GetMaximumSize() OVERRIDE {
return shell_->GetMaximumSize();
}
private:
views::Widget* frame_;
NativeWindowWin* shell_;
DISALLOW_COPY_AND_ASSIGN(NativeWindowFramelessView);
};
bool WindowHasModalDialog(HWND parent, HWND except, HWND after = NULL) {
HWND hwnd = ::FindWindowEx(parent, after, NULL, NULL);
if (hwnd != except &&
(::GetWindowLong(hwnd, GWL_STYLE) & (WS_VISIBLE | WS_POPUP)))
return true;
else if (hwnd == NULL)
return false;
else
return WindowHasModalDialog(parent, except, hwnd);
}
} // namespace
@@ -71,6 +215,8 @@ NativeWindowWin::NativeWindowWin(content::WebContents* web_contents,
resizable_(true) {
views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
params.delegate = this;
params.native_widget = new MenuCommandNativeWidget(this);
params.remove_standard_frame = !has_frame_;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
window_->set_frame_type(views::Widget::FRAME_TYPE_FORCE_NATIVE);
window_->Init(params);
@@ -82,7 +228,10 @@ NativeWindowWin::NativeWindowWin(content::WebContents* web_contents,
gfx::Size size(width, height);
window_->CenterWindow(size);
window_->UpdateWindowIcon();
web_view_->SetWebContents(web_contents);
OnViewWasResized();
}
NativeWindowWin::~NativeWindowWin() {
@@ -127,6 +276,10 @@ void NativeWindowWin::Unmaximize() {
window_->Restore();
}
bool NativeWindowWin::IsVisible() {
return window_->IsVisible();
}
void NativeWindowWin::Minimize() {
window_->Minimize();
}
@@ -217,19 +370,100 @@ bool NativeWindowWin::IsKiosk() {
return IsFullscreen();
}
bool NativeWindowWin::HasModalDialog() {
return WindowHasModalDialog(GetNativeWindow(),
GetWebContents()->GetView()->GetNativeView());
}
gfx::NativeWindow NativeWindowWin::GetNativeWindow() {
return window_->GetNativeView();
}
void NativeWindowWin::OnMenuCommand(int position, HMENU menu) {
DCHECK(menu_);
menu_->wrapper()->OnMenuCommand(position, menu);
}
void NativeWindowWin::SetMenu(ui::MenuModel* menu_model) {
menu_.reset(new atom::Menu2(menu_model, true));
::SetMenu(GetNativeWindow(), menu_->GetNativeMenu());
RegisterAccelerators();
}
void NativeWindowWin::UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) {
if (has_frame_)
return;
SkRegion* draggable_region = new SkRegion;
// By default, the whole window is non-draggable. We need to explicitly
// include those draggable regions.
for (std::vector<DraggableRegion>::const_iterator iter = regions.begin();
iter != regions.end(); ++iter) {
const DraggableRegion& region = *iter;
draggable_region->op(
region.bounds.x(),
region.bounds.y(),
region.bounds.right(),
region.bounds.bottom(),
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
}
draggable_region_.reset(draggable_region);
OnViewWasResized();
}
void NativeWindowWin::HandleKeyboardEvent(
content::WebContents*,
const content::NativeWebKeyboardEvent& event) {
if (event.type == WebKit::WebInputEvent::KeyUp) {
ui::Accelerator accelerator(
static_cast<ui::KeyboardCode>(event.windowsKeyCode),
content::GetModifiersFromNativeWebKeyboardEvent(event));
if (GetFocusManager()->ProcessAccelerator(accelerator)) {
return;
}
}
// Any unhandled keyboard/character messages should be defproced.
// This allows stuff like F10, etc to work correctly.
DefWindowProc(event.os_event.hwnd, event.os_event.message,
event.os_event.wParam, event.os_event.lParam);
}
void NativeWindowWin::Layout() {
DCHECK(web_view_);
web_view_->SetBounds(0, 0, width(), height());
OnViewWasResized();
}
void NativeWindowWin::ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) {
if (details.is_add && details.child == this)
AddChildView(web_view_);
}
bool NativeWindowWin::AcceleratorPressed(
const ui::Accelerator& accelerator) {
if (ContainsKey(accelerator_table_, accelerator)) {
const MenuItem& item = accelerator_table_[accelerator];
item.model->ActivatedAt(item.position);
return true;
} else {
return false;
}
}
void NativeWindowWin::DeleteDelegate() {
// Do nothing, window is managed by users.
}
views::View* NativeWindowWin::GetInitiallyFocusedView() {
return web_view_;
}
bool NativeWindowWin::CanResize() const {
return resizable_;
}
@@ -246,8 +480,15 @@ bool NativeWindowWin::ShouldHandleSystemCommands() const {
return true;
}
bool NativeWindowWin::ShouldShowWindowIcon() const {
return true;
gfx::ImageSkia NativeWindowWin::GetWindowAppIcon() {
if (icon_.IsEmpty())
return gfx::ImageSkia();
else
return *icon_.ToImageSkia();
}
gfx::ImageSkia NativeWindowWin::GetWindowIcon() {
return GetWindowAppIcon();
}
views::Widget* NativeWindowWin::GetWidget() {
@@ -259,12 +500,83 @@ const views::Widget* NativeWindowWin::GetWidget() const {
}
views::ClientView* NativeWindowWin::CreateClientView(views::Widget* widget) {
return new NativeWindowClientView(widget, web_view_, this);
return new NativeWindowClientView(widget, this);
}
views::NonClientFrameView* NativeWindowWin::CreateNonClientFrameView(
views::Widget* widget) {
return new NativeWindowFrameView(widget, this);
if (has_frame_)
return new NativeWindowFrameView(widget, this);
return new NativeWindowFramelessView(widget, this);
}
void NativeWindowWin::OnViewWasResized() {
// Set the window shape of the RWHV.
gfx::Size sz = web_view_->size();
int height = sz.height(), width = sz.width();
gfx::Path path;
path.addRect(0, 0, width, height);
SetWindowRgn(web_contents()->GetView()->GetNativeView(),
path.CreateNativeRegion(),
1);
SkRegion* rgn = new SkRegion;
if (!window_->IsFullscreen() && !window_->IsMaximized()) {
if (draggable_region())
rgn->op(*draggable_region(), SkRegion::kUnion_Op);
if (!has_frame_ && CanResize()) {
rgn->op(0, 0, width, kResizeInsideBoundsSize, SkRegion::kUnion_Op);
rgn->op(0, 0, kResizeInsideBoundsSize, height, SkRegion::kUnion_Op);
rgn->op(width - kResizeInsideBoundsSize, 0, width, height,
SkRegion::kUnion_Op);
rgn->op(0, height - kResizeInsideBoundsSize, width, height,
SkRegion::kUnion_Op);
}
}
content::WebContents* web_contents = GetWebContents();
if (web_contents->GetRenderViewHost()->GetView())
web_contents->GetRenderViewHost()->GetView()->SetClickthroughRegion(rgn);
}
void NativeWindowWin::RegisterAccelerators() {
views::FocusManager* focus_manager = GetFocusManager();
accelerator_table_.clear();
focus_manager->UnregisterAccelerators(this);
GenerateAcceleratorTable();
for (AcceleratorTable::const_iterator iter = accelerator_table_.begin();
iter != accelerator_table_.end(); ++iter) {
focus_manager->RegisterAccelerator(
iter->first, ui::AcceleratorManager::kNormalPriority, this);
}
}
void NativeWindowWin::GenerateAcceleratorTable() {
DCHECK(menu_);
ui::SimpleMenuModel* model = static_cast<ui::SimpleMenuModel*>(
menu_->model());
FillAcceleratorTable(&accelerator_table_, model);
}
void NativeWindowWin::FillAcceleratorTable(AcceleratorTable* table,
ui::MenuModel* model) {
int count = model->GetItemCount();
for (int i = 0; i < count; ++i) {
ui::MenuModel::ItemType type = model->GetTypeAt(i);
if (type == ui::MenuModel::TYPE_SUBMENU) {
ui::MenuModel* submodel = model->GetSubmenuModelAt(i);
FillAcceleratorTable(table, submodel);
} else {
ui::Accelerator accelerator;
if (model->GetAcceleratorAt(i, &accelerator)) {
MenuItem item = { i, model };
(*table)[accelerator] = item;
}
}
}
}
// static

View File

@@ -5,13 +5,17 @@
#ifndef ATOM_BROWSER_NATIVE_WINDOW_WIN_H_
#define ATOM_BROWSER_NATIVE_WINDOW_WIN_H_
#include "base/string16.h"
#include "base/strings/string16.h"
#include "base/memory/scoped_ptr.h"
#include "browser/native_window.h"
#include "ui/gfx/size.h"
#include "ui/views/widget/widget_delegate.h"
namespace ui {
class MenuModel;
}
namespace views {
class WebView;
class Widget;
@@ -19,8 +23,10 @@ class Widget;
namespace atom {
class Menu2;
class NativeWindowWin : public NativeWindow,
public views::WidgetDelegate {
public views::WidgetDelegateView {
public:
explicit NativeWindowWin(content::WebContents* web_contents,
base::DictionaryValue* options);
@@ -34,6 +40,7 @@ class NativeWindowWin : public NativeWindow,
virtual bool IsFocused() OVERRIDE;
virtual void Show() OVERRIDE;
virtual void Hide() OVERRIDE;
virtual bool IsVisible() OVERRIDE;
virtual void Maximize() OVERRIDE;
virtual void Unmaximize() OVERRIDE;
virtual void Minimize() OVERRIDE;
@@ -58,20 +65,41 @@ class NativeWindowWin : public NativeWindow,
virtual void FlashFrame(bool flash) OVERRIDE;
virtual void SetKiosk(bool kiosk) OVERRIDE;
virtual bool IsKiosk() OVERRIDE;
virtual bool HasModalDialog() OVERRIDE;
virtual gfx::NativeWindow GetNativeWindow() OVERRIDE;
void OnMenuCommand(int position, HMENU menu);
// Set the native window menu.
void SetMenu(ui::MenuModel* menu_model);
views::Widget* window() const { return window_.get(); }
SkRegion* draggable_region() { return draggable_region_.get(); }
protected:
virtual void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) OVERRIDE;
// Overridden from content::WebContentsDelegate:
virtual void HandleKeyboardEvent(
content::WebContents*,
const content::NativeWebKeyboardEvent&) OVERRIDE;
// Overridden from views::View:
virtual void Layout() OVERRIDE;
virtual void ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) OVERRIDE;
virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
// Overridden from views::WidgetDelegate:
virtual void DeleteDelegate() OVERRIDE;
virtual views::View* GetInitiallyFocusedView() OVERRIDE;
virtual bool CanResize() const OVERRIDE;
virtual bool CanMaximize() const OVERRIDE;
virtual string16 GetWindowTitle() const OVERRIDE;
virtual bool ShouldHandleSystemCommands() const OVERRIDE;
virtual bool ShouldShowWindowIcon() const OVERRIDE;
virtual gfx::ImageSkia GetWindowAppIcon() OVERRIDE;
virtual gfx::ImageSkia GetWindowIcon() OVERRIDE;
virtual views::Widget* GetWidget() OVERRIDE;
virtual const views::Widget* GetWidget() const OVERRIDE;
virtual views::ClientView* CreateClientView(views::Widget* widget) OVERRIDE;
@@ -79,9 +107,32 @@ class NativeWindowWin : public NativeWindow,
views::Widget* widget) OVERRIDE;
private:
typedef struct { int position; ui::MenuModel* model; } MenuItem;
typedef std::map<ui::Accelerator, MenuItem> AcceleratorTable;
void OnViewWasResized();
// Register accelerators supported by the menu model.
void RegisterAccelerators();
// Generate a table that contains memu model's accelerators and command ids.
void GenerateAcceleratorTable();
// Helper to fill the accelerator table from the model.
void FillAcceleratorTable(AcceleratorTable* table,
ui::MenuModel* model);
scoped_ptr<views::Widget> window_;
views::WebView* web_view_; // managed by window_.
// The window menu.
scoped_ptr<atom::Menu2> menu_;
// Map from accelerator to menu item's command id.
AcceleratorTable accelerator_table_;
scoped_ptr<SkRegion> draggable_region_;
bool resizable_;
string16 title_;
gfx::Size minimum_size_;

View File

@@ -0,0 +1,112 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "browser/net/adapter_request_job.h"
#include "base/threading/sequenced_worker_pool.h"
#include "browser/net/url_request_string_job.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/net_errors.h"
#include "net/url_request/url_request_error_job.h"
#include "net/url_request/url_request_file_job.h"
namespace atom {
AdapterRequestJob::AdapterRequestJob(ProtocolHandler* protocol_handler,
net::URLRequest* request,
net::NetworkDelegate* network_delegate)
: URLRequestJob(request, network_delegate),
protocol_handler_(protocol_handler),
weak_factory_(this) {
}
void AdapterRequestJob::Start() {
DCHECK(!real_job_);
content::BrowserThread::PostTask(
content::BrowserThread::UI,
FROM_HERE,
base::Bind(&AdapterRequestJob::GetJobTypeInUI,
weak_factory_.GetWeakPtr()));
}
void AdapterRequestJob::Kill() {
if (real_job_) // Kill could happen when real_job_ is created.
real_job_->Kill();
}
bool AdapterRequestJob::ReadRawData(net::IOBuffer* buf,
int buf_size,
int *bytes_read) {
DCHECK(real_job_);
return real_job_->ReadRawData(buf, buf_size, bytes_read);
}
bool AdapterRequestJob::IsRedirectResponse(GURL* location,
int* http_status_code) {
DCHECK(real_job_);
return real_job_->IsRedirectResponse(location, http_status_code);
}
net::Filter* AdapterRequestJob::SetupFilter() const {
DCHECK(real_job_);
return real_job_->SetupFilter();
}
bool AdapterRequestJob::GetMimeType(std::string* mime_type) const {
DCHECK(real_job_);
return real_job_->GetMimeType(mime_type);
}
bool AdapterRequestJob::GetCharset(std::string* charset) {
DCHECK(real_job_);
return real_job_->GetCharset(charset);
}
base::WeakPtr<AdapterRequestJob> AdapterRequestJob::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
void AdapterRequestJob::CreateErrorJobAndStart(int error_code) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
real_job_ = new net::URLRequestErrorJob(
request(), network_delegate(), error_code);
real_job_->Start();
}
void AdapterRequestJob::CreateStringJobAndStart(const std::string& mime_type,
const std::string& charset,
const std::string& data) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
real_job_ = new URLRequestStringJob(
request(), network_delegate(), mime_type, charset, data);
real_job_->Start();
}
void AdapterRequestJob::CreateFileJobAndStart(const base::FilePath& path) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
real_job_ = new net::URLRequestFileJob(
request(),
network_delegate(),
path,
content::BrowserThread::GetBlockingPool()->
GetTaskRunnerWithShutdownBehavior(
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
real_job_->Start();
}
void AdapterRequestJob::CreateJobFromProtocolHandlerAndStart() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
DCHECK(protocol_handler_);
real_job_ = protocol_handler_->MaybeCreateJob(request(),
network_delegate());
if (!real_job_.get())
CreateErrorJobAndStart(net::ERR_NOT_IMPLEMENTED);
else
real_job_->Start();
}
} // namespace atom

View File

@@ -0,0 +1,68 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_NET_ADAPTER_REQUEST_JOB_H_
#define ATOM_BROWSER_NET_ADAPTER_REQUEST_JOB_H_
#include "base/memory/weak_ptr.h"
#include "net/url_request/url_request_job.h"
#include "net/url_request/url_request_job_factory.h"
namespace base {
class FilePath;
}
namespace atom {
// Ask JS which type of job it wants, and then delegate corresponding methods.
class AdapterRequestJob : public net::URLRequestJob {
public:
typedef net::URLRequestJobFactory::ProtocolHandler ProtocolHandler;
AdapterRequestJob(ProtocolHandler* protocol_handler,
net::URLRequest* request,
net::NetworkDelegate* network_delegate);
public:
// net::URLRequestJob:
virtual void Start() OVERRIDE;
virtual void Kill() OVERRIDE;
virtual bool ReadRawData(net::IOBuffer* buf,
int buf_size,
int *bytes_read) OVERRIDE;
virtual bool IsRedirectResponse(GURL* location,
int* http_status_code) OVERRIDE;
virtual net::Filter* SetupFilter() const OVERRIDE;
virtual bool GetMimeType(std::string* mime_type) const OVERRIDE;
virtual bool GetCharset(std::string* charset) OVERRIDE;
base::WeakPtr<AdapterRequestJob> GetWeakPtr();
ProtocolHandler* default_protocol_handler() { return protocol_handler_; }
// Override this function to determine which job should be started.
virtual void GetJobTypeInUI() = 0;
void CreateErrorJobAndStart(int error_code);
void CreateStringJobAndStart(const std::string& mime_type,
const std::string& charset,
const std::string& data);
void CreateFileJobAndStart(const base::FilePath& path);
void CreateJobFromProtocolHandlerAndStart();
private:
// The delegated request job.
scoped_refptr<net::URLRequestJob> real_job_;
// Default protocol handler.
ProtocolHandler* protocol_handler_;
base::WeakPtrFactory<AdapterRequestJob> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(AdapterRequestJob);
};
} // namespace atom
#endif // ATOM_BROWSER_NET_ADAPTER_REQUEST_JOB_H_

View File

@@ -0,0 +1,178 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "browser/net/atom_url_request_context_getter.h"
#include "base/strings/string_util.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/worker_pool.h"
#include "browser/net/atom_url_request_job_factory.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/cookie_store_factory.h"
#include "content/public/common/url_constants.h"
#include "net/cert/cert_verifier.h"
#include "net/cookies/cookie_monster.h"
#include "net/http/http_auth_handler_factory.h"
#include "net/http/http_cache.h"
#include "net/http/http_server_properties_impl.h"
#include "net/proxy/dhcp_proxy_script_fetcher_factory.h"
#include "net/proxy/proxy_config_service.h"
#include "net/proxy/proxy_script_fetcher_impl.h"
#include "net/proxy/proxy_service.h"
#include "net/proxy/proxy_service_v8.h"
#include "net/ssl/default_server_bound_cert_store.h"
#include "net/ssl/server_bound_cert_service.h"
#include "net/ssl/ssl_config_service_defaults.h"
#include "net/url_request/data_protocol_handler.h"
#include "net/url_request/file_protocol_handler.h"
#include "net/url_request/static_http_user_agent_settings.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_storage.h"
#include "vendor/brightray/browser/network_delegate.h"
namespace atom {
using content::BrowserThread;
AtomURLRequestContextGetter::AtomURLRequestContextGetter(
const base::FilePath& base_path,
base::MessageLoop* io_loop,
base::MessageLoop* file_loop,
scoped_ptr<brightray::NetworkDelegate> network_delegate,
content::ProtocolHandlerMap* protocol_handlers)
: base_path_(base_path),
io_loop_(io_loop),
file_loop_(file_loop),
job_factory_(NULL),
network_delegate_(network_delegate.Pass()) {
// Must first be created on the UI thread.
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
std::swap(protocol_handlers_, *protocol_handlers);
// We must create the proxy config service on the UI loop on Linux because it
// must synchronously run on the glib message loop. This will be passed to
// the URLRequestContextStorage on the IO thread in GetURLRequestContext().
proxy_config_service_.reset(
net::ProxyService::CreateSystemProxyConfigService(
io_loop_->message_loop_proxy(),
file_loop_));
}
AtomURLRequestContextGetter::~AtomURLRequestContextGetter() {
}
net::URLRequestContext* AtomURLRequestContextGetter::GetURLRequestContext() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (!url_request_context_.get()) {
url_request_context_.reset(new net::URLRequestContext());
url_request_context_->set_network_delegate(network_delegate_.get());
storage_.reset(
new net::URLRequestContextStorage(url_request_context_.get()));
storage_->set_cookie_store(content::CreatePersistentCookieStore(
base_path_.Append(FILE_PATH_LITERAL("Cookies")),
false,
nullptr,
nullptr,
nullptr));
storage_->set_server_bound_cert_service(new net::ServerBoundCertService(
new net::DefaultServerBoundCertStore(NULL),
base::WorkerPool::GetTaskRunner(true)));
storage_->set_http_user_agent_settings(
new net::StaticHttpUserAgentSettings(
"en-us,en", EmptyString()));
scoped_ptr<net::HostResolver> host_resolver(
net::HostResolver::CreateDefaultResolver(NULL));
net::DhcpProxyScriptFetcherFactory dhcp_factory;
storage_->set_cert_verifier(net::CertVerifier::CreateDefault());
storage_->set_proxy_service(
net::CreateProxyServiceUsingV8ProxyResolver(
proxy_config_service_.release(),
new net::ProxyScriptFetcherImpl(url_request_context_.get()),
dhcp_factory.Create(url_request_context_.get()),
host_resolver.get(),
NULL,
url_request_context_->network_delegate()));
storage_->set_ssl_config_service(new net::SSLConfigServiceDefaults);
storage_->set_http_auth_handler_factory(
net::HttpAuthHandlerFactory::CreateDefault(host_resolver.get()));
scoped_ptr<net::HttpServerProperties> server_properties(
new net::HttpServerPropertiesImpl);
storage_->set_http_server_properties(server_properties.Pass());
base::FilePath cache_path = base_path_.Append(FILE_PATH_LITERAL("Cache"));
net::HttpCache::DefaultBackend* main_backend =
new net::HttpCache::DefaultBackend(
net::DISK_CACHE,
net::CACHE_BACKEND_DEFAULT,
cache_path,
0,
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE));
net::HttpNetworkSession::Params network_session_params;
network_session_params.cert_verifier =
url_request_context_->cert_verifier();
network_session_params.server_bound_cert_service =
url_request_context_->server_bound_cert_service();
network_session_params.proxy_service =
url_request_context_->proxy_service();
network_session_params.ssl_config_service =
url_request_context_->ssl_config_service();
network_session_params.http_auth_handler_factory =
url_request_context_->http_auth_handler_factory();
network_session_params.network_delegate =
url_request_context_->network_delegate();
network_session_params.http_server_properties =
url_request_context_->http_server_properties();
network_session_params.ignore_certificate_errors = false;
// Give |storage_| ownership at the end in case it's |mapped_host_resolver|.
storage_->set_host_resolver(host_resolver.Pass());
network_session_params.host_resolver =
url_request_context_->host_resolver();
net::HttpCache* main_cache = new net::HttpCache(
network_session_params, main_backend);
storage_->set_http_transaction_factory(main_cache);
DCHECK(!job_factory_);
job_factory_ = new AtomURLRequestJobFactory;
for (content::ProtocolHandlerMap::iterator it = protocol_handlers_.begin();
it != protocol_handlers_.end();
++it) {
bool set_protocol = job_factory_->SetProtocolHandler(
it->first,
it->second.release());
DCHECK(set_protocol);
}
protocol_handlers_.clear();
scoped_ptr<net::FileProtocolHandler> file_protocol_handler(
new net::FileProtocolHandler(
content::BrowserThread::GetBlockingPool()->
GetTaskRunnerWithShutdownBehavior(
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)));
job_factory_->SetProtocolHandler(chrome::kDataScheme,
new net::DataProtocolHandler);
job_factory_->SetProtocolHandler(chrome::kFileScheme,
file_protocol_handler.release());
storage_->set_job_factory(job_factory_);
}
return url_request_context_.get();
}
scoped_refptr<base::SingleThreadTaskRunner>
AtomURLRequestContextGetter::GetNetworkTaskRunner() const {
return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
}
net::HostResolver* AtomURLRequestContextGetter::host_resolver() {
return url_request_context_->host_resolver();
}
} // namespace atom

View File

@@ -0,0 +1,69 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_NET_ATOM_URL_REQUEST_CONTEXT_GETTER_H_
#define ATOM_BROWSER_NET_ATOM_URL_REQUEST_CONTEXT_GETTER_H_
#include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h"
#include "content/public/browser/content_browser_client.h"
#include "net/url_request/url_request_context_getter.h"
namespace base {
class MessageLoop;
}
namespace brightray {
class NetworkDelegate;
}
namespace net {
class HostResolver;
class ProxyConfigService;
class URLRequestContextStorage;
}
namespace atom {
class AtomURLRequestJobFactory;
class AtomURLRequestContextGetter : public net::URLRequestContextGetter {
public:
AtomURLRequestContextGetter(
const base::FilePath& base_path,
base::MessageLoop* io_loop,
base::MessageLoop* file_loop,
scoped_ptr<brightray::NetworkDelegate> network_delegate,
content::ProtocolHandlerMap* protocol_handlers);
// net::URLRequestContextGetter implementations:
virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE;
virtual scoped_refptr<base::SingleThreadTaskRunner>
GetNetworkTaskRunner() const OVERRIDE;
net::HostResolver* host_resolver();
net::URLRequestContextStorage* storage() const { return storage_.get(); }
AtomURLRequestJobFactory* job_factory() const { return job_factory_; }
protected:
virtual ~AtomURLRequestContextGetter();
private:
base::FilePath base_path_;
base::MessageLoop* io_loop_;
base::MessageLoop* file_loop_;
AtomURLRequestJobFactory* job_factory_;
scoped_ptr<net::ProxyConfigService> proxy_config_service_;
scoped_ptr<brightray::NetworkDelegate> network_delegate_;
scoped_ptr<net::URLRequestContextStorage> storage_;
scoped_ptr<net::URLRequestContext> url_request_context_;
content::ProtocolHandlerMap protocol_handlers_;
DISALLOW_COPY_AND_ASSIGN(AtomURLRequestContextGetter);
};
} // namespace atom
#endif // ATOM_BROWSER_NET_ATOM_URL_REQUEST_CONTEXT_GETTER_H_

View File

@@ -0,0 +1,109 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "browser/net/atom_url_request_job_factory.h"
#include "base/stl_util.h"
#include "net/base/load_flags.h"
#include "net/url_request/url_request.h"
namespace atom {
typedef net::URLRequestJobFactory::ProtocolHandler ProtocolHandler;
AtomURLRequestJobFactory::AtomURLRequestJobFactory() {}
AtomURLRequestJobFactory::~AtomURLRequestJobFactory() {
STLDeleteValues(&protocol_handler_map_);
}
bool AtomURLRequestJobFactory::SetProtocolHandler(
const std::string& scheme,
ProtocolHandler* protocol_handler) {
DCHECK(CalledOnValidThread());
base::AutoLock locked(lock_);
if (!protocol_handler) {
ProtocolHandlerMap::iterator it = protocol_handler_map_.find(scheme);
if (it == protocol_handler_map_.end())
return false;
delete it->second;
protocol_handler_map_.erase(it);
return true;
}
if (ContainsKey(protocol_handler_map_, scheme))
return false;
protocol_handler_map_[scheme] = protocol_handler;
return true;
}
ProtocolHandler* AtomURLRequestJobFactory::ReplaceProtocol(
const std::string& scheme,
ProtocolHandler* protocol_handler) {
DCHECK(CalledOnValidThread());
DCHECK(protocol_handler);
base::AutoLock locked(lock_);
if (!ContainsKey(protocol_handler_map_, scheme))
return NULL;
ProtocolHandler* original_protocol_handler = protocol_handler_map_[scheme];
protocol_handler_map_[scheme] = protocol_handler;
return original_protocol_handler;
}
ProtocolHandler* AtomURLRequestJobFactory::GetProtocolHandler(
const std::string& scheme) const {
DCHECK(CalledOnValidThread());
base::AutoLock locked(lock_);
ProtocolHandlerMap::const_iterator it = protocol_handler_map_.find(scheme);
if (it == protocol_handler_map_.end())
return NULL;
return it->second;
}
bool AtomURLRequestJobFactory::HasProtocolHandler(
const std::string& scheme) const {
base::AutoLock locked(lock_);
return ContainsKey(protocol_handler_map_, scheme);
}
net::URLRequestJob* AtomURLRequestJobFactory::MaybeCreateJobWithProtocolHandler(
const std::string& scheme,
net::URLRequest* request,
net::NetworkDelegate* network_delegate) const {
DCHECK(CalledOnValidThread());
base::AutoLock locked(lock_);
ProtocolHandlerMap::const_iterator it = protocol_handler_map_.find(scheme);
if (it == protocol_handler_map_.end())
return NULL;
return it->second->MaybeCreateJob(request, network_delegate);
}
bool AtomURLRequestJobFactory::IsHandledProtocol(
const std::string& scheme) const {
DCHECK(CalledOnValidThread());
return HasProtocolHandler(scheme) ||
net::URLRequest::IsHandledProtocol(scheme);
}
bool AtomURLRequestJobFactory::IsHandledURL(const GURL& url) const {
if (!url.is_valid()) {
// We handle error cases.
return true;
}
return IsHandledProtocol(url.scheme());
}
bool AtomURLRequestJobFactory::IsSafeRedirectTarget(
const GURL& location) const {
return IsHandledURL(location);
}
} // namespace atom

View File

@@ -0,0 +1,62 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_NET_ATOM_URL_REQUEST_URL_REQUEST_JOB_FACTORY_H_
#define ATOM_BROWSER_NET_ATOM_URL_REQUEST_URL_REQUEST_JOB_FACTORY_H_
#include <map>
#include <vector>
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/synchronization/lock.h"
#include "net/url_request/url_request_job_factory.h"
namespace atom {
class AtomURLRequestJobFactory : public net::URLRequestJobFactory {
public:
AtomURLRequestJobFactory();
virtual ~AtomURLRequestJobFactory();
// Sets the ProtocolHandler for a scheme. Returns true on success, false on
// failure (a ProtocolHandler already exists for |scheme|). On success,
// URLRequestJobFactory takes ownership of |protocol_handler|.
bool SetProtocolHandler(const std::string& scheme,
ProtocolHandler* protocol_handler);
// Intercepts the ProtocolHandler for a scheme. Returns the original protocol
// handler on success, otherwise returns NULL.
ProtocolHandler* ReplaceProtocol(const std::string& scheme,
ProtocolHandler* protocol_handler);
// Returns the protocol handler registered with scheme.
ProtocolHandler* GetProtocolHandler(const std::string& scheme) const;
// Whether the protocol handler is registered by the job factory.
bool HasProtocolHandler(const std::string& scheme) const;
// URLRequestJobFactory implementation
virtual net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
const std::string& scheme,
net::URLRequest* request,
net::NetworkDelegate* network_delegate) const OVERRIDE;
virtual bool IsHandledProtocol(const std::string& scheme) const OVERRIDE;
virtual bool IsHandledURL(const GURL& url) const OVERRIDE;
virtual bool IsSafeRedirectTarget(const GURL& location) const OVERRIDE;
private:
typedef std::map<std::string, ProtocolHandler*> ProtocolHandlerMap;
ProtocolHandlerMap protocol_handler_map_;
mutable base::Lock lock_;
DISALLOW_COPY_AND_ASSIGN(AtomURLRequestJobFactory);
};
} // namespace atom
#endif // ATOM_BROWSER_NET_ATOM_URL_REQUEST_URL_REQUEST_JOB_FACTORY_H_

View File

@@ -0,0 +1,33 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "browser/net/url_request_string_job.h"
#include "net/base/net_errors.h"
namespace atom {
URLRequestStringJob::URLRequestStringJob(net::URLRequest* request,
net::NetworkDelegate* network_delegate,
const std::string& mime_type,
const std::string& charset,
const std::string& data)
: net::URLRequestSimpleJob(request, network_delegate),
mime_type_(mime_type),
charset_(charset),
data_(data) {
}
int URLRequestStringJob::GetData(
std::string* mime_type,
std::string* charset,
std::string* data,
const net::CompletionCallback& callback) const {
*mime_type = mime_type_;
*charset = charset_;
*data = data_;
return net::OK;
}
} // namespace atom

View File

@@ -0,0 +1,36 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_NET_URL_REQUEST_STRING_JOB_H_
#define ATOM_BROWSER_NET_URL_REQUEST_STRING_JOB_H_
#include "net/url_request/url_request_simple_job.h"
namespace atom {
class URLRequestStringJob : public net::URLRequestSimpleJob {
public:
URLRequestStringJob(net::URLRequest* request,
net::NetworkDelegate* network_delegate,
const std::string& mime_type,
const std::string& charset,
const std::string& data);
// URLRequestSimpleJob:
virtual int GetData(std::string* mime_type,
std::string* charset,
std::string* data,
const net::CompletionCallback& callback) const OVERRIDE;
private:
std::string mime_type_;
std::string charset_;
std::string data_;
DISALLOW_COPY_AND_ASSIGN(URLRequestStringJob);
};
} // namespace atom
#endif // ATOM_BROWSER_NET_URL_REQUEST_STRING_JOB_H_

View File

@@ -4,9 +4,11 @@
#include "browser/ui/accelerator_util.h"
#include <stdio.h>
#include <string>
#include "base/string_util.h"
#include "base/strings/string_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "ui/base/accelerators/accelerator.h"
@@ -15,67 +17,158 @@ namespace accelerator_util {
namespace {
// For Mac, we convert "Ctrl" to "Command" and "MacCtrl" to "Ctrl". Other
// platforms leave the shortcut untouched.
std::string NormalizeShortcutSuggestion(const std::string& suggestion) {
#if !defined(OS_MACOSX)
return suggestion;
#endif
// Return key code of the char.
ui::KeyboardCode KeyboardCodeFromCharCode(char c, bool* shifted) {
*shifted = false;
switch (c) {
case 8: case 0x7F: return ui::VKEY_BACK;
case 9: return ui::VKEY_TAB;
case 0xD: case 3: return ui::VKEY_RETURN;
case 0x1B: return ui::VKEY_ESCAPE;
case ' ': return ui::VKEY_SPACE;
std::string key;
std::vector<std::string> tokens;
base::SplitString(suggestion, '+', &tokens);
for (size_t i = 0; i < tokens.size(); i++) {
if (tokens[i] == "Ctrl")
tokens[i] = "Command";
else if (tokens[i] == "MacCtrl")
tokens[i] = "Ctrl";
case 'a': return ui::VKEY_A;
case 'b': return ui::VKEY_B;
case 'c': return ui::VKEY_C;
case 'd': return ui::VKEY_D;
case 'e': return ui::VKEY_E;
case 'f': return ui::VKEY_F;
case 'g': return ui::VKEY_G;
case 'h': return ui::VKEY_H;
case 'i': return ui::VKEY_I;
case 'j': return ui::VKEY_J;
case 'k': return ui::VKEY_K;
case 'l': return ui::VKEY_L;
case 'm': return ui::VKEY_M;
case 'n': return ui::VKEY_N;
case 'o': return ui::VKEY_O;
case 'p': return ui::VKEY_P;
case 'q': return ui::VKEY_Q;
case 'r': return ui::VKEY_R;
case 's': return ui::VKEY_S;
case 't': return ui::VKEY_T;
case 'u': return ui::VKEY_U;
case 'v': return ui::VKEY_V;
case 'w': return ui::VKEY_W;
case 'x': return ui::VKEY_X;
case 'y': return ui::VKEY_Y;
case 'z': return ui::VKEY_Z;
case ')': *shifted = true; case '0': return ui::VKEY_0;
case '!': *shifted = true; case '1': return ui::VKEY_1;
case '@': *shifted = true; case '2': return ui::VKEY_2;
case '#': *shifted = true; case '3': return ui::VKEY_3;
case '$': *shifted = true; case '4': return ui::VKEY_4;
case '%': *shifted = true; case '5': return ui::VKEY_5;
case '^': *shifted = true; case '6': return ui::VKEY_6;
case '&': *shifted = true; case '7': return ui::VKEY_7;
case '*': *shifted = true; case '8': return ui::VKEY_8;
case '(': *shifted = true; case '9': return ui::VKEY_9;
case ':': *shifted = true; case ';': return ui::VKEY_OEM_1;
case '+': *shifted = true; case '=': return ui::VKEY_OEM_PLUS;
case '<': *shifted = true; case ',': return ui::VKEY_OEM_COMMA;
case '_': *shifted = true; case '-': return ui::VKEY_OEM_MINUS;
case '>': *shifted = true; case '.': return ui::VKEY_OEM_PERIOD;
case '?': *shifted = true; case '/': return ui::VKEY_OEM_2;
case '~': *shifted = true; case '`': return ui::VKEY_OEM_3;
case '{': *shifted = true; case '[': return ui::VKEY_OEM_4;
case '|': *shifted = true; case '\\': return ui::VKEY_OEM_5;
case '}': *shifted = true; case ']': return ui::VKEY_OEM_6;
case '"': *shifted = true; case '\'': return ui::VKEY_OEM_7;
default: return ui::VKEY_UNKNOWN;
}
return JoinString(tokens, '+');
}
} // namespace
bool StringToAccelerator(const std::string& description,
ui::Accelerator* accelerator) {
std::string shortcut(NormalizeShortcutSuggestion(description));
if (!IsStringASCII(description)) {
LOG(ERROR) << "The accelerator string can only contain ASCII characters";
return false;
}
std::string shortcut(StringToLowerASCII(description));
std::vector<std::string> tokens;
base::SplitString(shortcut, '+', &tokens);
if (tokens.size() < 2 || tokens.size() > 4) {
LOG(WARNING) << "Invalid accelerator description: " << description;
return false;
}
// Now, parse it into an accelerator.
int modifiers = ui::EF_NONE;
ui::KeyboardCode key = ui::VKEY_UNKNOWN;
for (size_t i = 0; i < tokens.size(); i++) {
if (tokens[i] == "Ctrl") {
// We use straight comparing instead of map because the accelerator tends
// to be correct and usually only uses few special tokens.
if (tokens[i].size() == 1) {
bool shifted = false;
key = KeyboardCodeFromCharCode(tokens[i][0], &shifted);
if (shifted)
modifiers |= ui::EF_SHIFT_DOWN;
} else if (tokens[i] == "ctrl" || tokens[i] == "control") {
modifiers |= ui::EF_CONTROL_DOWN;
} else if (tokens[i] == "Command") {
} else if (tokens[i] == "cmd" || tokens[i] == "command") {
modifiers |= ui::EF_COMMAND_DOWN;
} else if (tokens[i] == "Alt") {
} else if (tokens[i] == "commandorcontrol" || tokens[i] == "cmdorctrl") {
#if defined(OS_MACOSX)
modifiers |= ui::EF_COMMAND_DOWN;
#else
modifiers |= ui::EF_CONTROL_DOWN;
#endif
} else if (tokens[i] == "alt") {
modifiers |= ui::EF_ALT_DOWN;
} else if (tokens[i] == "Shift") {
} else if (tokens[i] == "shift") {
modifiers |= ui::EF_SHIFT_DOWN;
} else if (tokens[i].size() == 1) {
if (key != ui::VKEY_UNKNOWN) {
// Multiple key assignments.
key = ui::VKEY_UNKNOWN;
break;
}
if (tokens[i][0] >= 'A' && tokens[i][0] <= 'Z') {
key = static_cast<ui::KeyboardCode>(ui::VKEY_A + (tokens[i][0] - 'A'));
} else if (tokens[i][0] >= '0' && tokens[i][0] <= '9') {
key = static_cast<ui::KeyboardCode>(ui::VKEY_0 + (tokens[i][0] - '0'));
} else if (tokens[i][0] >= '+' && tokens[i][0] <= '.') {
key = static_cast<ui::KeyboardCode>(
ui::VKEY_OEM_PLUS + (tokens[i][0] - '+'));
} else if (tokens[i] == "tab") {
key = ui::VKEY_TAB;
} else if (tokens[i] == "space") {
key = ui::VKEY_SPACE;
} else if (tokens[i] == "backspace") {
key = ui::VKEY_BACK;
} else if (tokens[i] == "delete") {
key = ui::VKEY_DELETE;
} else if (tokens[i] == "enter" || tokens[i] == "return") {
key = ui::VKEY_RETURN;
} else if (tokens[i] == "up") {
key = ui::VKEY_UP;
} else if (tokens[i] == "down") {
key = ui::VKEY_DOWN;
} else if (tokens[i] == "left") {
key = ui::VKEY_LEFT;
} else if (tokens[i] == "right") {
key = ui::VKEY_RIGHT;
} else if (tokens[i] == "home") {
key = ui::VKEY_HOME;
} else if (tokens[i] == "end") {
key = ui::VKEY_END;
} else if (tokens[i] == "pagedown") {
key = ui::VKEY_PRIOR;
} else if (tokens[i] == "pageup") {
key = ui::VKEY_NEXT;
} else if (tokens[i] == "esc") {
key = ui::VKEY_ESCAPE;
} else if (tokens[i] == "volumemute") {
key = ui::VKEY_VOLUME_MUTE;
} else if (tokens[i] == "volumeup") {
key = ui::VKEY_VOLUME_UP;
} else if (tokens[i] == "volumedown") {
key = ui::VKEY_VOLUME_DOWN;
} else if (tokens[i] == "medianexttrack") {
key = ui::VKEY_MEDIA_NEXT_TRACK;
} else if (tokens[i] == "mediaprevioustrack") {
key = ui::VKEY_MEDIA_PREV_TRACK;
} else if (tokens[i] == "mediastop") {
key = ui::VKEY_MEDIA_STOP;
} else if (tokens[i] == "mediaplaypause") {
key = ui::VKEY_MEDIA_PLAY_PAUSE;
} else if (tokens[i].size() > 1 && tokens[i][0] == 'f') {
// F1 - F24.
int n;
if (base::StringToInt(tokens[i].c_str() + 1, &n)) {
key = static_cast<ui::KeyboardCode>(ui::VKEY_F1 + n - 1);
} else {
LOG(WARNING) << "Invalid accelerator character: " << tokens[i];
key = ui::VKEY_UNKNOWN;
break;
LOG(WARNING) << tokens[i] << "is not available on keyboard";
return false;
}
} else {
LOG(WARNING) << "Invalid accelerator token: " << tokens[i];
@@ -83,6 +176,11 @@ bool StringToAccelerator(const std::string& description,
}
}
if (key == ui::VKEY_UNKNOWN) {
LOG(WARNING) << "The accelerator doesn't contain a valid key";
return false;
}
*accelerator = ui::Accelerator(key, modifiers);
SetPlatformAccelerator(accelerator);
return true;

View File

@@ -6,7 +6,7 @@
#include "ui/base/accelerators/accelerator.h"
#import "ui/base/accelerators/platform_accelerator_cocoa.h"
#import "ui/base/keycodes/keyboard_code_conversion_mac.h"
#import "ui/events/keycodes/keyboard_code_conversion_mac.h"
namespace accelerator_util {

View File

@@ -2,18 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_ATOM_EVENT_PROCESSING_WINDOW_H_
#define ATOM_BROWSER_ATOM_EVENT_PROCESSING_WINDOW_H_
#ifndef ATOM_BROWSER_UI_ATOM_EVENT_PROCESSING_WINDOW_H_
#define ATOM_BROWSER_UI_ATOM_EVENT_PROCESSING_WINDOW_H_
#import <Cocoa/Cocoa.h>
#include "base/memory/scoped_nsobject.h"
#import "ui/base/cocoa/underlay_opengl_hosting_window.h"
// Override NSWindow to access unhandled keyboard events (for command
// processing); subclassing NSWindow is the only method to do
// this.
@interface AtomEventProcessingWindow : UnderlayOpenGLHostingWindow {
@interface AtomEventProcessingWindow : NSWindow {
@private
BOOL redispatchingEvent_;
BOOL eventHandled_;
@@ -30,4 +27,4 @@
- (BOOL)performKeyEquivalent:(NSEvent*)theEvent;
@end
#endif // ATOM_BROWSER_ATOM_EVENT_PROCESSING_WINDOW_H_
#endif // ATOM_BROWSER_UI_ATOM_EVENT_PROCESSING_WINDOW_H_

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "browser/atom_event_processing_window.h"
#import "browser/ui/atom_event_processing_window.h"
#include "base/logging.h"
#import "content/public/browser/render_widget_host_view_mac_base.h"

View File

@@ -8,8 +8,8 @@
#import <Cocoa/Cocoa.h>
#include "base/memory/scoped_nsobject.h"
#include "base/string16.h"
#include "base/mac/scoped_nsobject.h"
#include "base/strings/string16.h"
namespace ui {
class MenuModel;
@@ -24,7 +24,7 @@ class MenuModel;
@interface AtomMenuController : NSObject<NSMenuDelegate> {
@protected
ui::MenuModel* model_; // weak
scoped_nsobject<NSMenu> menu_;
base::scoped_nsobject<NSMenu> menu_;
BOOL isMenuOpen_;
}

View File

@@ -133,7 +133,7 @@ int EventFlagsFromNSEvent(NSEvent* event) {
fromModel:(ui::MenuModel*)model {
string16 label16 = model->GetLabelAt(index);
NSString* label = l10n_util::FixUpWindowsStyleLabel(label16);
scoped_nsobject<NSMenuItem> item(
base::scoped_nsobject<NSMenuItem> item(
[[NSMenuItem alloc] initWithTitle:label
action:@selector(itemSelected:)
keyEquivalent:@""]);
@@ -154,9 +154,11 @@ int EventFlagsFromNSEvent(NSEvent* event) {
[submenu setTitle:[item title]];
[item setSubmenu:submenu];
// Hack to set window menu.
// Hack to set window and help menu.
if ([[item title] isEqualToString:@"Window"] && [submenu numberOfItems] > 0)
[NSApp setWindowsMenu:submenu];
else if ([[item title] isEqualToString:@"Help"])
[NSApp setHelpMenu:submenu];
} else {
// The MenuModel works on indexes so we can't just set the command id as the
// tag like we do in other menus. Also set the represented object to be

View File

@@ -8,6 +8,7 @@
#include <string>
#include <vector>
#include "base/callback_forward.h"
#include "base/files/file_path.h"
namespace atom {
@@ -23,16 +24,34 @@ enum FileDialogProperty {
FILE_DIALOG_CREATE_DIRECTORY = 8,
};
bool ShowOpenDialog(const std::string& title,
typedef base::Callback<void(
bool result, const std::vector<base::FilePath>& paths)> OpenDialogCallback;
typedef base::Callback<void(
bool result, const base::FilePath& path)> SaveDialogCallback;
bool ShowOpenDialog(atom::NativeWindow* parent_window,
const std::string& title,
const base::FilePath& default_path,
int properties,
std::vector<base::FilePath>* paths);
bool ShowSaveDialog(atom::NativeWindow* window,
void ShowOpenDialog(atom::NativeWindow* parent_window,
const std::string& title,
const base::FilePath& default_path,
int properties,
const OpenDialogCallback& callback);
bool ShowSaveDialog(atom::NativeWindow* parent_window,
const std::string& title,
const base::FilePath& default_path,
base::FilePath* path);
void ShowSaveDialog(atom::NativeWindow* parent_window,
const std::string& title,
const base::FilePath& default_path,
const SaveDialogCallback& callback);
} // namespace file_dialog
#endif // BROWSER_UI_FILE_DIALOG_H_

View File

@@ -24,7 +24,7 @@ void SetupDialog(NSSavePanel* dialog,
NSString* default_dir = nil;
NSString* default_filename = nil;
if (!default_path.empty()) {
if (file_util::DirectoryExists(default_path)) {
if (base::DirectoryExists(default_path)) {
default_dir = base::SysUTF8ToNSString(default_path.value());
} else {
default_dir = base::SysUTF8ToNSString(default_path.DirName().value());
@@ -38,20 +38,11 @@ void SetupDialog(NSSavePanel* dialog,
if (default_filename)
[dialog setNameFieldStringValue:default_filename];
[dialog setCanSelectHiddenExtension:YES];
[dialog setAllowsOtherFileTypes:YES];
}
} // namespace
bool ShowOpenDialog(const std::string& title,
const base::FilePath& default_path,
int properties,
std::vector<base::FilePath>* paths) {
DCHECK(paths);
NSOpenPanel* dialog = [NSOpenPanel openPanel];
SetupDialog(dialog, title, default_path);
void SetupDialogForProperties(NSOpenPanel* dialog, int properties) {
[dialog setCanChooseFiles:(properties & FILE_DIALOG_OPEN_FILE)];
if (properties & FILE_DIALOG_OPEN_DIRECTORY)
[dialog setCanChooseDirectories:YES];
@@ -59,49 +50,119 @@ bool ShowOpenDialog(const std::string& title,
[dialog setCanCreateDirectories:YES];
if (properties & FILE_DIALOG_MULTI_SELECTIONS)
[dialog setAllowsMultipleSelection:YES];
}
if ([dialog runModal] == NSFileHandlingPanelCancelButton)
return false;
// Run modal dialog with parent window and return user's choice.
int RunModalDialog(NSSavePanel* dialog, atom::NativeWindow* parent_window) {
__block int chosen = NSFileHandlingPanelCancelButton;
if (parent_window == NULL) {
chosen = [dialog runModal];
} else {
NSWindow* window = parent_window->GetNativeWindow();
[dialog beginSheetModalForWindow:window
completionHandler:^(NSInteger c) {
chosen = c;
[NSApp stopModal];
}];
[NSApp runModalForWindow:window];
}
return chosen;
}
void ReadDialogPaths(NSOpenPanel* dialog, std::vector<base::FilePath>* paths) {
NSArray* urls = [dialog URLs];
for (NSURL* url in urls)
if ([url isFileURL])
paths->push_back(base::FilePath(base::SysNSStringToUTF8([url path])));
}
} // namespace
bool ShowOpenDialog(atom::NativeWindow* parent_window,
const std::string& title,
const base::FilePath& default_path,
int properties,
std::vector<base::FilePath>* paths) {
DCHECK(paths);
NSOpenPanel* dialog = [NSOpenPanel openPanel];
SetupDialog(dialog, title, default_path);
SetupDialogForProperties(dialog, properties);
int chosen = RunModalDialog(dialog, parent_window);
if (chosen == NSFileHandlingPanelCancelButton)
return false;
ReadDialogPaths(dialog, paths);
return true;
}
bool ShowSaveDialog(atom::NativeWindow* window,
void ShowOpenDialog(atom::NativeWindow* parent_window,
const std::string& title,
const base::FilePath& default_path,
int properties,
const OpenDialogCallback& c) {
NSOpenPanel* dialog = [NSOpenPanel openPanel];
SetupDialog(dialog, title, default_path);
SetupDialogForProperties(dialog, properties);
// Duplicate the callback object here since c is a reference and gcd would
// only store the pointer, by duplication we can force gcd to store a copy.
__block OpenDialogCallback callback = c;
NSWindow* window = parent_window ? parent_window->GetNativeWindow() : NULL;
[dialog beginSheetModalForWindow:window
completionHandler:^(NSInteger chosen) {
if (chosen == NSFileHandlingPanelCancelButton) {
callback.Run(false, std::vector<base::FilePath>());
} else {
std::vector<base::FilePath> paths;
ReadDialogPaths(dialog, &paths);
callback.Run(true, paths);
}
}];
}
bool ShowSaveDialog(atom::NativeWindow* parent_window,
const std::string& title,
const base::FilePath& default_path,
base::FilePath* path) {
DCHECK(window);
DCHECK(path);
NSSavePanel* dialog = [NSSavePanel savePanel];
SetupDialog(dialog, title, default_path);
[dialog setCanSelectHiddenExtension:YES];
int chosen = RunModalDialog(dialog, parent_window);
if (chosen == NSFileHandlingPanelCancelButton || ![[dialog URL] isFileURL])
return false;
__block bool result = false;
__block base::FilePath ret_path;
[dialog beginSheetModalForWindow:window->GetNativeWindow()
*path = base::FilePath(base::SysNSStringToUTF8([[dialog URL] path]));
return true;
}
void ShowSaveDialog(atom::NativeWindow* parent_window,
const std::string& title,
const base::FilePath& default_path,
const SaveDialogCallback& c) {
NSSavePanel* dialog = [NSSavePanel savePanel];
SetupDialog(dialog, title, default_path);
__block SaveDialogCallback callback = c;
NSWindow* window = parent_window ? parent_window->GetNativeWindow() : NULL;
[dialog beginSheetModalForWindow:window
completionHandler:^(NSInteger chosen) {
if (chosen == NSFileHandlingPanelCancelButton ||
![[dialog URL] isFileURL]) {
result = false;
if (chosen == NSFileHandlingPanelCancelButton) {
callback.Run(false, base::FilePath());
} else {
result = true;
ret_path = base::FilePath(base::SysNSStringToUTF8([[dialog URL] path]));
std::string path = base::SysNSStringToUTF8([[dialog URL] path]);
callback.Run(true, base::FilePath(path));
}
[NSApp stopModal];
}];
[NSApp runModalForWindow:window->GetNativeWindow()];
*path = ret_path;
return result;
}
} // namespace file_dialog

View File

@@ -4,29 +4,25 @@
#include "browser/ui/file_dialog.h"
#include <atlbase.h>
#include <windows.h>
#include <commdlg.h>
#include <shlobj.h>
#include "base/file_util.h"
#include "base/i18n/case_conversion.h"
#include "base/string_util.h"
#include "base/strings/string_util.h"
#include "base/strings/string_split.h"
#include "base/utf_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/registry.h"
#include "base/win/windows_version.h"
#include "browser/native_window.h"
#include "third_party/wtl/include/atlapp.h"
#include "third_party/wtl/include/atldlgs.h"
namespace file_dialog {
namespace {
// Given |extension|, if it's not empty, then remove the leading dot.
std::wstring GetExtensionWithoutLeadingDot(const std::wstring& extension) {
DCHECK(extension.empty() || extension[0] == L'.');
return extension.empty() ? extension : extension.substr(1);
}
// Distinguish directories from regular files.
bool IsDirectory(const base::FilePath& path) {
base::PlatformFileInfo file_info;
@@ -67,26 +63,21 @@ static bool GetRegistryDescriptionFromExtension(const std::wstring& file_ext,
// If a description is not provided for a file extension, it will be retrieved
// from the registry. If the file extension does not exist in the registry, it
// will be omitted from the filter, as it is likely a bogus extension.
std::wstring FormatFilterForExtensions(
const std::vector<std::wstring>& file_ext,
const std::vector<std::wstring>& ext_desc,
bool include_all_files) {
const std::wstring all_ext = L"*.*";
// TODO(zcbenz): Should be localized.
const std::wstring all_desc = L"All Files";
void FormatFilterForExtensions(
std::vector<std::wstring>* file_ext,
std::vector<std::wstring>* ext_desc,
bool include_all_files,
std::vector<COMDLG_FILTERSPEC>* file_types) {
DCHECK(file_ext->size() >= ext_desc->size());
DCHECK(file_ext.size() >= ext_desc.size());
if (file_ext.empty())
if (file_ext->empty())
include_all_files = true;
std::wstring result;
for (size_t i = 0; i < file_ext.size(); ++i) {
std::wstring ext = file_ext[i];
for (size_t i = 0; i < file_ext->size(); ++i) {
std::wstring ext = (*file_ext)[i];
std::wstring desc;
if (i < ext_desc.size())
desc = ext_desc[i];
if (i < ext_desc->size())
desc = (*ext_desc)[i];
if (ext.empty()) {
// Force something reasonable to appear in the dialog box if there is no
@@ -114,231 +105,214 @@ std::wstring FormatFilterForExtensions(
// the we create a description "QQQ File (.qqq)").
include_all_files = true;
// TODO(zcbenz): should be localized.
desc = base::i18n::ToUpper(WideToUTF16(ext_name)) + L" File (."
+ ext_name
+ L")";
desc = base::i18n::ToUpper(WideToUTF16(ext_name)) + L" File";
}
if (desc.empty())
desc = L"*." + ext_name;
desc += L" (*." + ext_name + L")";
// Store the description.
ext_desc->push_back(desc);
}
result.append(desc.c_str(), desc.size() + 1); // Append NULL too.
result.append(ext.c_str(), ext.size() + 1);
COMDLG_FILTERSPEC spec = { (*ext_desc)[i].c_str(), (*file_ext)[i].c_str() };
file_types->push_back(spec);
}
if (include_all_files) {
result.append(all_desc.c_str(), all_desc.size() + 1);
result.append(all_ext.c_str(), all_ext.size() + 1);
}
// TODO(zcbenz): Should be localized.
ext_desc->push_back(L"All Files (*.*)");
file_ext->push_back(L"*.*");
result.append(1, '\0'); // Double NULL required.
return result;
COMDLG_FILTERSPEC spec = {
(*ext_desc)[ext_desc->size() - 1].c_str(),
(*file_ext)[file_ext->size() - 1].c_str(),
};
file_types->push_back(spec);
}
}
// This function takes the output of a SaveAs dialog: a filename, a filter and
// the extension originally suggested to the user (shown in the dialog box) and
// returns back the filename with the appropriate extension tacked on. If the
// user requests an unknown extension and is not using the 'All files' filter,
// the suggested extension will be appended, otherwise we will leave the
// filename unmodified. |filename| should contain the filename selected in the
// SaveAs dialog box and may include the path, |filter_selected| should be
// '*.something', for example '*.*' or it can be blank (which is treated as
// *.*). |suggested_ext| should contain the extension without the dot (.) in
// front, for example 'jpg'.
std::wstring AppendExtensionIfNeeded(
const std::wstring& filename,
const std::wstring& filter_selected,
const std::wstring& suggested_ext) {
DCHECK(!filename.empty());
std::wstring return_value = filename;
// Generic class to delegate common open/save dialog's behaviours, users need to
// call interface methods via GetPtr().
template <typename T>
class FileDialog {
public:
FileDialog(const base::FilePath& default_path,
const std::string title,
int options,
const std::vector<std::wstring>& file_ext,
const std::vector<std::wstring>& desc_ext)
: file_ext_(file_ext),
desc_ext_(desc_ext) {
std::vector<COMDLG_FILTERSPEC> filters;
FormatFilterForExtensions(&file_ext_, &desc_ext_, true, &filters);
// If we wanted a specific extension, but the user's filename deleted it or
// changed it to something that the system doesn't understand, re-append.
// Careful: Checking net::GetMimeTypeFromExtension() will only find
// extensions with a known MIME type, which many "known" extensions on Windows
// don't have. So we check directly for the "known extension" registry key.
std::wstring file_extension(
GetExtensionWithoutLeadingDot(base::FilePath(filename).Extension()));
std::wstring key(L"." + file_extension);
if (!(filter_selected.empty() || filter_selected == L"*.*") &&
!base::win::RegKey(HKEY_CLASSES_ROOT, key.c_str(), KEY_READ).Valid() &&
file_extension != suggested_ext) {
if (return_value[return_value.length() - 1] != L'.')
return_value.append(L".");
return_value.append(suggested_ext);
std::wstring file_part;
if (!IsDirectory(default_path))
file_part = default_path.BaseName().value();
dialog_.reset(new T(
file_part.c_str(),
options,
NULL,
filters.data(),
filters.size()));
if (!title.empty())
GetPtr()->SetTitle(UTF8ToUTF16(title).c_str());
SetDefaultFolder(default_path);
}
// Strip any trailing dots, which Windows doesn't allow.
size_t index = return_value.find_last_not_of(L'.');
if (index < return_value.size() - 1)
return_value.resize(index + 1);
return return_value;
}
// Enforce visible dialog box.
UINT_PTR CALLBACK SaveAsDialogHook(HWND dialog, UINT message,
WPARAM wparam, LPARAM lparam) {
static const UINT kPrivateMessage = 0x2F3F;
switch (message) {
case WM_INITDIALOG: {
// Do nothing here. Just post a message to defer actual processing.
PostMessage(dialog, kPrivateMessage, 0, 0);
return TRUE;
}
case kPrivateMessage: {
// The dialog box is the parent of the current handle.
HWND real_dialog = GetParent(dialog);
// Retrieve the final size.
RECT dialog_rect;
GetWindowRect(real_dialog, &dialog_rect);
// Verify that the upper left corner is visible.
POINT point = { dialog_rect.left, dialog_rect.top };
HMONITOR monitor1 = MonitorFromPoint(point, MONITOR_DEFAULTTONULL);
point.x = dialog_rect.right;
point.y = dialog_rect.bottom;
// Verify that the lower right corner is visible.
HMONITOR monitor2 = MonitorFromPoint(point, MONITOR_DEFAULTTONULL);
if (monitor1 && monitor2)
return 0;
// Some part of the dialog box is not visible, fix it by moving is to the
// client rect position of the browser window.
HWND parent_window = GetParent(real_dialog);
if (!parent_window)
return 0;
WINDOWINFO parent_info;
parent_info.cbSize = sizeof(WINDOWINFO);
GetWindowInfo(parent_window, &parent_info);
SetWindowPos(real_dialog, NULL,
parent_info.rcClient.left,
parent_info.rcClient.top,
0, 0, // Size.
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE |
SWP_NOZORDER);
return 0;
}
bool Show(atom::NativeWindow* parent_window) {
HWND window = parent_window ? parent_window->GetNativeWindow() : NULL;
return dialog_->DoModal(window) == IDOK;
}
return 0;
}
T* GetDialog() { return dialog_.get(); }
IFileDialog* GetPtr() const { return dialog_->GetPtr(); }
const std::vector<std::wstring> file_ext() const { return file_ext_; }
private:
// Set up the initial directory for the dialog.
void SetDefaultFolder(const base::FilePath file_path) {
std::wstring directory = IsDirectory(file_path) ?
file_path.value() :
file_path.DirName().value();
ATL::CComPtr<IShellItem> folder_item;
HRESULT hr = SHCreateItemFromParsingName(directory.c_str(),
NULL,
IID_PPV_ARGS(&folder_item));
if (SUCCEEDED(hr))
GetPtr()->SetDefaultFolder(folder_item);
}
scoped_ptr<T> dialog_;
std::vector<std::wstring> file_ext_;
std::vector<std::wstring> desc_ext_;
std::vector<COMDLG_FILTERSPEC> filters_;
DISALLOW_COPY_AND_ASSIGN(FileDialog);
};
} // namespace
bool ShowOpenDialog(const std::string& title,
bool ShowOpenDialog(atom::NativeWindow* parent_window,
const std::string& title,
const base::FilePath& default_path,
int properties,
std::vector<base::FilePath>* paths) {
return false;
}
int options = FOS_FORCEFILESYSTEM | FOS_FILEMUSTEXIST;
if (properties & FILE_DIALOG_OPEN_DIRECTORY)
options |= FOS_PICKFOLDERS;
if (properties & FILE_DIALOG_MULTI_SELECTIONS)
options |= FOS_ALLOWMULTISELECT;
bool ShowSaveDialog(atom::NativeWindow* window,
const std::string& title,
const base::FilePath& default_path,
base::FilePath* path) {
std::wstring file_ext = default_path.Extension().insert(0, L"*");
std::wstring filter = FormatFilterForExtensions(
std::vector<std::wstring>(1, file_ext),
FileDialog<CShellFileOpenDialog> open_dialog(
default_path,
title,
options,
std::vector<std::wstring>(),
true);
std::wstring file_part = default_path.BaseName().value();
// If the default_path is a root directory, file_part will be '\', and the
// call to GetSaveFileName below will fail.
if (file_part.size() == 1 && file_part[0] == L'\\')
file_part.clear();
// The size of the in/out buffer in number of characters we pass to win32
// GetSaveFileName. From MSDN "The buffer must be large enough to store the
// path and file name string or strings, including the terminating NULL
// character. ... The buffer should be at least 256 characters long.".
// _IsValidPathComDlg does a copy expecting at most MAX_PATH, otherwise will
// result in an error of FNERR_INVALIDFILENAME. So we should only pass the
// API a buffer of at most MAX_PATH.
wchar_t file_name[MAX_PATH];
base::wcslcpy(file_name, file_part.c_str(), arraysize(file_name));
OPENFILENAME save_as;
// We must do this otherwise the ofn's FlagsEx may be initialized to random
// junk in release builds which can cause the Places Bar not to show up!
ZeroMemory(&save_as, sizeof(save_as));
save_as.lStructSize = sizeof(OPENFILENAME);
save_as.hwndOwner = window->GetNativeWindow();
save_as.hInstance = NULL;
save_as.lpstrFilter = filter.empty() ? NULL : filter.c_str();
save_as.lpstrCustomFilter = NULL;
save_as.nMaxCustFilter = 0;
save_as.nFilterIndex = 1;
save_as.lpstrFile = file_name;
save_as.nMaxFile = arraysize(file_name);
save_as.lpstrFileTitle = NULL;
save_as.nMaxFileTitle = 0;
// Set up the initial directory for the dialog.
std::wstring directory;
if (IsDirectory(default_path)) {
directory = default_path.value();
file_part.clear();
} else {
directory = default_path.DirName().value();
}
save_as.lpstrInitialDir = directory.c_str();
save_as.lpstrTitle = NULL;
save_as.Flags = OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_ENABLESIZING |
OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST;
save_as.lpstrDefExt = NULL; // default extension, ignored for now.
save_as.lCustData = NULL;
if (base::win::GetVersion() < base::win::VERSION_VISTA) {
// The save as on Windows XP remembers its last position,
// and if the screen resolution changed, it will be off screen.
save_as.Flags |= OFN_ENABLEHOOK;
save_as.lpfnHook = &SaveAsDialogHook;
}
// Must be NULL or 0.
save_as.pvReserved = NULL;
save_as.dwReserved = 0;
if (!GetSaveFileName(&save_as)) {
// Zero means the dialog was closed, otherwise we had an error.
DWORD error_code = CommDlgExtendedError();
if (error_code != 0) {
NOTREACHED() << "GetSaveFileName failed with code: " << error_code;
}
std::vector<std::wstring>());
if (!open_dialog.Show(parent_window))
return false;
ATL::CComPtr<IShellItemArray> items;
HRESULT hr = static_cast<IFileOpenDialog*>(open_dialog.GetPtr())->GetResults(
&items);
if (FAILED(hr))
return false;
ATL::CComPtr<IShellItem> item;
DWORD count = 0;
hr = items->GetCount(&count);
if (FAILED(hr))
return false;
paths->reserve(count);
for (DWORD i = 0; i < count; ++i) {
hr = items->GetItemAt(i, &item);
if (FAILED(hr))
return false;
wchar_t file_name[MAX_PATH];
hr = CShellFileOpenDialog::GetFileNameFromShellItem(
item, SIGDN_FILESYSPATH, file_name, MAX_PATH);
if (FAILED(hr))
return false;
paths->push_back(base::FilePath(file_name));
}
// Return the user's choice.
*path = base::FilePath();
// Figure out what filter got selected from the vector with embedded nulls.
// NOTE: The filter contains a string with embedded nulls, such as:
// JPG Image\0*.jpg\0All files\0*.*\0\0
// The filter index is 1-based index for which pair got selected. So, using
// the example above, if the first index was selected we need to skip 1
// instance of null to get to "*.jpg".
std::vector<std::wstring> filters;
if (!filter.empty() && save_as.nFilterIndex > 0)
base::SplitString(filter, '\0', &filters);
std::wstring filter_selected;
if (!filters.empty())
filter_selected = filters[(2 * (save_as.nFilterIndex - 1)) + 1];
// Get the extension that was suggested to the user (when the Save As dialog
// was opened).
std::wstring suggested_ext =
GetExtensionWithoutLeadingDot(default_path.Extension());
*path = base::FilePath(AppendExtensionIfNeeded(
save_as.lpstrFile, filter_selected, suggested_ext));
return true;
}
void ShowOpenDialog(atom::NativeWindow* parent_window,
const std::string& title,
const base::FilePath& default_path,
int properties,
const OpenDialogCallback& callback) {
std::vector<base::FilePath> paths;
bool result = ShowOpenDialog(parent_window,
title,
default_path,
properties,
&paths);
callback.Run(result, paths);
}
bool ShowSaveDialog(atom::NativeWindow* parent_window,
const std::string& title,
const base::FilePath& default_path,
base::FilePath* path) {
// TODO(zcbenz): Accept custom filters from caller.
std::vector<std::wstring> file_ext;
std::wstring extension = default_path.Extension();
if (!extension.empty())
file_ext.push_back(extension.insert(0, L"*"));
FileDialog<CShellFileSaveDialog> save_dialog(
default_path,
title,
FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT,
file_ext,
std::vector<std::wstring>());
if (!save_dialog.Show(parent_window))
return false;
wchar_t file_name[MAX_PATH];
HRESULT hr = save_dialog.GetDialog()->GetFilePath(file_name, MAX_PATH);
if (FAILED(hr))
return false;
// Append extension according to selected filter.
UINT filter_index = 1;
save_dialog.GetPtr()->GetFileTypeIndex(&filter_index);
std::wstring selected_filter = save_dialog.file_ext()[filter_index - 1];
if (selected_filter != L"*.*") {
std::wstring result = file_name;
if (!EndsWith(result, selected_filter.substr(1), false)) {
if (result[result.length() - 1] != L'.')
result.push_back(L'.');
result.append(selected_filter.substr(2));
*path = base::FilePath(result);
return true;
}
}
*path = base::FilePath(file_name);
return true;
}
void ShowSaveDialog(atom::NativeWindow* parent_window,
const std::string& title,
const base::FilePath& default_path,
const SaveDialogCallback& callback) {
base::FilePath path;
bool result = ShowSaveDialog(parent_window, title, default_path, &path);
callback.Run(result, path);
}
} // namespace file_dialog

View File

@@ -8,6 +8,8 @@
#include <string>
#include <vector>
#include "base/callback_forward.h"
namespace atom {
class NativeWindow;
@@ -18,6 +20,8 @@ enum MessageBoxType {
MESSAGE_BOX_TYPE_WARNING
};
typedef base::Callback<void(int code)> MessageBoxCallback;
int ShowMessageBox(NativeWindow* parent_window,
MessageBoxType type,
const std::vector<std::string>& buttons,
@@ -25,6 +29,14 @@ int ShowMessageBox(NativeWindow* parent_window,
const std::string& message,
const std::string& detail);
void ShowMessageBox(NativeWindow* parent_window,
MessageBoxType type,
const std::vector<std::string>& buttons,
const std::string& title,
const std::string& message,
const std::string& detail,
const MessageBoxCallback& callback);
} // namespace atom
#endif // BROWSER_UI_MESSAGE_BOX_H_

View File

@@ -6,20 +6,53 @@
#import <Cocoa/Cocoa.h>
#include "base/callback.h"
#include "base/strings/sys_string_conversions.h"
#include "browser/native_window.h"
#include "browser/ui/nsalert_synchronous_sheet_mac.h"
@interface ModalDelegate : NSObject {
@private
atom::MessageBoxCallback callback_;
NSAlert* alert_;
}
- (id)initWithCallback:(const atom::MessageBoxCallback&)callback
andAlert:(NSAlert*)alert;
@end
@implementation ModalDelegate
- (id)initWithCallback:(const atom::MessageBoxCallback&)callback
andAlert:(NSAlert*)alert {
if ((self = [super init])) {
callback_ = callback;
alert_ = alert;
}
return self;
}
- (void)alertDidEnd:(NSAlert*)alert
returnCode:(NSInteger)returnCode
contextInfo:(void*)contextInfo {
callback_.Run(returnCode);
[alert_ release];
[self release];
}
@end
namespace atom {
int ShowMessageBox(NativeWindow* parent_window,
MessageBoxType type,
const std::vector<std::string>& buttons,
const std::string& title,
const std::string& message,
const std::string& detail) {
namespace {
NSAlert* CreateNSAlert(NativeWindow* parent_window,
MessageBoxType type,
const std::vector<std::string>& buttons,
const std::string& title,
const std::string& message,
const std::string& detail) {
// Ignore the title; it's the window title on other platforms and ignorable.
NSAlert* alert = [[[NSAlert alloc] init] autorelease];
NSAlert* alert = [[NSAlert alloc] init];
[alert setMessageText:base::SysUTF8ToNSString(message)];
[alert setInformativeText:base::SysUTF8ToNSString(detail)];
@@ -40,10 +73,44 @@ int ShowMessageBox(NativeWindow* parent_window,
[button setTag:i];
}
return alert;
}
} // namespace
int ShowMessageBox(NativeWindow* parent_window,
MessageBoxType type,
const std::vector<std::string>& buttons,
const std::string& title,
const std::string& message,
const std::string& detail) {
NSAlert* alert = CreateNSAlert(
parent_window, type, buttons, title, message, detail);
[alert autorelease];
if (parent_window)
return [alert runModalSheetForWindow:parent_window->GetNativeWindow()];
else
return [alert runModal];
}
void ShowMessageBox(NativeWindow* parent_window,
MessageBoxType type,
const std::vector<std::string>& buttons,
const std::string& title,
const std::string& message,
const std::string& detail,
const MessageBoxCallback& callback) {
NSAlert* alert = CreateNSAlert(
parent_window, type, buttons, title, message, detail);
ModalDelegate* delegate = [[ModalDelegate alloc] initWithCallback:callback
andAlert:alert];
NSWindow* window = parent_window ? parent_window->GetNativeWindow() : nil;
[alert beginSheetModalForWindow:window
modalDelegate:delegate
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
contextInfo:nil];
}
} // namespace atom

View File

@@ -4,10 +4,11 @@
#include "browser/ui/message_box.h"
#include "base/message_loop.h"
#include "base/callback.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "browser/native_window.h"
#include "skia/ext/skia_utils_win.h"
#include "ui/views/controls/button/label_button.h"
@@ -38,7 +39,14 @@ class MessageDialog : public base::MessageLoop::Dispatcher,
const std::string& detail);
virtual ~MessageDialog();
int result() const { return result_; }
void Show();
int GetResult() const;
void set_callback(const MessageBoxCallback& callback) {
delete_on_close_ = true;
callback_ = callback;
}
private:
// Overridden from MessageLoop::Dispatcher:
@@ -63,11 +71,13 @@ class MessageDialog : public base::MessageLoop::Dispatcher,
const ui::Event& event) OVERRIDE;
bool should_close_;
bool delete_on_close_;
int result_;
string16 title_;
views::Widget* widget_;
views::MessageBoxView* message_box_view_;
std::vector<views::LabelButton*> buttons_;
MessageBoxCallback callback_;
DISALLOW_COPY_AND_ASSIGN(MessageDialog);
};
@@ -82,6 +92,7 @@ MessageDialog::MessageDialog(NativeWindow* parent_window,
const std::string& message,
const std::string& detail)
: should_close_(false),
delete_on_close_(false),
result_(-1),
title_(UTF8ToUTF16(title)),
widget_(NULL),
@@ -124,12 +135,30 @@ MessageDialog::MessageDialog(NativeWindow* parent_window,
set_background(views::Background::CreateSolidBackground(
skia::COLORREFToSkColor(GetSysColor(COLOR_WINDOW))));
widget_->Show();
}
MessageDialog::~MessageDialog() {
}
void MessageDialog::Show() {
widget_->Show();
}
int MessageDialog::GetResult() const {
// When the dialog is closed without choosing anything, we think the user
// chose 'Cancel', otherwise we think the default behavior is chosen.
if (result_ == -1) {
for (size_t i = 0; i < buttons_.size(); ++i)
if (LowerCaseEqualsASCII(buttons_[i]->GetText(), "cancel")) {
return i;
}
return 0;
} else {
return result_;
}
}
////////////////////////////////////////////////////////////////////////////////
// MessageDialog, private:
@@ -145,6 +174,11 @@ string16 MessageDialog::GetWindowTitle() const {
void MessageDialog::WindowClosing() {
should_close_ = true;
if (delete_on_close_) {
callback_.Run(GetResult());
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
}
}
views::Widget* MessageDialog::GetWidget() {
@@ -232,6 +266,7 @@ int ShowMessageBox(NativeWindow* parent_window,
const std::string& message,
const std::string& detail) {
MessageDialog dialog(parent_window, type, buttons, title, message, detail);
dialog.Show();
{
base::MessageLoop::ScopedNestableTaskAllower allow(
base::MessageLoopForUI::current());
@@ -239,18 +274,21 @@ int ShowMessageBox(NativeWindow* parent_window,
run_loop.Run();
}
// When the dialog is closed without choosing anything, we think the user
// chose 'Cancel', otherwise we think the default behavior is chosen.
if (dialog.result() == -1) {
for (size_t i = 0; i < buttons.size(); ++i)
if (LowerCaseEqualsASCII(buttons[i], "cancel")) {
return i;
}
return dialog.GetResult();
}
return 0;
} else {
return dialog.result();
}
void ShowMessageBox(NativeWindow* parent_window,
MessageBoxType type,
const std::vector<std::string>& buttons,
const std::string& title,
const std::string& message,
const std::string& detail,
const MessageBoxCallback& callback) {
// The dialog would be deleted when the dialog is closed.
MessageDialog* dialog = new MessageDialog(
parent_window, type, buttons, title, message, detail);
dialog->set_callback(callback);
dialog->Show();
}
} // namespace atom

View File

@@ -77,6 +77,7 @@ class Menu2 {
// Accessors.
ui::MenuModel* model() const { return model_; }
NativeMenuWin* wrapper() const { return wrapper_.get(); }
// Sets the minimum width of the menu.
void SetMinimumWidth(int width);

View File

@@ -8,22 +8,22 @@
#include "base/bind.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/message_loop/message_loop.h"
#include "base/stl_util.h"
#include "base/string_util.h"
#include "base/strings/string_util.h"
#include "base/win/wrapped_window_proc.h"
#include "browser/ui/win/menu_2.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/keycodes/keyboard_codes.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/l10n/l10n_util_win.h"
#include "ui/base/models/menu_model.h"
#include "ui/base/win/hwnd_util.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/font.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/win/hwnd_util.h"
#include "ui/native_theme/native_theme.h"
#include "ui/native_theme/native_theme_win.h"
#include "ui/views/controls/menu/menu_config.h"
@@ -84,14 +84,28 @@ class NativeMenuWin::MenuHostWindow {
RegisterClass();
hwnd_ = CreateWindowEx(l10n_util::GetExtendedStyles(), kWindowClassName,
L"", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
ui::CheckWindowCreated(hwnd_);
ui::SetWindowUserData(hwnd_, this);
gfx::CheckWindowCreated(hwnd_);
gfx::SetWindowUserData(hwnd_, this);
}
~MenuHostWindow() {
DestroyWindow(hwnd_);
}
// Called when the user selects a specific item.
void OnMenuCommand(int position, HMENU menu) {
NativeMenuWin* menu_win = GetNativeMenuWinFromHMENU(menu);
ui::MenuModel* model = menu_win->model_;
NativeMenuWin* root_menu = menu_win;
while (root_menu->parent_)
root_menu = root_menu->parent_;
// Only notify the model if it didn't already send out notification.
// See comment in MenuMessageHook for details.
if (root_menu->menu_action_ == MENU_ACTION_NONE)
model->ActivatedAt(position);
}
HWND hwnd() const { return hwnd_; }
private:
@@ -146,20 +160,6 @@ class NativeMenuWin::MenuHostWindow {
return reinterpret_cast<NativeMenuWin::ItemData*>(item_data);
}
// Called when the user selects a specific item.
void OnMenuCommand(int position, HMENU menu) {
NativeMenuWin* menu_win = GetNativeMenuWinFromHMENU(menu);
ui::MenuModel* model = menu_win->model_;
NativeMenuWin* root_menu = menu_win;
while (root_menu->parent_)
root_menu = root_menu->parent_;
// Only notify the model if it didn't already send out notification.
// See comment in MenuMessageHook for details.
if (root_menu->menu_action_ == MENU_ACTION_NONE)
model->ActivatedAt(position);
}
// Called as the user moves their mouse or arrows through the contents of the
// menu.
void OnMenuSelect(WPARAM w_param, HMENU menu) {
@@ -353,7 +353,7 @@ class NativeMenuWin::MenuHostWindow {
WPARAM w_param,
LPARAM l_param) {
MenuHostWindow* host =
reinterpret_cast<MenuHostWindow*>(ui::GetWindowUserData(window));
reinterpret_cast<MenuHostWindow*>(gfx::GetWindowUserData(window));
// host is null during initial construction.
LRESULT l_result = 0;
if (!host || !host->ProcessWindowMessage(window, message, w_param, l_param,
@@ -529,6 +529,10 @@ void NativeMenuWin::SetMinimumWidth(int width) {
NOTIMPLEMENTED();
}
void NativeMenuWin::OnMenuCommand(int position, HMENU menu) {
host_window_->OnMenuCommand(position, menu);
}
////////////////////////////////////////////////////////////////////////////////
// NativeMenuWin, private:

View File

@@ -13,7 +13,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/string16.h"
#include "base/strings/string16.h"
namespace gfx {
class Point;
@@ -56,6 +56,9 @@ class NativeMenuWin {
void RemoveMenuListener(views::MenuListener* listener);
void SetMinimumWidth(int width);
// Called by user to generate a menu command event.
void OnMenuCommand(int position, HMENU menu);
// Flag to create a window menu instead of popup menu.
void set_create_as_window_menu(bool flag) { create_as_window_menu_ = flag; }
bool create_as_window_menu() const { return create_as_window_menu_; }

View File

@@ -4,10 +4,16 @@
'conditions': [
['OS=="mac"', {
'clang': 1,
'mac_sdk%': '<!(python tools/mac/find_sdk.py 10.8)',
}],
['OS=="win" and (MSVS_VERSION=="2012e" or MSVS_VERSION=="2010e")', {
'msvs_express': 1,
'windows_driver_kit_path%': 'C:/WinDDK/7600.16385.1',
},{
'msvs_express': 0,
}],
],
# Reflects node's config.gypi.
'component%': 'static_library',
'python': 'python',
'node_install_npm': 'false',
'node_prefix': '',
@@ -24,11 +30,12 @@
'node_use_openssl': 'true',
'node_use_perfctr': 'false',
'node_use_systemtap': 'false',
'v8_postmortem_support': 'false',
},
# Settings to compile node under Windows.
'target_defaults': {
'target_conditions': [
['_target_name in ["libuv", "http_parser", "cares", "openssl", "node", "zlib"]', {
['_target_name in ["libuv", "http_parser", "cares", "openssl", "node_lib", "zlib"]', {
'msvs_disabled_warnings': [
4013, # 'free' undefined; assuming extern returning int
4054, #
@@ -36,6 +43,7 @@
4189, #
4131, # uses old-style declarator
4133, # incompatible types
4146, # unary minus operator applied to unsigned type, result still unsigned
4152, # function/data pointer conversion in expression
4206, # translation unit is empty
4204, # non-constant aggregate initializer
@@ -46,6 +54,7 @@
4505, # unreferenced local function has been removed
4701, # potentially uninitialized local variable 'sizew' used
4706, # assignment within conditional expression
4804, # unsafe use of type 'bool' in operation
4996, #
],
'msvs_settings': {
@@ -54,7 +63,41 @@
},
},
'xcode_settings': {
'GCC_TREAT_WARNINGS_AS_ERRORS': 'NO'
'GCC_TREAT_WARNINGS_AS_ERRORS': 'NO',
'WARNING_CFLAGS': [
'-Wno-parentheses-equality',
'-Wno-unused-function',
'-Wno-sometimes-uninitialized',
'-Wno-pointer-sign',
'-Wno-string-plus-int',
'-Wno-unused-variable',
'-Wno-deprecated-declarations',
'-Wno-return-type',
],
},
}],
['_target_name in ["node_lib", "atom_lib"]', {
'include_dirs': [
'vendor/brightray/vendor/download/libchromiumcontent/src/v8/include',
],
}],
['_target_name=="libuv"', {
'conditions': [
['OS=="win"', {
# Expose libuv's symbols.
'defines': [
'BUILDING_UV_SHARED=1',
],
}], # OS=="win"
],
}],
['_target_name.startswith("breakpad") or _target_name in ["crash_report_sender", "dump_syms"]', {
'xcode_settings': {
'WARNING_CFLAGS': [
'-Wno-deprecated-declarations',
'-Wno-unused-private-field',
'-Wno-unused-function',
],
},
}],
],
@@ -67,6 +110,12 @@
4819, # The file contains a character that cannot be represented in the current code page
],
'msvs_settings': {
'VCCLCompilerTool': {
# Programs that use the Standard C++ library must be compiled with C++
# exception handling enabled.
# http://support.microsoft.com/kb/154419
'ExceptionHandling': 1,
},
'VCLinkerTool': {
'AdditionalOptions': [
# ATL 8.0 included in WDK 7.1 makes the linker to generate following
@@ -86,6 +135,9 @@
],
},
},
'xcode_settings': {
'DEBUG_INFORMATION_FORMAT': 'dwarf-with-dsym',
},
},
'conditions': [
# Settings to compile with clang under OS X.
@@ -112,20 +164,44 @@
'-fcolor-diagnostics',
],
'SDKROOT': 'macosx<(mac_sdk)', # -isysroot
'GCC_C_LANGUAGE_STANDARD': 'c99', # -std=c99
},
},
}], # clang==1
# Windows specific settings.
# Using Visual Studio Express.
['msvs_express==1', {
'target_defaults': {
'defines!': [
'_SECURE_ATL',
],
'msvs_settings': {
'VCLibrarianTool': {
'AdditionalLibraryDirectories': [
'<(windows_driver_kit_path)/lib/ATL/i386',
],
},
'VCLinkerTool': {
'AdditionalLibraryDirectories': [
'<(windows_driver_kit_path)/lib/ATL/i386',
],
'AdditionalDependencies': [
'atlthunk.lib',
],
},
},
'msvs_system_include_dirs': [
'<(windows_driver_kit_path)/inc/atl71',
'<(windows_driver_kit_path)/inc/mfc42',
],
},
}], # msvs_express==1
# The breakdpad on Windows assumes Debug_x64 and Release_x64 configurations.
['OS=="win"', {
'target_defaults': {
'msvs_settings': {
'VCCLCompilerTool': {
# Programs that use the Standard C++ library must be compiled with C++
# exception handling enabled.
# http://support.microsoft.com/kb/154419
'ExceptionHandling': 1,
'configurations': {
'Debug_x64': {
},
'Release_x64': {
},
},
},

Some files were not shown because too many files have changed in this diff Show More