Compare commits

...

187 Commits

Author SHA1 Message Date
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
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
109 changed files with 2888 additions and 1306 deletions

View File

@@ -2,29 +2,46 @@
// 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 "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 "base/environment.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);
// Attach to the parent console if we've got one so that stdio works
AttachConsole(ATTACH_PARENT_PROCESS);
FILE* dontcare;
freopen_s(&dontcare, "CON", "w", stdout);
freopen_s(&dontcare, "CON", "w", stderr);
freopen_s(&dontcare, "CON", "r", stdin);
scoped_ptr<base::Environment> env(base::Environment::Create());
std::string node_indicator;
if (env->GetVar("ATOM_SHELL_INTERNAL_RUN_AS_NODE", &node_indicator) &&
@@ -74,8 +91,6 @@ 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[]) {
char* node_indicator = getenv("ATOM_SHELL_INTERNAL_RUN_AS_NODE");
if (node_indicator != NULL && strcmp(node_indicator, "1") == 0)
@@ -84,4 +99,4 @@ int main(int argc, const 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

@@ -10,6 +10,7 @@
#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 {

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

View File

@@ -4,6 +4,7 @@
'product_name': 'Atom',
'app_sources': [
'app/atom_main.cc',
'app/atom_main.h',
],
'bundle_sources': [
'browser/mac/atom.icns',
@@ -79,8 +80,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',
@@ -100,6 +99,8 @@
'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',
@@ -108,10 +109,10 @@
'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/cocoa/custom_frame_view.h',
'browser/ui/cocoa/custom_frame_view.mm',
'browser/ui/file_dialog.h',
'browser/ui/file_dialog_mac.mm',
'browser/ui/file_dialog_win.cc',
@@ -155,6 +156,7 @@
'common/platform_util.h',
'common/platform_util_mac.mm',
'common/platform_util_win.cc',
'common/v8_conversions.h',
'common/v8_value_converter_impl.cc',
'common/v8_value_converter_impl.h',
'renderer/api/atom_api_renderer_ipc.cc',
@@ -174,6 +176,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',
],

View File

@@ -7,6 +7,7 @@
#include "base/values.h"
#include "base/command_line.h"
#include "browser/browser.h"
#include "common/v8_conversions.h"
#include "vendor/node/src/node.h"
namespace atom {
@@ -111,14 +112,14 @@ v8::Handle<v8::Value> App::GetVersion(const v8::Arguments &args) {
v8::Handle<v8::Value> App::AppendSwitch(const v8::Arguments &args) {
v8::HandleScope scope;
if (!args[0]->IsString())
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);
}
@@ -130,10 +131,10 @@ v8::Handle<v8::Value> App::AppendSwitch(const v8::Arguments &args) {
v8::Handle<v8::Value> App::AppendArgument(const v8::Arguments &args) {
v8::HandleScope scope;
if (!args[0]->IsString())
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();
@@ -143,7 +144,7 @@ v8::Handle<v8::Value> App::AppendArgument(const v8::Arguments &args) {
// static
v8::Handle<v8::Value> App::DockBounce(const v8::Arguments& args) {
std::string type(*v8::String::Utf8Value(args[0]));
std::string type = FromV8Value(args[0]);
int request_id = -1;
if (type == "critical")
@@ -158,21 +159,20 @@ v8::Handle<v8::Value> App::DockBounce(const v8::Arguments& args) {
// static
v8::Handle<v8::Value> App::DockCancelBounce(const v8::Arguments& args) {
Browser::Get()->DockCancelBounce(args[0]->IntegerValue());
Browser::Get()->DockCancelBounce(FromV8Value(args[0]));
return v8::Undefined();
}
// static
v8::Handle<v8::Value> App::DockSetBadgeText(const v8::Arguments& args) {
std::string label(*v8::String::Utf8Value(args[0]));
Browser::Get()->DockSetBadgeText(label);
Browser::Get()->DockSetBadgeText(FromV8Value(args[0]));
return v8::Undefined();
}
// static
v8::Handle<v8::Value> App::DockGetBadgeText(const v8::Arguments& args) {
std::string text(Browser::Get()->DockGetBadgeText());
return v8::String::New(text.data(), text.size());
return ToV8Value(text);
}
#endif // defined(OS_MACOSX)

View File

@@ -6,6 +6,7 @@
#include "base/values.h"
#include "browser/auto_updater.h"
#include "common/v8_conversions.h"
namespace atom {
@@ -56,7 +57,7 @@ v8::Handle<v8::Value> AutoUpdater::New(const v8::Arguments &args) {
// static
v8::Handle<v8::Value> AutoUpdater::SetFeedURL(const v8::Arguments &args) {
auto_updater::AutoUpdater::SetFeedURL(*v8::String::Utf8Value(args[0]));
auto_updater::AutoUpdater::SetFeedURL(FromV8Value(args[0]));
return v8::Undefined();
}

View File

@@ -6,6 +6,7 @@
#include "base/values.h"
#include "common/api/api_messages.h"
#include "common/v8_conversions.h"
#include "common/v8_value_converter_impl.h"
#include "content/public/browser/render_view_host.h"
#include "vendor/node/src/node.h"
@@ -22,13 +23,11 @@ namespace api {
v8::Handle<v8::Value> BrowserIPC::Send(const v8::Arguments &args) {
v8::HandleScope scope;
if (!args[0]->IsString() || !args[1]->IsNumber() || !args[2]->IsNumber())
string16 channel;
int process_id, routing_id;
if (!FromV8Arguments(args, &channel, &process_id, &routing_id))
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();
RenderViewHost* render_view_host(RenderViewHost::FromID(
process_id, routing_id));
if (!render_view_host)

View File

@@ -5,6 +5,7 @@
#include "browser/api/atom_api_crash_reporter.h"
#include "browser/crash_reporter.h"
#include "common/v8_conversions.h"
#include "vendor/node/src/node.h"
#include "vendor/node/src/node_internals.h"
@@ -14,22 +15,20 @@ 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);
crash_reporter::CrashReporter::SetCompanyName(FromV8Value(args[0]));
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);
crash_reporter::CrashReporter::SetSubmissionURL(FromV8Value(args[0]));
return v8::Undefined();
}
// static
v8::Handle<v8::Value> CrashReporter::SetAutoSubmit(const v8::Arguments &args) {
crash_reporter::CrashReporter::SetAutoSubmit(args[0]->BooleanValue());
crash_reporter::CrashReporter::SetAutoSubmit(FromV8Value(args[0]));
return v8::Undefined();
}

View File

@@ -4,14 +4,14 @@
#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_conversions.h"
#include "vendor/node/src/node_internals.h"
using node::node_isolate;
namespace atom {
@@ -19,14 +19,24 @@ 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(v8::Persistent<v8::Function> callback, T arg) {
DCHECK(!callback.IsEmpty());
v8::HandleScope scope;
v8::Handle<v8::Value> value = ToV8Value(arg);
callback->Call(callback, 1, &value);
callback.Dispose(node_isolate);
}
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(v8::Persistent<v8::Function> 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) {
@@ -42,84 +52,103 @@ void Initialize(v8::Handle<v8::Object> target) {
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
int type;
std::vector<std::string> buttons;
std::string title, message, detail;
if (!FromV8Arguments(args, &type, &buttons, &title, &message, &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");
NativeWindow* native_window = FromV8Value(args[5]);
v8::Persistent<v8::Function> callback = FromV8Value(args[6]);
native_window = window->window();
if (callback.IsEmpty()) {
int chosen = atom::ShowMessageBox(
native_window,
(MessageBoxType)type,
buttons,
title,
message,
detail);
return scope.Close(v8::Integer::New(chosen));
} else {
atom::ShowMessageBox(
native_window,
(MessageBoxType)type,
buttons,
title,
message,
detail,
base::Bind(&CallV8Function<int>, callback));
return v8::Undefined();
}
MessageBoxType type = (MessageBoxType)(args[0]->IntegerValue());
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;
base::FilePath default_path;
int properties;
if (!FromV8Arguments(args, &title, &default_path, &properties))
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[3]);
v8::Persistent<v8::Function> callback = FromV8Value(args[4]);
std::vector<base::FilePath> paths;
if (!file_dialog::ShowOpenDialog(title, default_path, properties, &paths))
if (callback.IsEmpty()) {
std::vector<base::FilePath> paths;
if (!file_dialog::ShowOpenDialog(native_window,
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, ToV8Value(paths[i]));
return scope.Close(result);
} else {
file_dialog::ShowOpenDialog(
native_window,
title,
default_path,
properties,
base::Bind(&CallV8Function2<const std::vector<base::FilePath>&>,
callback));
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);
}
}
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
std::string title;
base::FilePath default_path;
if (!FromV8Arguments(args, &title, &default_path))
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[2]);
v8::Persistent<v8::Function> callback = FromV8Value(args[3]);
std::string title(*v8::String::Utf8Value(args[1]));
base::FilePath default_path(V8ValueToFilePath(args[2]));
if (callback.IsEmpty()) {
base::FilePath path;
if (!file_dialog::ShowSaveDialog(native_window,
title,
default_path,
&path))
return v8::Undefined();
base::FilePath path;
if (!file_dialog::ShowSaveDialog(window->window(),
title,
default_path,
&path))
return scope.Close(ToV8Value(path));
} else {
file_dialog::ShowSaveDialog(
native_window,
title,
default_path,
base::Bind(&CallV8Function2<const base::FilePath&>, callback));
return v8::Undefined();
return scope.Close(FilePathToV8Value(path));
}
}
} // namespace api

View File

@@ -4,6 +4,10 @@
#include "browser/api/atom_api_event.h"
#include "browser/native_window.h"
#include "common/api/api_messages.h"
#include "common/v8_conversions.h"
using node::node_isolate;
namespace atom {
@@ -13,10 +17,14 @@ namespace api {
v8::Persistent<v8::FunctionTemplate> Event::constructor_template_;
Event::Event()
: prevent_default_(false) {
: sender_(NULL),
message_(NULL),
prevent_default_(false) {
}
Event::~Event() {
if (sender_ != NULL)
sender_->RemoveObserver(this);
}
// static
@@ -31,6 +39,8 @@ v8::Handle<v8::Object> Event::CreateV8Object() {
constructor_template_->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);
}
v8::Handle<v8::Object> v8_event =
@@ -39,14 +49,30 @@ v8::Handle<v8::Object> Event::CreateV8Object() {
return scope.Close(v8_event);
}
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
v8::Handle<v8::Value> Event::New(const v8::Arguments& args) {
Event* event = new Event;
event->Wrap(args.This());
return args.This();
}
v8::Handle<v8::Value> Event::PreventDefault(const v8::Arguments &args) {
// static
v8::Handle<v8::Value> Event::PreventDefault(const v8::Arguments& args) {
Event* event = Unwrap<Event>(args.This());
if (event == NULL)
return node::ThrowError("Event is already destroyed");
@@ -56,6 +82,31 @@ v8::Handle<v8::Value> Event::PreventDefault(const v8::Arguments &args) {
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Event::SendReply(const v8::Arguments& 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;
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Event::Destroy(const v8::Arguments& args) {
delete Unwrap<Event>(args.This());
return v8::Undefined();
}
} // namespace api
} // namespace atom

View File

@@ -6,19 +6,32 @@
#define ATOM_BROWSER_ATOM_API_EVENT_H_
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/string16.h"
#include "browser/native_window_observer.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();
// Pass the sender and message to be replied.
void SetSenderAndMessage(NativeWindow* sender, IPC::Message* message);
// Accessor to return handle_, this follows Google C++ Style.
v8::Persistent<v8::Object>& handle() { return handle_; }
@@ -28,12 +41,22 @@ class Event : public node::ObjectWrap {
protected:
Event();
// NativeWindowObserver implementations:
virtual void OnWindowClosed() OVERRIDE;
private:
static v8::Handle<v8::Value> New(const v8::Arguments &args);
static v8::Handle<v8::Value> PreventDefault(const v8::Arguments &args);
static v8::Handle<v8::Value> New(const v8::Arguments& args);
static v8::Handle<v8::Value> PreventDefault(const v8::Arguments& args);
static v8::Handle<v8::Value> SendReply(const v8::Arguments& args);
static v8::Handle<v8::Value> Destroy(const v8::Arguments& args);
static v8::Persistent<v8::FunctionTemplate> constructor_template_;
// Replyer for the synchronous messages.
NativeWindow* sender_;
IPC::Message* message_;
bool prevent_default_;
DISALLOW_COPY_AND_ASSIGN(Event);

View File

@@ -4,8 +4,8 @@
#include "browser/api/atom_api_menu.h"
#include "browser/api/atom_api_window.h"
#include "browser/ui/accelerator_util.h"
#include "common/v8_conversions.h"
#define UNWRAP_MEMNU_AND_CHECK \
Menu* self = ObjectWrap::Unwrap<Menu>(args.This()); \
@@ -18,17 +18,6 @@ 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,
@@ -93,7 +82,7 @@ bool Menu::GetAcceleratorForCommandId(int command_id,
"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);
}
@@ -110,18 +99,18 @@ bool Menu::IsItemForCommandIdDynamic(int command_id) const {
string16 Menu::GetLabelForCommandId(int command_id) const {
v8::HandleScope scope;
return V8ValueToUTF16(CallDelegate(v8::False(),
handle(),
"getLabelForCommandId",
command_id));
return FromV8Value(CallDelegate(v8::False(),
handle(),
"getLabelForCommandId",
command_id));
}
string16 Menu::GetSublabelForCommandId(int command_id) const {
v8::HandleScope scope;
return V8ValueToUTF16(CallDelegate(v8::False(),
handle(),
"getSubLabelForCommandId",
command_id));
return FromV8Value(CallDelegate(v8::False(),
handle(),
"getSubLabelForCommandId",
command_id));
}
void Menu::ExecuteCommand(int command_id, int event_flags) {
@@ -145,16 +134,15 @@ v8::Handle<v8::Value> Menu::New(const v8::Arguments &args) {
v8::Handle<v8::Value> Menu::InsertItem(const v8::Arguments &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]));
self->model_->InsertItemAt(index, command_id, label);
return v8::Undefined();
}
@@ -163,16 +151,15 @@ v8::Handle<v8::Value> Menu::InsertItem(const v8::Arguments &args) {
v8::Handle<v8::Value> Menu::InsertCheckItem(const v8::Arguments &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]));
self->model_->InsertCheckItemAt(index, command_id, label);
return v8::Undefined();
}
@@ -181,21 +168,15 @@ v8::Handle<v8::Value> Menu::InsertCheckItem(const v8::Arguments &args) {
v8::Handle<v8::Value> Menu::InsertRadioItem(const v8::Arguments &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);
self->model_->InsertRadioItemAt(index, command_id, label, group_id);
return v8::Undefined();
}
@@ -204,11 +185,10 @@ v8::Handle<v8::Value> Menu::InsertRadioItem(const v8::Arguments &args) {
v8::Handle<v8::Value> Menu::InsertSeparator(const v8::Arguments &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
@@ -221,25 +201,20 @@ v8::Handle<v8::Value> Menu::InsertSeparator(const v8::Arguments &args) {
v8::Handle<v8::Value> Menu::InsertSubMenu(const v8::Arguments &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());
index, command_id, label, submenu->model_.get());
return v8::Undefined();
}
@@ -248,7 +223,9 @@ v8::Handle<v8::Value> Menu::InsertSubMenu(const v8::Arguments &args) {
v8::Handle<v8::Value> Menu::SetIcon(const v8::Arguments &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.
@@ -260,10 +237,12 @@ v8::Handle<v8::Value> Menu::SetIcon(const v8::Arguments &args) {
v8::Handle<v8::Value> Menu::SetSublabel(const v8::Arguments &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]));
self->model_->SetSublabel(index, label);
return v8::Undefined();
}
@@ -301,14 +280,14 @@ v8::Handle<v8::Value> Menu::GetCommandIdAt(const v8::Arguments &args) {
v8::Handle<v8::Value> Menu::GetLabelAt(const v8::Arguments &args) {
UNWRAP_MEMNU_AND_CHECK;
int index = args[0]->IntegerValue();
return UTF16ToV8Value(self->model_->GetLabelAt(index));
return ToV8Value(self->model_->GetLabelAt(index));
}
// static
v8::Handle<v8::Value> Menu::GetSublabelAt(const v8::Arguments &args) {
UNWRAP_MEMNU_AND_CHECK;
int index = args[0]->IntegerValue();
return UTF16ToV8Value(self->model_->GetSublabelAt(index));
return ToV8Value(self->model_->GetSublabelAt(index));
}
// static
@@ -334,11 +313,11 @@ v8::Handle<v8::Value> Menu::IsVisibleAt(const v8::Arguments &args) {
v8::Handle<v8::Value> Menu::Popup(const v8::Arguments &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());
self->Popup(window);
return v8::Undefined();
}
@@ -372,6 +351,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

@@ -68,7 +68,9 @@ class Menu : public EventEmitter,
static v8::Handle<v8::Value> Popup(const v8::Arguments &args);
#if defined(OS_MACOSX)
#if defined(OS_WIN)
static v8::Handle<v8::Value> AttachToWindow(const v8::Arguments &args);
#elif defined(OS_MACOSX)
static v8::Handle<v8::Value> SetApplicationMenu(const v8::Arguments &args);
static v8::Handle<v8::Value> SendActionToFirstResponder(
const v8::Arguments &args);

View File

@@ -8,6 +8,7 @@
#include "base/mac/scoped_sending_event.h"
#include "base/strings/sys_string_conversions.h"
#include "browser/native_window.h"
#include "common/v8_conversions.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
@@ -95,10 +96,10 @@ v8::Handle<v8::Value> Menu::SendActionToFirstResponder(
const v8::Arguments &args) {
v8::HandleScope scope;
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();

View File

@@ -4,8 +4,11 @@
#include "browser/api/atom_api_menu_win.h"
#include "browser/native_window_win.h"
#include "browser/ui/win/menu_2.h"
#include "common/v8_conversions.h"
#include "ui/gfx/point.h"
#include "ui/gfx/screen.h"
namespace atom {
@@ -19,8 +22,26 @@ 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
v8::Handle<v8::Value> Menu::AttachToWindow(const v8::Arguments& args) {
v8::HandleScope scope;
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());
return v8::Undefined();
}
// static

View File

@@ -7,10 +7,11 @@
#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_conversions.h"
#include "content/public/browser/browser_thread.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "vendor/node/src/node.h"
#include "vendor/node/src/node_internals.h"
@@ -29,13 +30,16 @@ v8::Persistent<v8::Object> g_protocol_object;
typedef std::map<std::string, v8::Persistent<v8::Function>> 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 scope;
v8::Local<v8::Value> argv[] = {
v8::String::New(event.data(), event.size()),
v8::String::New(parameter.data(), parameter.size()),
v8::Handle<v8::Value> argv[] = {
ToV8Value(event),
ToV8Value(parameter),
};
node::MakeCallback(g_protocol_object, "emit", arraysize(argv), argv);
}
@@ -55,10 +59,7 @@ v8::Handle<v8::Object> ConvertURLRequestToV8Object(
// Get the job factory.
AtomURLRequestJobFactory* GetRequestJobFactory() {
return static_cast<AtomURLRequestJobFactory*>(
const_cast<net::URLRequestJobFactory*>(
static_cast<content::BrowserContext*>(AtomBrowserContext::Get())->
GetRequestContext()->GetURLRequestContext()->job_factory()));
return AtomBrowserContext::Get()->url_request_context_getter()->job_factory();
}
class CustomProtocolRequestJob : public AdapterRequestJob {
@@ -83,7 +84,7 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
// Determine the type of the job we are going to create.
if (result->IsString()) {
std::string data = *v8::String::Utf8Value(result);
std::string data = FromV8Value(result);
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
@@ -95,14 +96,12 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
return;
} else if (result->IsObject()) {
v8::Handle<v8::Object> obj = result->ToObject();
std::string name = *v8::String::Utf8Value(obj->GetConstructorName());
std::string name = FromV8Value(obj->GetConstructorName());
if (name == "RequestStringJob") {
std::string mime_type = *v8::String::Utf8Value(obj->Get(
std::string mime_type = FromV8Value(obj->Get(
v8::String::New("mimeType")));
std::string charset = *v8::String::Utf8Value(obj->Get(
v8::String::New("charset")));
std::string data = *v8::String::Utf8Value(obj->Get(
v8::String::New("data")));
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,
@@ -114,8 +113,7 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
data));
return;
} else if (name == "RequestFileJob") {
base::FilePath path = base::FilePath::FromUTF8Unsafe(
*v8::String::Utf8Value(obj->Get(v8::String::New("path"))));
base::FilePath path = FromV8Value(obj->Get(v8::String::New("path")));
content::BrowserThread::PostTask(
content::BrowserThread::IO,
@@ -183,16 +181,20 @@ class CustomProtocolHandler : public ProtocolHandler {
// static
v8::Handle<v8::Value> Protocol::RegisterProtocol(const v8::Arguments& args) {
std::string scheme(*v8::String::Utf8Value(args[0]));
std::string scheme;
v8::Persistent<v8::Function> callback;
if (!FromV8Arguments(args, &scheme, &callback))
return node::ThrowTypeError("Bad argument");
if (g_handlers.find(scheme) != g_handlers.end() ||
net::URLRequest::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.
if (!args[1]->IsFunction())
return node::ThrowError("Handler must be a function");
g_handlers[scheme] = v8::Persistent<v8::Function>::New(
node::node_isolate, v8::Handle<v8::Function>::Cast(args[1]));
g_handlers[scheme] = callback;
content::BrowserThread::PostTask(content::BrowserThread::IO,
FROM_HERE,
@@ -203,7 +205,12 @@ v8::Handle<v8::Value> Protocol::RegisterProtocol(const v8::Arguments& args) {
// static
v8::Handle<v8::Value> Protocol::UnregisterProtocol(const v8::Arguments& args) {
std::string scheme(*v8::String::Utf8Value(args[0]));
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));
@@ -220,24 +227,27 @@ v8::Handle<v8::Value> Protocol::UnregisterProtocol(const v8::Arguments& args) {
// static
v8::Handle<v8::Value> Protocol::IsHandledProtocol(const v8::Arguments& args) {
return v8::Boolean::New(net::URLRequest::IsHandledProtocol(
*v8::String::Utf8Value(args[0])));
return ToV8Value(net::URLRequest::IsHandledProtocol(FromV8Value(args[0])));
}
// static
v8::Handle<v8::Value> Protocol::InterceptProtocol(const v8::Arguments& args) {
std::string scheme(*v8::String::Utf8Value(args[0]));
std::string scheme;
v8::Persistent<v8::Function> 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.
if (!args[1]->IsFunction())
return node::ThrowError("Handler must be a function");
g_handlers[scheme] = v8::Persistent<v8::Function>::New(
node::node_isolate, v8::Handle<v8::Function>::Cast(args[1]));
g_handlers[scheme] = callback;
content::BrowserThread::PostTask(content::BrowserThread::IO,
FROM_HERE,
@@ -247,7 +257,12 @@ v8::Handle<v8::Value> Protocol::InterceptProtocol(const v8::Arguments& args) {
// static
v8::Handle<v8::Value> Protocol::UninterceptProtocol(const v8::Arguments& args) {
std::string scheme(*v8::String::Utf8Value(args[0]));
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));

View File

@@ -6,6 +6,7 @@
#include "base/values.h"
#include "browser/native_window.h"
#include "common/v8_conversions.h"
#include "common/v8_value_converter_impl.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h"
@@ -27,15 +28,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 +61,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() {
@@ -108,6 +101,9 @@ v8::Handle<v8::Value> Window::New(const v8::Arguments &args) {
new Window(args.This(), static_cast<base::DictionaryValue*>(options.get()));
// Give js code a chance to do initialization.
node::MakeCallback(args.This(), "_init", 0, NULL);
return args.This();
}
@@ -141,7 +137,7 @@ v8::Handle<v8::Value> Window::Focus(const v8::Arguments &args) {
// static
v8::Handle<v8::Value> Window::IsFocused(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(self->window_->IsFocused());
return ToV8Value(self->window_->IsFocused());
}
// static
@@ -162,6 +158,12 @@ v8::Handle<v8::Value> Window::Hide(const v8::Arguments &args) {
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Window::IsVisible(const v8::Arguments& args) {
UNWRAP_WINDOW_AND_CHECK;
return ToV8Value(self->window_->IsVisible());
}
// static
v8::Handle<v8::Value> Window::Maximize(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK;
@@ -202,10 +204,11 @@ v8::Handle<v8::Value> Window::Restore(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::SetFullscreen(const v8::Arguments &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());
self->window_->SetFullscreen(fs);
return v8::Undefined();
}
@@ -213,18 +216,18 @@ v8::Handle<v8::Value> Window::SetFullscreen(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::IsFullscreen(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(self->window_->IsFullscreen());
return ToV8Value(self->window_->IsFullscreen());
}
// static
v8::Handle<v8::Value> Window::SetSize(const v8::Arguments &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()));
self->window_->SetSize(gfx::Size(width, height));
return v8::Undefined();
}
@@ -234,8 +237,8 @@ v8::Handle<v8::Value> Window::GetSize(const v8::Arguments &args) {
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;
}
@@ -244,11 +247,11 @@ v8::Handle<v8::Value> Window::GetSize(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::SetMinimumSize(const v8::Arguments &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()));
self->window_->SetMinimumSize(gfx::Size(width, height));
return v8::Undefined();
}
@@ -258,8 +261,8 @@ v8::Handle<v8::Value> Window::GetMinimumSize(const v8::Arguments &args) {
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;
}
@@ -268,11 +271,12 @@ v8::Handle<v8::Value> Window::GetMinimumSize(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::SetMaximumSize(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 2)
return node::ThrowTypeError("Bad argument");
self->window_->SetMaximumSize(
gfx::Size(args[0]->IntegerValue(), args[1]->IntegerValue()));
int width, height;
if (!FromV8Arguments(args, &width, &height))
return node::ThrowTypeError("Bad argument");
self->window_->SetMaximumSize(gfx::Size(width, height));
return v8::Undefined();
}
@@ -282,8 +286,8 @@ v8::Handle<v8::Value> Window::GetMaximumSize(const v8::Arguments &args) {
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;
}
@@ -292,10 +296,11 @@ v8::Handle<v8::Value> Window::GetMaximumSize(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::SetResizable(const v8::Arguments &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());
self->window_->SetResizable(resizable);
return v8::Undefined();
}
@@ -303,17 +308,18 @@ v8::Handle<v8::Value> Window::SetResizable(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::IsResizable(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(self->window_->IsResizable());
return ToV8Value(self->window_->IsResizable());
}
// static
v8::Handle<v8::Value> Window::SetAlwaysOnTop(const v8::Arguments &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());
self->window_->SetAlwaysOnTop(top);
return v8::Undefined();
}
@@ -321,7 +327,7 @@ v8::Handle<v8::Value> Window::SetAlwaysOnTop(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::IsAlwaysOnTop(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(self->window_->IsAlwaysOnTop());
return ToV8Value(self->window_->IsAlwaysOnTop());
}
// static
@@ -337,11 +343,11 @@ v8::Handle<v8::Value> Window::Center(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::SetPosition(const v8::Arguments &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()));
self->window_->SetPosition(gfx::Point(x, y));
return v8::Undefined();
}
@@ -351,8 +357,8 @@ v8::Handle<v8::Value> Window::GetPosition(const v8::Arguments &args) {
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;
}
@@ -361,20 +367,18 @@ v8::Handle<v8::Value> Window::GetPosition(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::SetTitle(const v8::Arguments &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]));
self->window_->SetTitle(title);
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Window::GetTitle(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK;
std::string title = self->window_->GetTitle();
return v8::String::New(title.c_str(), title.size());
return ToV8Value(self->window_->GetTitle());
}
// static
@@ -391,10 +395,11 @@ v8::Handle<v8::Value> Window::FlashFrame(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::SetKiosk(const v8::Arguments &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());
self->window_->SetKiosk(kiosk);
return v8::Undefined();
}
@@ -402,7 +407,7 @@ v8::Handle<v8::Value> Window::SetKiosk(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::IsKiosk(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(self->window_->IsKiosk());
return ToV8Value(self->window_->IsKiosk());
}
// static
@@ -423,13 +428,21 @@ v8::Handle<v8::Value> Window::CloseDevTools(const v8::Arguments &args) {
return v8::Undefined();
}
// static
v8::Handle<v8::Value> Window::IsDevToolsOpened(const v8::Arguments& args) {
UNWRAP_WINDOW_AND_CHECK;
return ToV8Value(self->window_->IsDevToolsOpened());
}
// static
v8::Handle<v8::Value> Window::InspectElement(const v8::Arguments& args) {
UNWRAP_WINDOW_AND_CHECK;
self->window_->InspectElement(args[0]->IntegerValue(),
args[1]->IntegerValue());
int x, y;
if (!FromV8Arguments(args, &x, &y))
return node::ThrowTypeError("Bad argument");
self->window_->InspectElement(x, y);
return v8::Undefined();
}
@@ -454,7 +467,7 @@ v8::Handle<v8::Value> Window::BlurWebView(const v8::Arguments &args) {
// static
v8::Handle<v8::Value> Window::IsWebViewFocused(const v8::Arguments& args) {
UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(self->window_->IsWebViewFocused());
return ToV8Value(self->window_->IsWebViewFocused());
}
// static
@@ -471,24 +484,21 @@ v8::Handle<v8::Value> Window::RestartHangMonitorTimeout(
v8::Handle<v8::Value> Window::GetPageTitle(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK;
string16 title = self->window_->GetWebContents()->GetTitle();
return UTF16ToV8String(title);
return ToV8Value(self->window_->GetWebContents()->GetTitle());
}
// static
v8::Handle<v8::Value> Window::IsLoading(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(self->window_->GetWebContents()->IsLoading());
return ToV8Value(self->window_->GetWebContents()->IsLoading());
}
// static
v8::Handle<v8::Value> Window::IsWaitingForResponse(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(
self->window_->GetWebContents()->IsWaitingForResponse());
return ToV8Value(self->window_->GetWebContents()->IsWaitingForResponse());
}
// static
@@ -504,14 +514,14 @@ v8::Handle<v8::Value> Window::Stop(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::GetRoutingID(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK;
return v8::Integer::New(self->window_->GetWebContents()->GetRoutingID());
return ToV8Value(self->window_->GetWebContents()->GetRoutingID());
}
// static
v8::Handle<v8::Value> Window::GetProcessID(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK;
return v8::Integer::New(
return ToV8Value(
self->window_->GetWebContents()->GetRenderProcessHost()->GetID());
}
@@ -519,19 +529,20 @@ v8::Handle<v8::Value> Window::GetProcessID(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::IsCrashed(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK;
return v8::Boolean::New(self->window_->GetWebContents()->IsCrashed());
return ToV8Value(self->window_->GetWebContents()->IsCrashed());
}
// static
v8::Handle<v8::Value> Window::LoadURL(const v8::Arguments &args) {
UNWRAP_WINDOW_AND_CHECK;
if (args.Length() < 1 || !args[0]->IsString())
std::string url;
if (!FromV8Arguments(args, &url))
return node::ThrowTypeError("Bad argument");
NavigationController& controller =
self->window_->GetWebContents()->GetController();
controller.LoadURL(GURL(*v8::String::Utf8Value(args[0])),
controller.LoadURL(GURL(url),
content::Referrer(),
content::PAGE_TRANSITION_AUTO_TOPLEVEL,
std::string());
@@ -549,7 +560,7 @@ v8::Handle<v8::Value> Window::GetURL(const v8::Arguments &args) {
if (controller.GetActiveEntry())
url = controller.GetActiveEntry()->GetVirtualURL().spec();
return v8::String::New(url.c_str(), url.size());
return ToV8Value(url);
}
// static
@@ -559,7 +570,7 @@ v8::Handle<v8::Value> Window::CanGoBack(const v8::Arguments &args) {
NavigationController& controller =
self->window_->GetWebContents()->GetController();
return v8::Boolean::New(controller.CanGoBack());
return ToV8Value(controller.CanGoBack());
}
// static
@@ -569,21 +580,21 @@ v8::Handle<v8::Value> Window::CanGoForward(const v8::Arguments &args) {
NavigationController& controller =
self->window_->GetWebContents()->GetController();
return v8::Boolean::New(controller.CanGoForward());
return ToV8Value(controller.CanGoForward());
}
// static
v8::Handle<v8::Value> Window::CanGoToOffset(const v8::Arguments &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));
return ToV8Value(controller.CanGoToOffset(offset));
}
// static
@@ -612,12 +623,13 @@ v8::Handle<v8::Value> Window::GoForward(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::GoToIndex(const v8::Arguments &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());
controller.GoToIndex(index);
return v8::Undefined();
}
@@ -626,12 +638,13 @@ v8::Handle<v8::Value> Window::GoToIndex(const v8::Arguments &args) {
v8::Handle<v8::Value> Window::GoToOffset(const v8::Arguments &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());
controller.GoToOffset(offset);
return v8::Undefined();
}
@@ -673,6 +686,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,6 +713,7 @@ 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);

View File

@@ -53,6 +53,7 @@ class Window : public EventEmitter,
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> IsVisible(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);
@@ -79,6 +80,7 @@ class Window : public EventEmitter,
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> IsDevToolsOpened(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);

View File

@@ -8,6 +8,8 @@
#include "base/logging.h"
#include "base/values.h"
#include "browser/api/atom_api_event.h"
#include "common/v8_conversions.h"
#include "common/v8_value_converter_impl.h"
#include "content/public/browser/browser_thread.h"
#include "vendor/node/src/node.h"
@@ -42,7 +44,7 @@ void AtomBrowserBindings::AfterLoad() {
void AtomBrowserBindings::OnRendererMessage(int process_id,
int routing_id,
const std::string& channel,
const string16& channel,
const base::ListValue& args) {
v8::HandleScope scope;
@@ -53,7 +55,7 @@ void AtomBrowserBindings::OnRendererMessage(int process_id,
// 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));
@@ -72,21 +74,24 @@ void AtomBrowserBindings::OnRendererMessage(int process_id,
void AtomBrowserBindings::OnRendererMessageSync(
int process_id,
int routing_id,
const std::string& channel,
const string16& channel,
const base::ListValue& args,
base::DictionaryValue* result) {
NativeWindow* sender,
IPC::Message* message) {
v8::HandleScope scope;
v8::Handle<v8::Context> context = v8::Context::GetCurrent();
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));
@@ -101,11 +106,6 @@ void AtomBrowserBindings::OnRendererMessageSync(
}
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()));
}
} // namespace atom

View File

@@ -5,17 +5,21 @@
#ifndef ATOM_BROWSER_API_ATOM_BROWSER_BINDINGS_
#define ATOM_BROWSER_API_ATOM_BROWSER_BINDINGS_
#include <string>
#include "base/string16.h"
#include "common/api/atom_bindings.h"
namespace base {
class DictionaryValue;
class ListValue;
}
namespace IPC {
class Message;
}
namespace atom {
class NativeWindow;
class AtomBrowserBindings : public AtomBindings {
public:
AtomBrowserBindings();
@@ -27,15 +31,16 @@ class AtomBrowserBindings : public AtomBindings {
// 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);
NativeWindow* sender,
IPC::Message* message);
// The require('atom').browserMainParts object.
v8::Handle<v8::Object> browser_main_parts() {

View File

@@ -9,6 +9,15 @@ app = new Application
app.getHomeDir = ->
process.env[if process.platform is 'win32' then 'USERPROFILE' else 'HOME']
app.getBrowserWindows = ->
require('../../atom/objects-registry.js').getAllWindows()
app.setApplicationMenu = (menu) ->
require('menu').setApplicationMenu menu
app.getApplicationMenu = ->
require('menu').getApplicationMenu()
app.commandLine =
appendSwitch: bindings.appendSwitch,
appendArgument: bindings.appendArgument

View File

@@ -1,28 +1,36 @@
EventEmitter = require('events').EventEmitter
app = require 'app'
v8Util = process.atomBinding 'v8_util'
objectsRegistry = require '../../atom/objects-registry.js'
BrowserWindow = process.atomBinding('window').BrowserWindow
BrowserWindow::__proto__ = EventEmitter.prototype
BrowserWindow::_init = ->
# Simulate the application menu on platforms other than OS X.
if process.platform isnt 'darwin'
menu = app.getApplicationMenu()
@setMenu menu if menu?
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.getFocusedWindow = ->
windows = objectsRegistry.getAllWindows()
windows = app.getBrowserWindows()
return window for window in windows when window.isFocused()
BrowserWindow.fromProcessIdAndRoutingId = (processId, routingId) ->
windows = objectsRegistry.getAllWindows()
windows = app.getBrowserWindows()
return window for window in windows when window.getProcessId() == processId and
window.getRoutingId() == routingId

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

@@ -14,8 +14,13 @@ 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

@@ -3,6 +3,7 @@ EventEmitter = require('events').EventEmitter
IDWeakMap = require 'id-weak-map'
MenuItem = require 'menu-item'
app = require 'app'
bindings = process.atomBinding 'menu'
Menu = bindings.Menu
@@ -39,13 +40,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 = app.getBrowserWindows()
w.setMenu menu for w in windows
Menu.getApplicationMenu = -> applicationMenu
Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder

View File

@@ -26,7 +26,7 @@ atom.browserMainParts =
global.__atom = atom
# Add browser/api/lib to require's search paths,
# which contains javascript part of Atom's built-in libraries.
# which contains javascript part of Atom's built-in libraries.
globalPaths = require('module').globalPaths
globalPaths.push path.join process.resourcesPath, 'browser', 'api', 'lib'
@@ -38,11 +38,11 @@ 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']
type: 'warning'
title: 'An javascript error occured in the browser'
message: 'uncaughtException'
detail: message
buttons: ['OK']
# Load the RPC server.
require './rpc-server.js'

View File

@@ -1,7 +1,9 @@
BrowserWindow = require 'browser-window'
EventEmitter = require('events').EventEmitter
IDWeakMap = require 'id-weak-map'
v8Util = process.atomBinding 'v8_util'
# Class to reference all objects.
class ObjectsStore
@stores = {}
@@ -37,46 +39,57 @@ class ObjectsStore
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
class ObjectsRegistry extends EventEmitter
constructor: ->
# 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
# Remember all windows in the weak map.
@windowsWeakMap = new IDWeakMap
process.on 'ATOM_BROWSER_INTERNAL_NEW', (obj) =>
if obj.constructor is BrowserWindow
id = @windowsWeakMap.add obj
obj.on 'destroyed', => @windowsWeakMap.remove id
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
# 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'
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.
# 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
# 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]
[id, storeId]
# Get an object according to its id.
get: (id) ->
@objectsWeakMap.get id
exports.get = (id) ->
objectsWeakMap.get id
# Remove an object according to its storeId.
remove: (processId, routingId, storeId) ->
ObjectsStore.forRenderView(processId, routingId).remove storeId
exports.getAllWindows = () ->
keys = windowsWeakMap.keys()
windowsWeakMap.get key for key in keys
# Clear all references to objects from renderer view.
clear: (processId, routingId) ->
@emit "release-renderer-view-#{processId}-#{routingId}"
ObjectsStore.releaseForRenderView processId, routingId
exports.remove = (processId, routingId, storeId) ->
ObjectsStore.forRenderView(processId, routingId).remove storeId
# Return an array of all browser windows.
getAllWindows: ->
keys = @windowsWeakMap.keys()
@windowsWeakMap.get key for key in keys
exports.clear = (processId, routingId) ->
ObjectsStore.releaseForRenderView processId, routingId
module.exports = new ObjectsRegistry

View File

@@ -52,37 +52,55 @@ unwrapArgs = (processId, routingId, args) ->
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
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
event.returnValue = errorToMeta e
ipc.on 'ATOM_BROWSER_RELEASE_RENDER_VIEW', (event, processId, routingId) ->
objectsRegistry.clear processId, routingId
event.returnValue = null
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
@@ -91,18 +109,17 @@ 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
@@ -110,32 +127,32 @@ ipc.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, processId, routingId, id, meth
constructor = objectsRegistry.get(id)[method]
# Call new with array of arguments.
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_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

@@ -4,14 +4,9 @@
#include "browser/atom_browser_client.h"
#include "browser/atom_browser_context.h"
#include "browser/atom_browser_main_parts.h"
#include "browser/net/atom_url_request_job_factory.h"
#include "content/public/common/url_constants.h"
#include "net/url_request/data_protocol_handler.h"
#include "net/url_request/file_protocol_handler.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_storage.h"
#include "vendor/brightray/browser/url_request_context_getter.h"
#include "browser/net/atom_url_request_context_getter.h"
#include "webkit/glue/webpreferences.h"
namespace atom {
@@ -25,31 +20,8 @@ AtomBrowserClient::~AtomBrowserClient() {
net::URLRequestContextGetter* AtomBrowserClient::CreateRequestContext(
content::BrowserContext* browser_context,
content::ProtocolHandlerMap* protocol_handlers) {
content::ProtocolHandlerMap preset_handlers;
std::swap(preset_handlers, *protocol_handlers);
// Create our implementaton of job factory.
AtomURLRequestJobFactory* job_factory = new AtomURLRequestJobFactory;
content::ProtocolHandlerMap::iterator it;
for (it = preset_handlers.begin(); it != preset_handlers.end(); ++it)
job_factory->SetProtocolHandler(it->first, it->second.release());
job_factory->SetProtocolHandler(chrome::kDataScheme,
new net::DataProtocolHandler);
job_factory->SetProtocolHandler(chrome::kFileScheme,
new net::FileProtocolHandler);
// Go through default procedure.
net::URLRequestContextGetter* request_context_getter =
brightray::BrowserClient::CreateRequestContext(browser_context,
protocol_handlers);
net::URLRequestContext* request_context =
request_context_getter->GetURLRequestContext();
// Replace default job factory.
storage_.reset(new net::URLRequestContextStorage(request_context));
storage_->set_job_factory(job_factory);
return request_context_getter;
return static_cast<AtomBrowserContext*>(browser_context)->
CreateRequestContext(protocol_handlers);
}
void AtomBrowserClient::OverrideWebkitPrefs(

View File

@@ -7,10 +7,6 @@
#include "brightray/browser/browser_client.h"
namespace net {
class URLRequestContextStorage;
}
namespace atom {
class AtomBrowserClient : public brightray::BrowserClient {
@@ -34,8 +30,6 @@ class AtomBrowserClient : public brightray::BrowserClient {
virtual brightray::BrowserMainParts* OverrideCreateBrowserMainParts(
const content::MainFunctionParams&) OVERRIDE;
scoped_ptr<net::URLRequestContextStorage> storage_;
DISALLOW_COPY_AND_ASSIGN(AtomBrowserClient);
};

View File

@@ -5,15 +5,65 @@
#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();
}
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

@@ -10,6 +10,7 @@
#include "browser/atom_browser_context.h"
#include "browser/browser.h"
#include "common/node_bindings.h"
#include "net/proxy/proxy_resolver_v8.h"
#include "vendor/node/src/node.h"
#include "vendor/node/src/node_internals.h"
@@ -75,6 +76,11 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
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 +88,10 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
#endif
}
int AtomBrowserMainParts::PreCreateThreads() {
// TODO(zcbenz): Calling CreateIsolate() on Windows when updated to Chrome30.
net::ProxyResolverV8::RememberDefaultIsolate();
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

@@ -31,7 +31,6 @@ app.on('finish-launching', function() {
});
mainWindow.on('closed', function() {
console.log('closed');
mainWindow = null;
});
@@ -39,129 +38,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,7 +1,7 @@
var app = require('app');
var argv = require('optimist').argv;
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() {
@@ -9,6 +9,8 @@ app.on('window-all-closed', function() {
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.
if (argv._.length > 0) {
@@ -23,6 +25,9 @@ if (argv._.length > 0) {
throw e;
}
}
} else if (argv.version) {
console.log('v' + process.versions['atom-shell']);
process.exit(0);
} else {
require('./default_app.js');
}

View File

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

View File

@@ -6,6 +6,7 @@
#include <string>
#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
@@ -31,6 +32,7 @@
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
#include "webkit/glue/image_decoder.h"
using content::NavigationEntry;
@@ -46,6 +48,12 @@ NativeWindow::NativeWindow(content::WebContents* 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);
@@ -141,6 +149,10 @@ void NativeWindow::CloseDevTools() {
inspectable_web_contents()->GetView()->CloseDevTools();
}
bool NativeWindow::IsDevToolsOpened() {
return inspectable_web_contents()->IsDevToolsOpened();
}
void NativeWindow::InspectElement(int x, int y) {
OpenDevTools();
content::RenderViewHost* rvh = GetWebContents()->GetRenderViewHost();
@@ -165,6 +177,27 @@ 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() || !file_util::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());
webkit_glue::ImageDecoder decoder;
scoped_ptr<SkBitmap> decoded(new SkBitmap());
*decoded = decoder.Decode(data, file_contents.length());
if (decoded->empty())
return false; // Unable to decode.
icon_ = gfx::Image::CreateFrom1xBitmap(*decoded.release());
return true;
}
void NativeWindow::CloseWebContents() {
bool prevent_default = false;
FOR_EACH_OBSERVER(NativeWindowObserver,
@@ -300,7 +333,8 @@ 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)
@@ -340,7 +374,7 @@ void NativeWindow::Observe(int type,
}
}
void NativeWindow::OnRendererMessage(const std::string& channel,
void NativeWindow::OnRendererMessage(const string16& channel,
const base::ListValue& args) {
AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessage(
GetWebContents()->GetRenderProcessHost()->GetID(),
@@ -349,15 +383,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

@@ -13,6 +13,7 @@
#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,6 +36,10 @@ class Rect;
class Size;
}
namespace IPC {
class Message;
}
namespace atom {
class AtomJavaScriptDialogManager;
@@ -65,6 +70,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;
@@ -94,11 +100,13 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
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);
// The same with closing a tab in a real browser.
//
@@ -170,15 +178,18 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
// Whether window has standard frame.
bool has_frame_;
// Window icon.
gfx::Image icon_;
private:
void RendererUnresponsiveDelayed();
void OnRendererMessage(const std::string& channel,
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_;

View File

@@ -28,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;

View File

@@ -13,8 +13,7 @@
#include "base/mac/mac_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/values.h"
#import "browser/atom_event_processing_window.h"
#import "browser/ui/cocoa/custom_frame_view.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"
@@ -158,8 +157,8 @@ NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
atomWindow = [[AtomNSWindow alloc]
initWithContentRect:cocoa_bounds
styleMask:NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSResizableWindowMask |
NSTexturedBackgroundWindowMask
NSMiniaturizableWindowMask | NSResizableWindowMask |
NSTexturedBackgroundWindowMask
backing:NSBackingStoreBuffered
defer:YES];
@@ -210,7 +209,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 {
@@ -230,6 +232,10 @@ void NativeWindowMac::Hide() {
[window() orderOut:nil];
}
bool NativeWindowMac::IsVisible() {
return [window() isVisible];
}
void NativeWindowMac::Maximize() {
[window() zoom:nil];
}

View File

@@ -4,8 +4,12 @@
#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"
@@ -14,8 +18,10 @@
#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"
@@ -26,24 +32,49 @@ 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);
};
@@ -173,6 +204,7 @@ 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);
@@ -185,6 +217,8 @@ NativeWindowWin::NativeWindowWin(content::WebContents* web_contents,
gfx::Size size(width, height);
window_->CenterWindow(size);
window_->UpdateWindowIcon();
web_view_->SetWebContents(web_contents);
OnViewWasResized();
}
@@ -231,6 +265,10 @@ void NativeWindowWin::Unmaximize() {
window_->Restore();
}
bool NativeWindowWin::IsVisible() {
return window_->IsVisible();
}
void NativeWindowWin::Minimize() {
window_->Minimize();
}
@@ -325,6 +363,17 @@ 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_)
@@ -352,12 +401,54 @@ void NativeWindowWin::UpdateDraggableRegions(
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(bool is_add,
views::View* parent,
views::View* child) {
if (is_add && 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_;
}
@@ -374,8 +465,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() {
@@ -387,7 +485,7 @@ 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(
@@ -428,6 +526,44 @@ void NativeWindowWin::OnViewWasResized() {
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
NativeWindow* NativeWindow::Create(content::WebContents* web_contents,
base::DictionaryValue* options) {

View File

@@ -12,6 +12,10 @@
#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;
@@ -60,6 +67,12 @@ class NativeWindowWin : public NativeWindow,
virtual bool IsKiosk() 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:
@@ -71,12 +84,22 @@ class NativeWindowWin : public NativeWindow,
content::WebContents*,
const content::NativeWebKeyboardEvent&) OVERRIDE;
// Overridden from views::View:
virtual void Layout() OVERRIDE;
virtual void ViewHierarchyChanged(bool is_add,
views::View* parent,
views::View* child) 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;
@@ -84,11 +107,30 @@ 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_;

View File

@@ -30,8 +30,8 @@ void AdapterRequestJob::Start() {
}
void AdapterRequestJob::Kill() {
DCHECK(real_job_);
real_job_->Kill();
if (real_job_) // Kill could happen when real_job_ is created.
real_job_->Kill();
}
bool AdapterRequestJob::ReadRawData(net::IOBuffer* buf,

View File

@@ -0,0 +1,169 @@
// 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/string_util.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,
MessageLoop* io_loop,
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));
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()));
storage_->set_http_server_properties(new net::HttpServerPropertiesImpl);
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();
job_factory_->SetProtocolHandler(chrome::kDataScheme,
new net::DataProtocolHandler);
job_factory_->SetProtocolHandler(chrome::kFileScheme,
new net::FileProtocolHandler);
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

@@ -4,6 +4,8 @@
#include "browser/ui/accelerator_util.h"
#include <stdio.h>
#include <string>
#include "base/string_util.h"
@@ -15,67 +17,152 @@ 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") {
modifiers |= ui::EF_CONTROL_DOWN;
} else if (tokens[i] == "Command") {
} else if (tokens[i] == "command") {
modifiers |= ui::EF_COMMAND_DOWN;
} else if (tokens[i] == "Alt") {
} 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 +170,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

@@ -2,18 +2,17 @@
// 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 +29,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

@@ -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

@@ -1,56 +0,0 @@
// Copyright (c) 2012 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.
#import <Cocoa/Cocoa.h>
// CustomFrameView is a class whose methods we swizzle into NSGrayFrame
// on 10.7 and below, or NSThemeFrame on 10.8 and above, so that we can
// support custom frame drawing. This is used with a textured window so that
// AppKit does not draw a title bar.
// This class is never to be instantiated on its own.
// We explored a variety of ways to support custom frame drawing and custom
// window widgets.
// Our requirements were:
// a) that we could fall back on standard system drawing at any time for the
// "default theme"
// b) We needed to be able to draw both a background pattern, and an overlay
// graphic, and we need to be able to set the pattern phase of our background
// window.
// c) We had to be able to support "transparent" themes, so that you could see
// through to the underlying windows in places without the system theme
// getting in the way.
//
// Since we want "A" we couldn't just do a transparent borderless window. At
// least I couldn't find the right combination of HITheme calls to make it draw
// nicely, and I don't trust that the HITheme calls are going to exist in future
// system versions.
// "C" precluded us from inserting a view between the system frame and the
// the content frame in Z order. To get the transparency we actually need to
// replace the drawing of the system frame.
// "B" precluded us from just setting a background color on the window.
//
// Originally we tried overriding the private API +frameViewForStyleMask: to
// add our own subclass of NSGrayView to our window. Turns out that if you
// subclass NSGrayView it does not draw correctly when you call NSGrayView's
// drawRect. It appears that NSGrayView's drawRect: method (and that of its
// superclasses) do lots of "isMemberOfClass/isKindOfClass" calls, and if your
// class is NOT an instance of NSGrayView (as opposed to a subclass of
// NSGrayView) then the system drawing will not work correctly.
//
// Given all of the above, we found swizzling drawRect in _load to be the
// easiest and safest method of achieving our goals. We do the best we can to
// check that everything is safe, and attempt to fallback gracefully if it is
// not.
@interface NSWindow (CustomFrameView)
// To define custom window drawing behaviour, override this method on an
// NSWindow subclass. Call the default method (on super) to draw the
// default frame.
// NOTE: Always call the default implementation (even if you just immediately
// draw over it), otherwise the top-left and top-right corners of the window
// won't be drawn correctly.
- (void)drawCustomFrameRect:(NSRect)rect forView:(NSView*)view;
@end

View File

@@ -1,138 +0,0 @@
// Copyright (c) 2012 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.
#import "browser/ui/cocoa/custom_frame_view.h"
#import <objc/runtime.h>
#import <Carbon/Carbon.h>
#include "base/logging.h"
#include "base/mac/mac_util.h"
#include "base/mac/scoped_nsautorelease_pool.h"
namespace {
BOOL gCanDrawTitle = NO;
BOOL gCanGetCornerRadius = NO;
} // namespace
@interface NSView (Swizzles)
- (void)drawRectOriginal:(NSRect)rect;
- (NSPoint)_fullScreenButtonOriginOriginal;
@end
@interface NSWindow (FramedBrowserWindow)
- (NSPoint)fullScreenButtonOriginAdjustment;
@end
@implementation NSWindow (CustomFrameView)
- (void)drawCustomFrameRect:(NSRect)rect forView:(NSView*)view {
[view drawRectOriginal:rect];
}
@end
@interface CustomFrameView : NSView
@end
@implementation CustomFrameView
// This is where we swizzle drawRect, and add in two methods that we
// need. If any of these fail it shouldn't affect the functionality of the
// others. If they all fail, we will lose window frame theming and
// roll overs for our close widgets, but things should still function
// correctly.
+ (void)load {
base::mac::ScopedNSAutoreleasePool pool;
// On 10.8+ the background for textured windows are no longer drawn by
// NSGrayFrame, and NSThemeFrame is used instead <http://crbug.com/114745>.
Class borderViewClass = NSClassFromString(
base::mac::IsOSMountainLionOrLater() ? @"NSThemeFrame" : @"NSGrayFrame");
DCHECK(borderViewClass);
if (!borderViewClass) return;
// Exchange draw rect.
Method m0 = class_getInstanceMethod([self class], @selector(drawRect:));
DCHECK(m0);
if (m0) {
BOOL didAdd = class_addMethod(borderViewClass,
@selector(drawRectOriginal:),
method_getImplementation(m0),
method_getTypeEncoding(m0));
DCHECK(didAdd);
if (didAdd) {
Method m1 = class_getInstanceMethod(borderViewClass,
@selector(drawRect:));
Method m2 = class_getInstanceMethod(borderViewClass,
@selector(drawRectOriginal:));
DCHECK(m1 && m2);
if (m1 && m2) {
method_exchangeImplementations(m1, m2);
}
}
}
// Swizzle the method that sets the origin for the Lion fullscreen button. Do
// nothing if it cannot be found.
m0 = class_getInstanceMethod([self class],
@selector(_fullScreenButtonOrigin));
if (m0) {
BOOL didAdd = class_addMethod(borderViewClass,
@selector(_fullScreenButtonOriginOriginal),
method_getImplementation(m0),
method_getTypeEncoding(m0));
if (didAdd) {
Method m1 = class_getInstanceMethod(borderViewClass,
@selector(_fullScreenButtonOrigin));
Method m2 = class_getInstanceMethod(borderViewClass,
@selector(_fullScreenButtonOriginOriginal));
if (m1 && m2) {
method_exchangeImplementations(m1, m2);
}
}
}
}
+ (BOOL)canDrawTitle {
return gCanDrawTitle;
}
+ (BOOL)canGetCornerRadius {
return gCanGetCornerRadius;
}
- (id)initWithFrame:(NSRect)frame {
// This class is not for instantiating.
[self doesNotRecognizeSelector:_cmd];
return nil;
}
- (id)initWithCoder:(NSCoder*)coder {
// This class is not for instantiating.
[self doesNotRecognizeSelector:_cmd];
return nil;
}
// Here is our custom drawing for our frame.
- (void)drawRect:(NSRect)rect {
// Delegate drawing to the window, whose default implementation (above) is to
// call into the original implementation.
[[self window] drawCustomFrameRect:rect forView:self];
}
// Override to move the fullscreen button to the left of the profile avatar.
- (NSPoint)_fullScreenButtonOrigin {
NSWindow* window = [self window];
NSPoint offset = NSZeroPoint;
if ([window respondsToSelector:@selector(fullScreenButtonOriginAdjustment)])
offset = [window fullScreenButtonOriginAdjustment];
NSPoint origin = [self _fullScreenButtonOriginOriginal];
origin.x += offset.x;
origin.y += offset.y;
return origin;
}
@end

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

@@ -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,6 +4,7 @@
#include "browser/ui/file_dialog.h"
#include <atlbase.h>
#include <windows.h>
#include <commdlg.h>
#include <shlobj.h>
@@ -14,19 +15,14 @@
#include "base/strings/string_split.h"
#include "base/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,6 +4,7 @@
#include "browser/ui/message_box.h"
#include "base/callback.h"
#include "base/message_loop.h"
#include "base/run_loop.h"
#include "base/string_util.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

@@ -92,6 +92,20 @@ class NativeMenuWin::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) {
@@ -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

@@ -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,7 +4,12 @@
'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.
@@ -57,6 +62,16 @@
'GCC_TREAT_WARNINGS_AS_ERRORS': 'NO'
},
}],
['_target_name=="libuv"', {
'conditions': [
['OS=="win"', {
# Expose libuv's symbols.
'defines': [
'BUILDING_UV_SHARED=1',
],
}], # OS=="win"
],
}],
],
'msvs_cygwin_shell': 0, # Strangely setting it to 1 would make building under cygwin fail.
'msvs_disabled_warnings': [
@@ -67,6 +82,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
@@ -112,23 +133,36 @@
'-fcolor-diagnostics',
],
'SDKROOT': 'macosx<(mac_sdk)', # -isysroot
'GCC_C_LANGUAGE_STANDARD': 'c99', # -std=c99
},
},
}], # clang==1
# Windows specific settings.
['OS=="win"', {
# Using Visual Studio Express.
['msvs_express==1', {
'target_defaults': {
'defines!': [
'_SECURE_ATL',
],
'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,
'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',
],
},
}], # OS=="win"
}], # msvs_express==1
],
}

View File

@@ -4,8 +4,7 @@
// Multiply-included file, no traditional include guard.
#include <string>
#include "base/string16.h"
#include "base/values.h"
#include "common/draggable_region.h"
#include "content/public/common/common_param_traits.h"
@@ -22,16 +21,16 @@ IPC_STRUCT_TRAITS_BEGIN(atom::DraggableRegion)
IPC_STRUCT_TRAITS_END()
IPC_MESSAGE_ROUTED2(AtomViewHostMsg_Message,
std::string /* channel */,
string16 /* channel */,
ListValue /* arguments */)
IPC_SYNC_MESSAGE_ROUTED2_1(AtomViewHostMsg_Message_Sync,
std::string /* channel */,
string16 /* channel */,
ListValue /* arguments */,
DictionaryValue /* result */)
string16 /* result (in JSON) */)
IPC_MESSAGE_ROUTED2(AtomViewMsg_Message,
std::string /* channel */,
string16 /* channel */,
ListValue /* arguments */)
// Sent by the renderer when the draggable regions are updated.

View File

@@ -7,17 +7,35 @@
#include "base/debug/debugger.h"
#include "base/logging.h"
#include "common/atom_version.h"
#include "common/v8_conversions.h"
#include "vendor/node/src/node.h"
namespace atom {
namespace {
static int kMaxCallStackSize = 200; // Same with WebKit.
static uv_async_t dummy_uv_handle;
void UvNoOp(uv_async_t* handle, int status) {
}
v8::Handle<v8::Object> DumpStackFrame(v8::Handle<v8::StackFrame> stack_frame) {
v8::Local<v8::Object> result = v8::Object::New();
result->Set(ToV8Value("line"), ToV8Value(stack_frame->GetLineNumber()));
result->Set(ToV8Value("column"), ToV8Value(stack_frame->GetColumn()));
v8::Handle<v8::String> script = stack_frame->GetScriptName();
if (!script.IsEmpty())
result->Set(ToV8Value("script"), script);
v8::Handle<v8::String> function = stack_frame->GetScriptNameOrSourceURL();
if (!function.IsEmpty())
result->Set(ToV8Value("function"), function);
return result;
}
} // namespace
// Defined in atom_extensions.cc.
@@ -37,6 +55,7 @@ void AtomBindings::BindTo(v8::Handle<v8::Object> process) {
node::SetMethod(process, "crash", Crash);
node::SetMethod(process, "activateUvLoop", ActivateUVLoop);
node::SetMethod(process, "log", Log);
node::SetMethod(process, "getCurrentStackTrace", GetCurrentStackTrace);
process->Get(v8::String::New("versions"))->ToObject()->
Set(v8::String::New("atom-shell"), v8::String::New(ATOM_VERSION_STRING));
@@ -111,4 +130,23 @@ v8::Handle<v8::Value> AtomBindings::Log(const v8::Arguments& args) {
return v8::Undefined();
}
// static
v8::Handle<v8::Value> AtomBindings::GetCurrentStackTrace(
const v8::Arguments& args) {
v8::HandleScope scope;
int stack_limit = kMaxCallStackSize;
FromV8Arguments(args, &stack_limit);
v8::Local<v8::StackTrace> stack_trace = v8::StackTrace::CurrentStackTrace(
stack_limit, v8::StackTrace::kDetailed);
int frame_count = stack_trace->GetFrameCount();
v8::Local<v8::Array> result = v8::Array::New(frame_count);
for (int i = 0; i < frame_count; ++i)
result->Set(i, DumpStackFrame(stack_trace->GetFrame(i)));
return scope.Close(result);
}
} // namespace atom

View File

@@ -24,6 +24,7 @@ class AtomBindings {
static v8::Handle<v8::Value> Crash(const v8::Arguments& args);
static v8::Handle<v8::Value> ActivateUVLoop(const v8::Arguments& args);
static v8::Handle<v8::Value> Log(const v8::Arguments& args);
static v8::Handle<v8::Value> GetCurrentStackTrace(const v8::Arguments& args);
DISALLOW_COPY_AND_ASSIGN(AtomBindings);
};

View File

@@ -6,8 +6,8 @@
#define ATOM_VERSION_H
#define ATOM_MAJOR_VERSION 0
#define ATOM_MINOR_VERSION 4
#define ATOM_PATCH_VERSION 7
#define ATOM_MINOR_VERSION 6
#define ATOM_PATCH_VERSION 11
#define ATOM_VERSION_IS_RELEASE 1

View File

@@ -7,7 +7,9 @@
#include "base/command_line.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "common/v8_conversions.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/escape.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
#include "vendor/node/src/node.h"
@@ -37,10 +39,16 @@ NodeBindings::NodeBindings(bool is_browser)
}
NodeBindings::~NodeBindings() {
// Clear uv.
// Quit the embed thread.
embed_closed_ = true;
uv_sem_post(&embed_sem_);
WakeupEmbedThread();
// Wait for everything to be done.
uv_thread_join(&embed_thread_);
message_loop_->RunUntilIdle();
// Clear uv.
uv_sem_destroy(&embed_sem_);
uv_timer_stop(&idle_timer_);
}
@@ -116,9 +124,12 @@ void NodeBindings::BindTo(WebKit::WebFrame* frame) {
// Run the script of cefode.js.
std::string script_path(GURL(frame->document().url()).path());
script_path = net::UnescapeURLComponent(
script_path,
net::UnescapeRule::SPACES | net::UnescapeRule::URL_SPECIAL_CHARS);
v8::Handle<v8::Value> args[2] = {
v8::Local<v8::Value>::New(node::process),
v8::String::New(script_path.c_str(), script_path.size())
ToV8Value(script_path),
};
v8::Local<v8::Function>::Cast(result)->Call(context->Global(), 2, args);
}

232
common/v8_conversions.h Normal file
View File

@@ -0,0 +1,232 @@
// 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 COMMON_V8_CONVERSIONS_H_
#define COMMON_V8_CONVERSIONS_H_
#include <string>
#include <vector>
#include "base/files/file_path.h"
#include "base/string16.h"
#include "browser/api/atom_api_window.h"
#include "v8/include/v8.h"
// Convert V8 value to arbitrary supported types.
struct FromV8Value {
explicit FromV8Value(v8::Handle<v8::Value> value) : value_(value) {}
operator int() {
return value_->IntegerValue();
}
operator bool() {
return value_->BooleanValue();
}
operator std::string() {
return *v8::String::Utf8Value(value_);
}
operator string16() {
v8::String::Value s(value_);
return string16(reinterpret_cast<const char16*>(*s), s.length());
}
operator base::FilePath() {
return base::FilePath::FromUTF8Unsafe(FromV8Value(value_));
}
operator std::vector<std::string>() {
std::vector<std::string> array;
v8::Handle<v8::Array> v8_array = v8::Handle<v8::Array>::Cast(value_);
for (uint32_t i = 0; i < v8_array->Length(); ++i)
array.push_back(FromV8Value(v8_array->Get(i)));
return array;
}
operator atom::NativeWindow*() {
using atom::api::Window;
if (value_->IsObject()) {
Window* window = Window::Unwrap<Window>(value_->ToObject());
if (window && window->window())
return window->window();
}
return NULL;
}
operator v8::Persistent<v8::Function>() {
return value_->IsFunction() ?
v8::Persistent<v8::Function>::New(
node::node_isolate,
v8::Handle<v8::Function>::Cast(value_)) :
v8::Persistent<v8::Function>();
}
v8::Handle<v8::Value> value_;
};
// Convert arbitrary supported native type to V8 value.
inline v8::Handle<v8::Value> ToV8Value(int i) {
return v8::Integer::New(i);
}
inline v8::Handle<v8::Value> ToV8Value(bool b) {
return v8::Boolean::New(b);
}
inline v8::Handle<v8::Value> ToV8Value(const char* s) {
return v8::String::New(s);
}
inline v8::Handle<v8::Value> ToV8Value(const std::string& s) {
return v8::String::New(s.data(), s.size());
}
inline v8::Handle<v8::Value> ToV8Value(const string16& s) {
return v8::String::New(reinterpret_cast<const uint16_t*>(s.data()), s.size());
}
inline v8::Handle<v8::Value> ToV8Value(const base::FilePath& path) {
std::string path_string(path.AsUTF8Unsafe());
return v8::String::New(path_string.data(), path_string.size());
}
inline v8::Handle<v8::Value> ToV8Value(void* whatever) {
return v8::Undefined();
}
inline
v8::Handle<v8::Value> ToV8Value(const std::vector<base::FilePath>& paths) {
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 result;
}
// Check if a V8 Value is of specified type.
template<class T> inline
bool V8ValueCanBeConvertedTo(v8::Handle<v8::Value> value) {
return false;
}
template<> inline
bool V8ValueCanBeConvertedTo<int>(v8::Handle<v8::Value> value) {
return value->IsNumber();
}
template<> inline
bool V8ValueCanBeConvertedTo<bool>(v8::Handle<v8::Value> value) {
return value->IsBoolean();
}
template<> inline
bool V8ValueCanBeConvertedTo<std::string>(v8::Handle<v8::Value> value) {
return value->IsString();
}
template<> inline
bool V8ValueCanBeConvertedTo<string16>(v8::Handle<v8::Value> value) {
return V8ValueCanBeConvertedTo<std::string>(value);
}
template<> inline
bool V8ValueCanBeConvertedTo<base::FilePath>(v8::Handle<v8::Value> value) {
return V8ValueCanBeConvertedTo<std::string>(value);
}
template<> inline
bool V8ValueCanBeConvertedTo<std::vector<std::string>>(
v8::Handle<v8::Value> value) {
return value->IsArray();
}
template<> inline
bool V8ValueCanBeConvertedTo<atom::NativeWindow*>(v8::Handle<v8::Value> value) {
using atom::api::Window;
if (value->IsObject()) {
Window* window = Window::Unwrap<Window>(value->ToObject());
if (window && window->window())
return true;
}
return false;
}
template<> inline
bool V8ValueCanBeConvertedTo<v8::Persistent<v8::Function>>(
v8::Handle<v8::Value> value) {
return value->IsFunction();
}
// Check and convert V8's Arguments to native types.
template<typename T1> inline
bool FromV8Arguments(const v8::Arguments& args, T1* value, int index = 0) {
if (!V8ValueCanBeConvertedTo<T1>(args[index]))
return false;
*value = static_cast<const T1&>(FromV8Value(args[index]));
return true;
}
template<typename T1, typename T2> inline
bool FromV8Arguments(const v8::Arguments& args, T1* a1, T2* a2) {
return FromV8Arguments<T1>(args, a1) && FromV8Arguments<T2>(args, a2, 1);
}
template<typename T1, typename T2, typename T3> inline
bool FromV8Arguments(const v8::Arguments& args, T1* a1, T2* a2, T3* a3) {
return FromV8Arguments<T1, T2>(args, a1, a2) &&
FromV8Arguments<T3>(args, a3, 2);
}
template<typename T1, typename T2, typename T3, typename T4> inline
bool FromV8Arguments(const v8::Arguments& args,
T1* a1,
T2* a2,
T3* a3,
T4* a4) {
return FromV8Arguments<T1, T2, T3>(args, a1, a2, a3) &&
FromV8Arguments<T4>(args, a4, 3);
}
template<typename T1, typename T2, typename T3, typename T4, typename T5> inline
bool FromV8Arguments(const v8::Arguments& args,
T1* a1,
T2* a2,
T3* a3,
T4* a4,
T5* a5) {
return FromV8Arguments<T1, T2, T3, T4>(args, a1, a2, a3, a4) &&
FromV8Arguments<T5>(args, a5, 4);
}
template<typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6> inline
bool FromV8Arguments(const v8::Arguments& args,
T1* a1,
T2* a2,
T3* a3,
T4* a4,
T5* a5,
T6* a6) {
return FromV8Arguments<T1, T2, T3, T4, T5>(args, a1, a2, a3, a4, a5) &&
FromV8Arguments<T6>(args, a6, 5);
}
template<typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7> inline
bool FromV8Arguments(const v8::Arguments& args,
T1* a1,
T2* a2,
T3* a3,
T4* a4,
T5* a5,
T6* a6,
T7* a7) {
return
FromV8Arguments<T1, T2, T3, T4, T5, T6>(args, a1, a2, a3, a4, a5, a6) &&
FromV8Arguments<T7>(args, a7, 6);
}
#endif // COMMON_V8_CONVERSIONS_H_

View File

@@ -79,12 +79,16 @@ code will not run.
Returns the version of current bundle or executable.
## app.getBrowserWindows()
Returns an array of all browser windows.
## app.commandLine.appendSwitch(switch, [value])
Append a switch [with optional value] to Chromium's command line.
**Note:** This will not affect `process.argv`, and is mainly used by
**developers to control some low-level Chromium behaviors.
**Note:** This will not affect `process.argv`, and is mainly used by developers
to control some low-level Chromium behaviors.
## app.commandLine.appendArgument(value)

View File

@@ -141,6 +141,10 @@ Shows the window.
Hides the window.
### BrowserWindow.isVisible()
Returns whether the window is visible to the user.
### BrowserWindow.maximize()
Maximizes the window.

View File

@@ -18,7 +18,7 @@ Emitted when renderer sent a message to the browser.
* `routingId` Integer
Emitted when renderer sent a synchronous message to the browser. The receiver
should store the result in `event.result`.
should store the result in `event.returnValue`.
**Note:** Due to the limitation of `EventEmitter`, returning value in the
event handler has no effect, so we have to store the result by using the

View File

@@ -23,5 +23,4 @@
## Notes on accelerator
On OS X, the `Ctrl` would automatically translated to `Command`, if you really
want `Ctrl` on OS X, you should use `MacCtrl`.
On Linux and Windows, the `Command` key would not have any effect.

View File

@@ -14,6 +14,9 @@ protocol.registerProtocol('atom', function(request) {
});
```
**Note:** This module can only be used after the `will-finish-launching` event
was emitted.
## protocol.registerProtocol(scheme, handler)
* `scheme` String

View File

@@ -30,7 +30,7 @@ An example of sending synchronous message from renderer to browser:
// In browser:
var ipc = require('ipc');
ipc.on('browser-data-request', function(event, processId, routingId, message) {
event.result = 'THIS SOME DATA FROM THE BROWSER';
event.returnValue = 'THIS SOME DATA FROM THE BROWSER';
});
```

View File

@@ -3,11 +3,21 @@
## Prerequisites
* Windows 7 or later
* Visual Studio 2010 Express or higher
* Visual Studio 2010 Express or Profissional
* Make sure "X64 Compilers and Tools" are installed if you use the
Profissional edition.
* [Python 2.7](http://www.python.org/download/releases/2.7/)
* [node.js](http://nodejs.org/)
* [git](http://git-scm.com)
If you are using Visual Studio 2010 __Express__ then you also need following
softwares:
* [WDK](http://www.microsoft.com/en-us/download/details.aspx?id=11800)
* `Build Environments` is required.
* [Windows 7 SDK](http://www.microsoft.com/en-us/download/details.aspx?id=8279)
* `Windows Headers` and `Visual C++ Compilers` are required.
The instructions bellow are executed under [cygwin](http://www.cygwin.com),
but it's not a requirement, you can also build atom-shell under Windows's
console or other terminals.
@@ -18,7 +28,7 @@ not use Visual Studio for the development. Support of building with Visual
Studio will come in future.
**Note:** Even though Visual Studio is not used for building, it's still
**required because we need the build toolchains it provided.
**required** because we need the build toolchains it provided.
## Getting the code

View File

@@ -1,20 +1,21 @@
{
"name" : "atom",
"version" : "0.1.0",
"name": "atom-shell",
"version": "0.6.11",
"dependencies": {
"coffee-script": "1.6.2",
"devDependencies": {
"coffee-script": "~1.6.3",
"coffeelint": "~0.6.1",
"mocha": "~1.13.0",
"walkdir": "~0.0.7",
"mocha": "*",
"walkdir": "*",
"unzip": "*",
"d3": "*",
"int64-native": "*"
"unzip": "~0.1.9",
"d3": "~3.3.8",
"int64-native": "~0.2.0"
},
"private": true,
"scripts": {
"preinstall": "true"
"preinstall": "node -e 'process.exit(0)'"
}
}

View File

@@ -6,6 +6,7 @@
#include "base/values.h"
#include "common/api/api_messages.h"
#include "common/v8_conversions.h"
#include "content/public/renderer/render_view.h"
#include "content/public/renderer/v8_value_converter.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
@@ -47,8 +48,7 @@ v8::Handle<v8::Value> RendererIPC::Send(const v8::Arguments &args) {
if (!args[0]->IsString())
return node::ThrowTypeError("Bad argument");
std::string channel(*v8::String::Utf8Value(args[0]));
string16 channel = FromV8Value(args[0]);
RenderView* render_view = GetCurrentRenderView();
// Convert Arguments to Array, so we can use V8ValueConverter to convert it
@@ -82,7 +82,7 @@ v8::Handle<v8::Value> RendererIPC::SendSync(const v8::Arguments &args) {
return node::ThrowTypeError("Bad argument");
v8::Handle<v8::Context> context = v8::Context::GetCurrent();
std::string channel(*v8::String::Utf8Value(args[0]));
string16 channel = FromV8Value(args[0]);
// Convert Arguments to Array, so we can use V8ValueConverter to convert it
// to ListValue.
@@ -97,12 +97,12 @@ v8::Handle<v8::Value> RendererIPC::SendSync(const v8::Arguments &args) {
RenderView* render_view = GetCurrentRenderView();
base::DictionaryValue result;
string16 json;
IPC::SyncMessage* message = new AtomViewHostMsg_Message_Sync(
render_view->GetRoutingID(),
channel,
*static_cast<base::ListValue*>(arguments.get()),
&result);
&json);
// Enable the UI thread in browser to receive messages.
message->EnableMessagePumping();
bool success = render_view->Send(message);
@@ -110,7 +110,7 @@ v8::Handle<v8::Value> RendererIPC::SendSync(const v8::Arguments &args) {
if (!success)
return node::ThrowError("Unable to send AtomViewHostMsg_Message_Sync");
return scope.Close(converter->ToV8Value(&result, context));
return scope.Close(ToV8Value(json));
}
// static

View File

@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "base/values.h"
#include "common/v8_conversions.h"
#include "content/public/renderer/render_view.h"
#include "content/public/renderer/v8_value_converter.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
@@ -51,7 +52,7 @@ void AtomRendererBindings::BindToFrame(WebFrame* frame) {
AtomBindings::BindTo(GetProcessObject(context));
}
void AtomRendererBindings::OnBrowserMessage(const std::string& channel,
void AtomRendererBindings::OnBrowserMessage(const string16& channel,
const base::ListValue& args) {
if (!render_view_->GetWebView())
return;
@@ -70,7 +71,7 @@ void AtomRendererBindings::OnBrowserMessage(const std::string& channel,
std::vector<v8::Handle<v8::Value>> arguments;
arguments.reserve(1 + args.GetSize());
arguments.push_back(v8::String::New(channel.c_str(), channel.size()));
arguments.push_back(ToV8Value(channel));
for (size_t i = 0; i < args.GetSize(); i++) {
const base::Value* value;

View File

@@ -5,10 +5,10 @@
#ifndef ATOM_RENDERER_API_ATOM_RENDERER_BINDINGS_H_
#define ATOM_RENDERER_API_ATOM_RENDERER_BINDINGS_H_
#include <string>
#include "common/api/atom_bindings.h"
#include "base/string16.h"
namespace base {
class ListValue;
}
@@ -32,7 +32,7 @@ class AtomRendererBindings : public AtomBindings {
void BindToFrame(WebKit::WebFrame* frame);
// Dispatch messages from browser.
void OnBrowserMessage(const std::string& channel,
void OnBrowserMessage(const string16& channel,
const base::ListValue& args);
private:

View File

@@ -16,9 +16,11 @@ class Ipc extends EventEmitter
ipc.send('ATOM_INTERNAL_MESSAGE', args...)
sendSync: (args...) ->
ipc.sendSync('ATOM_INTERNAL_MESSAGE_SYNC', 'sync-message', args...).result
msg = ipc.sendSync('ATOM_INTERNAL_MESSAGE_SYNC', 'sync-message', args...)
JSON.parse(msg)
sendChannelSync: (args...) ->
ipc.sendSync('ATOM_INTERNAL_MESSAGE_SYNC', args...).result
msg = ipc.sendSync('ATOM_INTERNAL_MESSAGE_SYNC', args...)
JSON.parse(msg)
module.exports = new Ipc

View File

@@ -72,6 +72,7 @@ metaToValue = (meta) ->
ret.__defineSetter__ member.name, (value) ->
# Set member data.
ipc.sendChannelSync 'ATOM_BROWSER_MEMBER_SET', meta.id, member.name, value
value
ret.__defineGetter__ member.name, ->
# Get member data.

View File

@@ -101,7 +101,7 @@ bool AtomRenderViewObserver::OnMessageReceived(const IPC::Message& message) {
return handled;
}
void AtomRenderViewObserver::OnBrowserMessage(const std::string& channel,
void AtomRenderViewObserver::OnBrowserMessage(const string16& channel,
const base::ListValue& args) {
atom_bindings()->OnBrowserMessage(channel, args);
}

View File

@@ -35,7 +35,7 @@ class AtomRenderViewObserver : content::RenderViewObserver {
virtual void DraggableRegionsChanged(WebKit::WebFrame* frame) OVERRIDE;
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
void OnBrowserMessage(const std::string& channel,
void OnBrowserMessage(const string16& channel,
const base::ListValue& args);
scoped_ptr<AtomRendererBindings> atom_bindings_;

View File

@@ -1,12 +1,11 @@
#!/usr/bin/env python
import argparse
import errno
import os
import subprocess
import sys
from lib.util import *
from lib.util import scoped_cwd
SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
@@ -67,8 +66,8 @@ def update_apm():
def update_node_modules():
for dirname in ['.', 'browser/default_app', 'spec']:
update_node_modules_for_dir(dirname);
for dirname in ['browser/default_app', '.']:
update_node_modules_for_dir(dirname)
def update_node_modules_for_dir(dirname):

116
script/bump-version.py Executable file
View File

@@ -0,0 +1,116 @@
#!/usr/bin/env python
import os
import re
import subprocess
import sys
SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
def main():
if len(sys.argv) != 2:
print 'Usage: bump-version.py version'
return 1
version = sys.argv[1]
if version[0] == 'v':
version = version[1:]
versions = parse_version(version)
os.chdir(SOURCE_ROOT)
update_package_json(version)
update_win_rc(version, versions)
update_version_h(versions)
update_info_plist(version)
tag_version(version)
def parse_version(version):
vs = version.split('.')
if len(vs) > 4:
return vs[0:4]
else:
return vs + [0] * (4 - len(vs))
def update_package_json(version):
pattern = re.compile(' *"version" *: *"[0-9.]+"')
with open('package.json', 'r') as f:
lines = f.readlines()
for i in range(0, len(lines)):
if pattern.match(lines[i]):
lines[i] = ' "version": "{0}",\n'.format(version)
with open('package.json', 'w') as f:
f.write(''.join(lines))
return
def update_win_rc(version, versions):
pattern_fv = re.compile(' FILEVERSION [0-9,]+')
pattern_pv = re.compile(' PRODUCTVERSION [0-9,]+')
pattern_fvs = re.compile(' *VALUE "FileVersion", "[0-9.]+"')
pattern_pvs = re.compile(' *VALUE "ProductVersion", "[0-9.]+"')
win_rc = os.path.join('app', 'win', 'atom.rc')
with open(win_rc, 'r') as f:
lines = f.readlines()
versions = [str(v) for v in versions]
for i in range(0, len(lines)):
line = lines[i]
if pattern_fv.match(line):
lines[i] = ' FILEVERSION {0}\r\n'.format(','.join(versions))
elif pattern_pv.match(line):
lines[i] = ' PRODUCTVERSION {0}\r\n'.format(','.join(versions))
elif pattern_fvs.match(line):
lines[i] = ' VALUE "FileVersion", "{0}"\r\n'.format(version)
elif pattern_pvs.match(line):
lines[i] = ' VALUE "ProductVersion", "{0}"\r\n'.format(version)
with open(win_rc, 'w') as f:
f.write(''.join(lines))
def update_version_h(versions):
version_h = os.path.join('common', 'atom_version.h')
with open(version_h, 'r') as f:
lines = f.readlines()
for i in range(0, len(lines)):
line = lines[i]
if 'ATOM_MAJOR_VERSION' in line:
lines[i] = '#define ATOM_MAJOR_VERSION {0}\n'.format(versions[0])
lines[i + 1] = '#define ATOM_MINOR_VERSION {0}\n'.format(versions[1])
lines[i + 2] = '#define ATOM_PATCH_VERSION {0}\n'.format(versions[2])
with open(version_h, 'w') as f:
f.write(''.join(lines))
return
def update_info_plist(version):
info_plist = os.path.join('browser', 'mac', 'Info.plist')
with open(info_plist, 'r') as f:
lines = f.readlines()
for i in range(0, len(lines)):
line = lines[i]
if 'CFBundleVersion' in line:
lines[i + 1] = ' <string>{0}</string>\n'.format(version)
with open(info_plist, 'w') as f:
f.write(''.join(lines))
return
def tag_version(version):
subprocess.check_call(['git', 'commit', '-a', '-m',
'Bump v{0}.'.format(version)])
subprocess.check_call(['git', 'tag', 'v{0}'.format(version)])
if __name__ == '__main__':
sys.exit(main())

View File

@@ -11,6 +11,8 @@ SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
def main():
run_script('bootstrap.py')
run_script('cpplint.py')
run_script('pylint.py')
run_script('coffeelint.py')
run_script('build.py')
run_script('test.py', ['--ci'])
run_script('create-dist.py')

6
script/coffeelint.json Normal file
View File

@@ -0,0 +1,6 @@
{
"max_line_length": {
"value": 80,
"level": "ignore"
}
}

31
script/coffeelint.py Executable file
View File

@@ -0,0 +1,31 @@
#!/usr/bin/env python
import glob
import os
import subprocess
import sys
SOURCE_ROOT = os.path.dirname(os.path.dirname(__file__))
def main():
os.chdir(SOURCE_ROOT)
coffeelint = os.path.join(SOURCE_ROOT, 'node_modules', 'coffeelint', 'bin',
'coffeelint')
settings = ['--quiet', '-f', os.path.join('script', 'coffeelint.json')]
files = glob.glob('browser/api/lib/*.coffee') + \
glob.glob('renderer/api/lib/*.coffee') + \
glob.glob('common/api/lib/*.coffee') + \
glob.glob('browser/atom/*.coffee')
if sys.platform in ['win32', 'cygwin']:
subprocess.check_call(['node', coffeelint] + settings + files,
executable='C:/Program Files/nodejs/node.exe')
else:
subprocess.check_call(['node', coffeelint] + settings + files)
if __name__ == '__main__':
sys.exit(main())

View File

@@ -4,8 +4,6 @@ import os
import subprocess
import sys
from lib.util import *
SOURCE_ROOT = os.path.dirname(os.path.dirname(__file__))
@@ -22,5 +20,6 @@ def main():
else:
subprocess.check_call(['node', coffee, '-c', '-o', output_dir, input_file])
if __name__ == '__main__':
sys.exit(main())

5
script/cpplint.py vendored
View File

@@ -7,12 +7,11 @@ import sys
IGNORE_FILES = [
'app/win/resource.h',
'browser/atom_event_processing_window.h',
'browser/atom_application_mac.h',
'browser/atom_application_delegate_mac.h',
'browser/native_window_mac.h',
'browser/ui/atom_event_processing_window.h',
'browser/ui/atom_menu_controller_mac.h',
'browser/ui/cocoa/custom_frame_view.h',
'browser/ui/nsalert_synchronous_sheet_mac.h',
'common/api/api_messages.cc',
'common/api/api_messages.h',
@@ -32,7 +31,7 @@ def main():
def list_files(directories, filters):
matches = []
for directory in directories:
for root, dirs, filenames, in os.walk(directory):
for root, _, filenames, in os.walk(directory):
for f in filters:
for filename in fnmatch.filter(filenames, f):
matches.append(os.path.join(root, filename))

View File

@@ -1,14 +1,13 @@
#!/usr/bin/env python
import errno
import glob
import os
import shutil
import subprocess
import sys
import tarfile
from lib.util import *
from lib.util import scoped_cwd, rm_rf, get_atom_shell_version, make_zip, \
safe_mkdir
ATOM_SHELL_VRESION = get_atom_shell_version()
@@ -32,6 +31,7 @@ TARGET_BINARIES = {
],
'win32': [
'atom.exe',
'atom.exe.pdb',
'chromiumcontent.dll',
'content_shell.pak',
'ffmpegsumo.dll',
@@ -79,7 +79,7 @@ def main():
def force_build():
build = os.path.join(SOURCE_ROOT, 'script', 'build.py')
subprocess.check_call([sys.executable, build, '-c', 'Release']);
subprocess.check_call([sys.executable, build, '-c', 'Release'])
def copy_binaries():
@@ -99,7 +99,7 @@ def copy_headers():
# Copy standard node headers from node. repository.
for include_path in HEADERS_DIRS:
abs_path = os.path.join(NODE_DIR, include_path)
for dirpath, dirnames, filenames in os.walk(abs_path):
for dirpath, _, filenames in os.walk(abs_path):
for filename in filenames:
extension = os.path.splitext(filename)[1]
if extension not in HEADERS_SUFFIX:
@@ -111,7 +111,7 @@ def copy_headers():
# Copy V8 headers from chromium's repository.
src = os.path.join(SOURCE_ROOT, 'vendor', 'brightray', 'vendor', 'download',
'libchromiumcontent', 'src')
for dirpath, dirnames, filenames in os.walk(os.path.join(src, 'v8')):
for dirpath, _, filenames in os.walk(os.path.join(src, 'v8')):
for filename in filenames:
extension = os.path.splitext(filename)[1]
if extension not in HEADERS_SUFFIX:
@@ -122,8 +122,7 @@ def copy_headers():
def copy_license():
license = os.path.join(SOURCE_ROOT, 'LICENSE')
shutil.copy2(license, DIST_DIR)
shutil.copy2(os.path.join(SOURCE_ROOT, 'LICENSE'), DIST_DIR)
def create_version():
@@ -138,10 +137,9 @@ def create_zip():
zip_file = os.path.join(SOURCE_ROOT, 'dist', dist_name)
with scoped_cwd(DIST_DIR):
files = TARGET_BINARIES[TARGET_PLATFORM] + \
TARGET_DIRECTORIES[TARGET_PLATFORM] + \
['LICENSE', 'version']
make_zip(zip_file, files)
files = TARGET_BINARIES[TARGET_PLATFORM] + ['LICENSE', 'version']
dirs = TARGET_DIRECTORIES[TARGET_PLATFORM]
make_zip(zip_file, files, dirs)
def create_header_tarball():

69
script/lib/github.py Normal file
View File

@@ -0,0 +1,69 @@
#!/usr/bin/env python
import json
import re
import requests
GITHUB_URL = 'https://api.github.com'
GITHUB_UPLOAD_ASSET_URL = 'https://uploads.github.com'
class GitHub:
def __init__(self, access_token):
self._authorization = 'token %s' % access_token
pattern = '^/repos/{0}/{0}/releases/{1}/assets$'.format('[^/]+', '[0-9]+')
self._releases_upload_api_pattern = re.compile(pattern)
def __getattr__(self, attr):
return _Callable(self, '/%s' % attr)
def send(self, method, path, **kw):
if not 'headers' in kw:
kw['headers'] = dict()
headers = kw['headers']
headers['Authorization'] = self._authorization
headers['Accept'] = 'application/vnd.github.manifold-preview'
# Switch to a different domain for the releases uploading API.
if self._releases_upload_api_pattern.match(path):
url = '%s%s' % (GITHUB_UPLOAD_ASSET_URL, path)
else:
url = '%s%s' % (GITHUB_URL, path)
# Data are sent in JSON format.
if 'data' in kw:
kw['data'] = json.dumps(kw['data'])
r = getattr(requests, method)(url, **kw).json()
if 'message' in r:
raise Exception(json.dumps(r, indent=2, separators=(',', ': ')))
return r
class _Executable:
def __init__(self, gh, method, path):
self._gh = gh
self._method = method
self._path = path
def __call__(self, **kw):
return self._gh.send(self._method, self._path, **kw)
class _Callable(object):
def __init__(self, gh, name):
self._gh = gh
self._name = name
def __call__(self, *args):
if len(args) == 0:
return self
name = '%s/%s' % (self._name, '/'.join([str(arg) for arg in args]))
return _Callable(self._gh, name)
def __getattr__(self, attr):
if attr in ['get', 'put', 'post', 'patch', 'delete']:
return _Executable(self._gh, attr, self._name)
name = '%s/%s' % (self._name, attr)
return _Callable(self._gh, name)

View File

@@ -64,14 +64,19 @@ def extract_zip(zip_path, destination):
with zipfile.ZipFile(zip_path) as z:
z.extractall(destination)
def make_zip(zip_file_path, files):
def make_zip(zip_file_path, files, dirs):
safe_unlink(zip_file_path)
if sys.platform == 'darwin':
files += dirs
subprocess.check_call(['zip', '-r', '-y', zip_file_path] + files)
else:
zip_file = zipfile.ZipFile(zip_file_path, "w")
zip_file = zipfile.ZipFile(zip_file_path, "w", zipfile.ZIP_DEFLATED)
for filename in files:
zip_file.write(filename, filename)
for dirname in dirs:
for root, _, filenames in os.walk(dirname):
for f in filenames:
zip_file.write(os.path.join(root, f))
zip_file.close()

22
script/pylint.py Executable file
View File

@@ -0,0 +1,22 @@
#!/usr/bin/env python
import glob
import os
import subprocess
import sys
SOURCE_ROOT = os.path.dirname(os.path.dirname(__file__))
def main():
os.chdir(SOURCE_ROOT)
pylint = os.path.join(SOURCE_ROOT, 'vendor', 'depot_tools', 'pylint.py')
settings = ['--rcfile=vendor/depot_tools/pylintrc']
pys = glob.glob('script/*.py')
subprocess.check_call([sys.executable, pylint] + settings + pys,
env=dict(PYTHONPATH='script'))
if __name__ == '__main__':
sys.exit(main())

View File

@@ -3,11 +3,11 @@
import sys
import os
from lib.util import *
from lib.util import safe_mkdir, extract_zip, tempdir, download
SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
FRAMEWORKS_URL='https://gh-contractor-zcbenz.s3.amazonaws.com/frameworks'
FRAMEWORKS_URL = 'https://gh-contractor-zcbenz.s3.amazonaws.com/frameworks'
def main():

View File

@@ -1,10 +1,9 @@
#!/usr/bin/env python
import os
import subprocess
import sys
from lib.util import *
SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))

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