Compare commits

...

238 Commits

Author SHA1 Message Date
Cheng Zhao
7ceca9f426 Bump v0.30.1 2015-07-24 16:59:18 +08:00
Cheng Zhao
720dc92efe Merge pull request #2325 from atom/linux-min-max
linux: Fix min/max size not working
2015-07-24 16:57:59 +08:00
Cheng Zhao
73ded9d378 linux: Fix min/max size not working 2015-07-24 16:21:44 +08:00
Cheng Zhao
48975d04e0 Merge pull request #2323 from atom/better-spec
Fix a few flaky tests
2015-07-24 16:21:16 +08:00
Cheng Zhao
417e97eef0 spec: Don't reuse port in session spec 2015-07-24 15:49:19 +08:00
Cheng Zhao
b52c07f650 spec: Make dom-ready spec stronger 2015-07-24 15:48:13 +08:00
Cheng Zhao
1a93b1db52 spec: Make the basic-auth spec stronger 2015-07-24 15:33:07 +08:00
Cheng Zhao
b547772c68 Merge pull request #2321 from atom/web-contents-focus
Focus on WebContents when we load url in BrowserWindow for the first time
2015-07-24 14:24:14 +08:00
Cheng Zhao
d822e0d720 Merge pull request #2320 from atom/appcomands
Fix app-command event always return 'unknown'.
2015-07-24 13:28:30 +08:00
Cheng Zhao
29c574cf0f Focus WebContents when we first load url in BrowserWindow 2015-07-24 13:08:19 +08:00
Haojian Wu
3840a10da6 Fix app-command event always return 'unknown'. 2015-07-24 13:02:11 +08:00
Cheng Zhao
9bb87af66b Add webContents.focus 2015-07-24 12:58:28 +08:00
Cheng Zhao
9ec60cd585 Merge pull request #2316 from tengyifei/master
Only allow extensions explicitly specified by the user. Fixes #2296
2015-07-24 11:11:56 +08:00
Yifei Teng
8960aa956c Only allow extensions explicitly specified by the user. Fixes #2296 2015-07-23 12:30:07 -07:00
Cheng Zhao
de17894fce Merge pull request #2307 from atom/dialog-options
Add "noLink" option for showMessageBox
2015-07-23 17:59:09 +08:00
Cheng Zhao
6c44553456 Show all buttons as custom buttons when noLink is specified 2015-07-23 17:34:35 +08:00
Cheng Zhao
cc2a9f617d Add noLink option for showMessageBox 2015-07-23 17:25:37 +08:00
Cheng Zhao
1578d2fda9 Allow the C++ JS binding function to accept arbitrary long arguments 2015-07-23 15:00:42 +08:00
Cheng Zhao
da724d65d7 Add |options| for ShowMessageBox 2015-07-23 14:16:43 +08:00
Cheng Zhao
eb92e9cdd8 Use node::MakeCallback to emit events in C++
Fix #2165
2015-07-23 13:48:34 +08:00
Cheng Zhao
5a980497e8 Merge pull request #2298 from deepak1556/default_protocol_handler_patch
protocol: fix adapter request job for default handlers
2015-07-23 12:15:54 +08:00
Cheng Zhao
72eb87a631 Make the extraSize of BrowserWindow.setAspectRatio optional 2015-07-23 10:14:02 +08:00
Cheng Zhao
df35700b94 Style fixes
* Use under_score for variable names in C++
* Use const& when possible
* Line length <= 80
2015-07-23 10:07:58 +08:00
Cheng Zhao
ea1b89c699 Merge pull request #2250 from EyeSee360/master
Maintain an aspect ratio for content within a window
2015-07-23 09:45:42 +08:00
Cheng Zhao
a8658b7dca Merge pull request #2302 from etiktin/patch-1
Update dialog.md
2015-07-23 09:42:03 +08:00
Brendon Gonzalez
e64fbe3529 Merge pull request #4 from EyeSee360/msb/electron-pr-update
changes requested for pull request #2250 into electron master
2015-07-22 13:48:51 -04:00
Robo
97c90d31d3 get jsprotocolhandler in IO thread 2015-07-22 21:54:12 +05:30
Robo
a1ec07e07e read post-filtered data when filters are present 2015-07-22 21:45:08 +05:30
Eran Tiktin
d701e1aa40 Update dialog.md
Added a comment about the fact that on Windows, the "question" message box uses the same icon as the "info" message box (Electron uses the task dialog API instead of the message box API). This is because Microsoft's API doesn't supply a default question icon (see `pszIcon` in https://msdn.microsoft.com/en-us/library/windows/desktop/bb760540(v=vs.85).aspx).
2015-07-22 18:13:50 +03:00
Michael S. Barthelemy
6d25c81bd1 changes requested for pull request #2250 into electron master 2015-07-22 10:23:31 -04:00
Robo
58f1907579 protocol: copy headers from original request for custom request job 2015-07-22 13:54:39 +05:30
Cheng Zhao
3250764e72 Merge pull request #2297 from atom/get-user-agent
Implement getUserAgent API.
2015-07-22 15:38:35 +08:00
Haojian Wu
462e6e0a82 Implement getUserAgent API. 2015-07-22 12:25:10 +08:00
Cheng Zhao
59269a70a0 docs: Mention libappindicator1 is required, close #1347 2015-07-21 11:27:43 +08:00
Cheng Zhao
8df8b5731e Merge pull request #2287 from atom/fix-mac-content-size
mac: Always call SetSize for frameless window
2015-07-21 10:53:17 +08:00
Cheng Zhao
dbab889fcc Merge pull request #2232 from atom/status_item_view
Introduce custom status item view on OS X.
2015-07-21 10:36:19 +08:00
Cheng Zhao
891d107a51 mac: Always use GetSize for frameless window 2015-07-21 10:34:37 +08:00
Cheng Zhao
3ea878941b mac: Always call SetSize for framless window 2015-07-21 10:29:05 +08:00
Cheng Zhao
f25cf7481f spec: Test setContentSize for frameless window 2015-07-21 10:17:38 +08:00
Haojian Wu
d342c9a6df Implement 'drop-files' tray event on OS X. 2015-07-20 20:06:15 +08:00
Cheng Zhao
a1f0c24bf4 Merge pull request #2270 from UsabilityEtc/patch-1
Improve grammar and sentence structure of app.md
2015-07-20 18:40:09 +08:00
Cheng Zhao
a11d8ea558 Merge pull request #2246 from deepak1556/session_proxy_api
session: api to set proxy
2015-07-20 18:29:53 +08:00
Cheng Zhao
f6263f8c6b Update brightray for #2238 2015-07-20 18:27:49 +08:00
Robo
d3055a5ca0 session: api to set proxy 2015-07-20 15:21:47 +05:30
Jeffrey Morgan
5010c15ffc Improve grammar and sentence structure of app.md
Improve the grammar and sentence structure of app.md. Replace references to Mac with OS X for consistency with other docs and use the OS X nomenclature of notification rather than message.
2015-07-18 15:40:01 +01:00
Michael S. Barthelemy
6656afd57f fix bug with computing the case where we should constrain via height 2015-07-17 10:25:30 -04:00
Cheng Zhao
8cf9df2d8d docs: Mention null session of RequestHttpJob 2015-07-16 15:17:45 -07:00
Cheng Zhao
3145c78b61 Merge pull request #2207 from deepak1556/fetch_job_patch
protocol: create separate request context for fetch job
2015-07-16 15:14:45 -07:00
Robo
de3ccc4b98 use current session when not defined 2015-07-17 02:00:43 +05:30
Michael S. Barthelemy
d0c6176640 wrap lines to meet Travis CI build requirements 2015-07-16 14:45:27 -04:00
Michael S. Barthelemy
7cdfa44438 shorten names 2015-07-16 14:31:01 -04:00
Michael S. Barthelemy
10faf314d4 fix line length issue 2015-07-16 14:26:48 -04:00
mbarthelemy
378e81ffaa Merge pull request #1 from EyeSee360/msb/aspect-ratio
add function maintainAspectRatioOfInteriorContent to BrowserWindow
2015-07-16 14:01:55 -04:00
Michael S. Barthelemy
423ea00263 Merge branch 'master' into msb/aspect-ratio 2015-07-16 13:57:38 -04:00
Michael S. Barthelemy
666aca7803 add function maintainAspectRatioOfInteriorContent to BrowserWindow in order to enforce an aspect ratio for an electron window 2015-07-16 13:54:51 -04:00
Cheng Zhao
135aca02af Bump v0.30.0 2015-07-17 01:01:25 +08:00
Cheng Zhao
7ab8134613 Don't upload PDB files in CI
Somehow it is blocking.
2015-07-17 00:54:57 +08:00
Robo
57244e4718 use request context from session if provided 2015-07-16 20:18:33 +05:30
Robo
8eb87c5d2b protocol: create separate request context for fetch job 2015-07-16 20:18:33 +05:30
Cheng Zhao
02cadde8de Merge pull request #2200 from atom/input_accept_attr
Enable 'accept' attribute in 'input' label.
2015-07-16 07:20:30 -07:00
Cheng Zhao
88ab23def9 Update brightray for #1852 2015-07-16 06:36:10 -07:00
Cheng Zhao
db6d8de5dc docs: Say more about standard scheme 2015-07-16 06:32:09 -07:00
Cheng Zhao
652843f447 Merge pull request #2234 from astoilkov/patch-1
fix typo in browser-window.md
2015-07-16 04:34:23 -07:00
Haojian Wu
21e5054fac Make <input type="file"\> remember last used directory. 2015-07-16 19:29:12 +08:00
Cheng Zhao
a2c26b8c74 Fix hanlding trailing slash in asar package, close #2222 2015-07-16 03:49:26 -07:00
Haojian Wu
2cd6ad1a97 More code style fixing. 2015-07-16 18:42:20 +08:00
Cheng Zhao
78e55414d4 Merge pull request #2235 from mhkeller/doc-json-fix
valid example json, fix https://github.com/atom/electron/issues/2228
2015-07-16 02:53:59 -07:00
Haojian Wu
17628b3e40 📝 tray.popContextMenu API. 2015-07-16 11:53:13 +08:00
Haojian Wu
736fe0c1db Fix OS X build error. 2015-07-16 11:43:42 +08:00
Haojian Wu
ed4c69343f Add 'tray.popContextMenu()' Windows implementation. 2015-07-16 11:42:43 +08:00
Haojian Wu
4421fbf9f3 Implement 'tray.popContextMenu' API on OS X. 2015-07-16 10:50:53 +08:00
Haojian Wu
002eb1a326 Simplify code logic and fix object-c code style. 2015-07-16 10:49:55 +08:00
Jeffrey Morgan
4baaf03ac7 Improve grammar and comments
Improve the grammar and sentence structure of the text and improve the code comments.
2015-07-15 16:48:24 -07:00
Cheng Zhao
c2bfc60a59 Merge pull request #2216 from UsabilityEtc/patch-1
Improve grammar and code formatting
2015-07-15 16:44:20 -07:00
Cheng Zhao
f78dcfb8e0 Merge pull request #2214 from PButcher/patch-1
Update window-open.md
2015-07-15 16:43:50 -07:00
Cheng Zhao
91bfd1f77c Merge pull request #2206 from dalinaum/patch-1
Update README-ko.md
2015-07-15 13:14:05 -07:00
Cheng Zhao
9ee0d46734 Use CTRL+SHIFT+I for toggling devtools, fix #2205 2015-07-15 13:11:01 -07:00
mhkeller
ca2cb9c9ba valid example json, fix https://github.com/atom/electron/issues/2228 2015-07-15 10:34:33 -04:00
Antonio Stoilkov
00c484c68b fix typo in browser-window.md 2015-07-15 17:29:02 +03:00
Haojian Wu
38c33d69ae 📝 'right-clicked' doc. 2015-07-15 20:13:59 +08:00
Haojian Wu
5ad3fff6a0 Implement 'right-clicked' tray event on Windows. 2015-07-15 20:03:05 +08:00
Haojian Wu
cca4f4abd5 Implement 'right-clicked' tray event on OS X. 2015-07-15 19:32:00 +08:00
Haojian Wu
e54fda6b34 Introduce Electron custom statusItem view.
Reimplement tray functions on OS X by using custom statusItem view.
2015-07-15 18:26:39 +08:00
Cheng Zhao
1e9eccf959 Forward the crashed event to BrowserWindow, fix #2201 2015-07-14 15:13:41 -07:00
Cheng Zhao
4b06c0645c Merge pull request #2220 from atom/provide-user-agent
Provide default user agent in BrowserContext
2015-07-14 13:17:36 -07:00
Cheng Zhao
c6f870d4e4 Fix cpplint warnings 2015-07-14 12:16:13 -07:00
Cheng Zhao
053594eae8 Set default user agent for WebContents 2015-07-14 12:13:25 -07:00
Cheng Zhao
1615c97ce8 Don't set two "Electron"s in user agent 2015-07-14 12:12:55 -07:00
Cheng Zhao
940db1d1dd Provide default user agent in BrowserContext 2015-07-14 11:40:15 -07:00
Cheng Zhao
56dfef8d0d spec: Test user agent in websocket 2015-07-14 11:39:41 -07:00
Cheng Zhao
3ffd774405 Merge pull request #2197 from deepak1556/user_agent_patch
webContents: set http useragent settings when overriding user agent
2015-07-14 09:59:09 -07:00
Cheng Zhao
076942ca7a Merge pull request #2215 from atom/delete-global
Don't expose "global" when node integration is off
2015-07-14 09:53:44 -07:00
Cheng Zhao
b6e8420bf2 spec: Check if window.global is set 2015-07-14 09:15:03 -07:00
Cheng Zhao
096439dce7 Don't expose "global" when node integration is off 2015-07-14 09:15:03 -07:00
Cheng Zhao
346fb745f2 No need to actually create a page for cookie test 2015-07-14 09:14:22 -07:00
Cheng Zhao
020ccd8018 spec: Cookie test should not rely on cookie's count
Other apps can also write cookie to `file://` protocol.
2015-07-14 08:59:06 -07:00
Jeffrey Morgan
ce24226128 Update global-shortcut.md
Improved the grammar and code formatting of global-shortcut.md.
2015-07-14 16:58:15 +01:00
Peter Butcher
b3c51e46e7 Update window-open.md
Just an irritating typo.
2015-07-14 16:37:52 +01:00
Cheng Zhao
886db7a3f2 Merge pull request #2195 from atom/jl-docs-typo
Fix docs typo
2015-07-14 08:35:33 -07:00
Cheng Zhao
6c5dde60a3 Merge pull request #2211 from atom/no-heap-stl
Avoiding creating static STL containers
2015-07-14 02:48:05 -07:00
Cheng Zhao
7f06072420 Avoiding creating static STL containers
It is OK under most cases, but if you happen to also use COM in your
application, you will have heap corruptions.
2015-07-14 17:33:16 +08:00
Cheng Zhao
5708b7fbec Fix the ill cookie test 2015-07-14 02:32:20 -07:00
Cheng Zhao
5863ed4c33 win: Also map MESSAGE_BOX_TYPE_QUESTION to TD_INFORMATION_ICON 2015-07-13 21:51:19 -07:00
Cheng Zhao
14388feb23 Merge pull request #2187 from jprichardson/patch-1
emit error object on process.on('uncaughtException') in renderer
2015-07-13 21:46:06 -07:00
Cheng Zhao
e5f852d7d5 docs: Adds the dependencies of arm target
Close #2181
2015-07-13 15:26:35 -07:00
Cheng Zhao
83e8ceceda Fix session specs 2015-07-13 15:23:02 -07:00
Cheng Zhao
3ef54147c9 Merge pull request #2179 from deepak1556/proxy_patch
doc: kProxyPacUrl support
2015-07-13 15:14:58 -07:00
Cheng Zhao
f8df377631 Update brightray, refs #1599 2015-07-13 15:14:28 -07:00
Cheng Zhao
868dee55de The options of clearStorageData should be optional 2015-07-13 15:13:17 -07:00
Cheng Zhao
7dba4d1d8d Call callback of ClearCache after cache is doomed 2015-07-13 14:27:07 -07:00
Cheng Zhao
6840d424cd docs: Add WebContents.session 2015-07-13 12:41:07 -07:00
Cheng Zhao
34819140c3 Merge pull request #2102 from deepak1556/storage_cleanup_api_patch
app: api to clear data from different storage types
2015-07-13 12:34:48 -07:00
Cheng Zhao
9e8a118d10 Cleanup code 2015-07-14 03:23:19 +08:00
Cheng Zhao
0c7c6ddcc9 Merge pull request #2175 from atom/propagate-app-model-id
Propagate App Model User ID on Windows
2015-07-13 12:16:10 -07:00
LYK
eadd2f8de6 Update README-ko.md
Remove a personal email address and repository.
2015-07-13 23:29:06 +09:00
Haojian Wu
04606a9f97 Enable 'accept' attribute in 'input' label. 2015-07-13 14:47:30 +08:00
Robo
cb4309bbd9 webContents: set http useragent settings when overriding user agent 2015-07-13 02:20:15 +05:30
Jessica Lord
1249196118 Fix docs typo
It was breaking the docs site build because it's a code block type
2015-07-11 19:46:26 -07:00
JP Richardson
d6ae874038 emit error object on process.on('uncaughtException') in renderer
Chromium added the actual `error` object to the 5th parameter in `window.onerror`. This should be emitted as opposed to the `errorMsg` string. Worse yet, since `errorMsg` wasn't an instance of `Error`, any code that assumes this in any `process.on('uncaughtException')` handler would fail. Also, correctly emitting the error provides the stack trace.

This is now an HTML5 standard.

Sources:
- https://html.spec.whatwg.org/multipage/webappapis.html#errorevent
- https://mikewest.org/2013/08/debugging-runtime-errors-with-window-onerror
- https://code.google.com/p/chromium/issues/detail?id=147127
2015-07-10 14:38:03 -05:00
Robo
e0e4c1b54c doc: kProxyPacUrl support 2015-07-10 13:56:21 +05:30
Robo
628fb5f5e9 app: api to clear data from different storage types 2015-07-10 11:31:30 +05:30
Cheng Zhao
967c273ddb Always use top window's context for resolving url
Refs #2166.
2015-07-10 13:57:09 +08:00
Cheng Zhao
a24d2921af Merge pull request #2164 from hankbao/global-shortcut-doc-update
Update global-shortcut.md
2015-07-10 13:33:07 +08:00
Cheng Zhao
5ae57baf11 Allow more insecure content when web-security is off
Close #2076
2015-07-10 13:29:46 +08:00
Cheng Zhao
7a390bdd4c Merge pull request #2125 from deepak1556/protocol_cleanup
protocol: cleanup
2015-07-10 12:16:17 +08:00
Cheng Zhao
72f4884127 Merge pull request #2144 from deepak1556/clipboard_multiwrite_patch
clipboard: api to write multiple formats to same writer
2015-07-10 12:14:58 +08:00
Cheng Zhao
6383eb876e Fix failed specs caused by window.open url parsing 2015-07-10 12:14:25 +08:00
Robo
c56b3425a9 read/write protocol handler map in IO 2015-07-10 09:33:36 +05:30
Robo
2d3e938a7f clipboard: api to write multiple formats to same writer 2015-07-10 09:20:52 +05:30
Cheng Zhao
260ec96edd Resolve relative urls in window.open, fix #2166 2015-07-10 11:36:41 +08:00
Cheng Zhao
4379d24e9d Event "close" => "closed", fix #2149 2015-07-10 10:38:15 +08:00
Cheng Zhao
fedf764b7b Merge pull request #2161 from atom/close-test
Add a test to verify the WebView close event
2015-07-10 10:36:23 +08:00
Paul Betts
39c6e2d2e5 Linter fixes 2015-07-09 17:00:19 -07:00
Paul Betts
35aaad68d7 Set the AppUserModelId on the renderer side 2015-07-09 16:48:02 -07:00
Paul Betts
779583adf5 Append the app user model ID as a switch 2015-07-09 16:37:12 -07:00
Paul Betts
a0784bd038 Add a new renderer switch to pass down the app model ID 2015-07-09 16:37:11 -07:00
Hank Bao
fc9612a5ed Fix sample code indention 2015-07-09 22:49:16 +08:00
Robo
2cd5fb5694 add compatibility will old api 2015-07-09 14:48:58 +05:30
Robo
da00329d78 protocol: cleanup 2015-07-09 14:48:58 +05:30
Hank Bao
fb99bfac52 Update sample code in global-shortcut.md 2015-07-09 17:03:58 +08:00
Hank Bao
7b19b6b4f2 Update global-shortcut.md
Make it clear that the `global-shortcut` module should not be used until the ready event of app module gets emitted.
2015-07-09 12:30:37 +08:00
Kevin Sawicki
d661099322 Merge pull request #2159 from atom/code-of-conduct
Code of Conduct
2015-07-08 15:22:40 -07:00
Paul Betts
ea63a04388 Add a test to verify the webview close event 2015-07-08 14:34:44 -07:00
Brandon Keepers
6f92141587 Add code of conduct to README 2015-07-08 16:29:24 -04:00
Brandon Keepers
078bd7fb5b Add code of conduct to contributing guidelines 2015-07-08 16:23:06 -04:00
Cheng Zhao
1703a6f20e Merge pull request #2152 from atom/task-dialog
Implement showMessageBox with TaskDialogIndirect
2015-07-08 16:41:29 +08:00
Cheng Zhao
001b4a3179 Final cleanup 2015-07-08 16:24:39 +08:00
Cheng Zhao
aab78db8b8 On Windows "Cancel" button is also forced to be canclId 2015-07-08 16:00:30 +08:00
Cheng Zhao
9793473b10 Show custom buttons as links 2015-07-08 15:57:45 +08:00
Cheng Zhao
a89e5592f2 Use stock buttons on Windows when possible 2015-07-08 15:55:53 +08:00
Cheng Zhao
989351a41d Show user's icon when specified 2015-07-08 15:04:34 +08:00
Cheng Zhao
6fb8b2ce4f Show icon according to dialog's type 2015-07-08 14:46:06 +08:00
Cheng Zhao
f0be4025a5 If "detail" is empty then don't make message hilighted 2015-07-08 14:41:19 +08:00
Cheng Zhao
49da74f976 Handle when dialog is cancelled 2015-07-08 14:35:28 +08:00
Cheng Zhao
1146441c2a Implement ShowMessageBox with TaskDialog 2015-07-08 14:12:11 +08:00
Cheng Zhao
d01c200345 Set compilation requirements for using TaskDialogIndirect
* Link with Comctl32.lib
* Update manifest file to use common controls v6

Thanks @vinnyp for finding out how to make it work
2015-07-08 13:30:04 +08:00
Cheng Zhao
b7cdb00d09 Hard code the chromedriver's version
It is not possible to run chromedriver for all targets.
2015-07-08 12:53:33 +08:00
Cheng Zhao
cb92df687d Upload PDBs to Windows symbol server 2015-07-08 12:12:28 +08:00
Cheng Zhao
2e51afcd9e Merge pull request #2150 from mattdesl/patch-2
improve docs on toJpeg(quality)
2015-07-08 11:10:16 +08:00
Cheng Zhao
fdc01b8ba8 Merge pull request #2146 from atom/cancel-id
Add "cancelId" option for showMessageBox
2015-07-08 10:08:39 +08:00
Cheng Zhao
e0528655a8 Merge pull request #2133 from atom/app_dir_api
Implment app.getAppPath API.
2015-07-08 10:08:22 +08:00
Matt DesLauriers
08983e1ba9 improve docs on toJpeg(quality) 2015-07-07 20:20:20 -04:00
Cheng Zhao
7d456d3556 docs: cancelId 2015-07-07 18:51:49 +08:00
Cheng Zhao
df4b5f4ede On OS X the "Cancel" is always get selected when dialog is cancelled 2015-07-07 18:45:43 +08:00
Cheng Zhao
fb537d91fc Set default cancelId in JavaScript 2015-07-07 18:39:08 +08:00
Cheng Zhao
b158427271 Add cancelId option for showMessageBox 2015-07-07 18:39:08 +08:00
Cheng Zhao
083d0b8b60 Merge pull request #2145 from atom/gtk-message-box
Use GtkMessageBox for dialog.showMessageBox on Linux
2015-07-07 18:08:06 +08:00
Haojian Wu
a2857d2dca Implment app.getAppPath API. 2015-07-07 17:37:53 +08:00
Cheng Zhao
a90a994a89 Bump v0.29.2 2015-07-07 17:22:05 +08:00
Cheng Zhao
a2d1ec2c1f Make "title" work 2015-07-07 17:21:30 +08:00
Cheng Zhao
9b25c16980 Allow "detail" to be empty 2015-07-07 17:21:30 +08:00
Cheng Zhao
810f14aecb Simplify the code 2015-07-07 17:21:30 +08:00
Cheng Zhao
e627592eed Reuse ShowMessageBox in ShowErrorBox 2015-07-07 17:21:30 +08:00
Cheng Zhao
3e6394a004 gtk: Map dialog type to message box type 2015-07-07 17:21:30 +08:00
Cheng Zhao
02e28ea758 Fix focusing message box 2015-07-07 17:21:30 +08:00
Cheng Zhao
b98cdf71c4 gtk: Implement message box APIs 2015-07-07 17:21:26 +08:00
Cheng Zhao
8fca1f52d3 Use SetGtkTransientForAura from libgtk2ui 2015-07-07 15:12:08 +08:00
Cheng Zhao
1ff00281f3 Seperate linux's implementation of message box 2015-07-07 15:12:08 +08:00
Cheng Zhao
7bcbad925e Install libnss3-dev on CI 2015-07-07 14:42:02 +08:00
Cheng Zhao
3fa1f3ca6f Run clean after cibuild 2015-07-07 14:36:44 +08:00
Cheng Zhao
5e7f1ce383 linux: Link with nss 2015-07-07 14:16:31 +08:00
Cheng Zhao
79b0fe967b Merge pull request #2142 from atom/no-back-on-backspace
Do not navigate back when backspace is pressed
2015-07-07 13:57:00 +08:00
Cheng Zhao
d3204e9a9d Update libchromiumcontent
This applies the patch that disables navigating back when backspace is
pressed.
2015-07-07 13:39:55 +08:00
Cheng Zhao
808ceb8811 Merge pull request #2140 from mattdesl/patch-1
Document `process.platform` check in example
2015-07-07 11:45:10 +08:00
Cheng Zhao
74603624df Merge pull request #2138 from atom/window-move-issue
Fix a type error on window.moveTo API.
2015-07-07 11:29:06 +08:00
Matt DesLauriers
0c0446e254 explain the process.platform check 2015-07-06 20:38:38 -04:00
Haojian Wu
41c1a34b4f Fix a type error on window.moveTo API. 2015-07-07 07:25:58 +08:00
Cheng Zhao
519b51f055 Merge pull request #2134 from fbrinker/patch-1
Update using-native-node-modules.md
2015-07-06 22:04:15 +08:00
Cheng Zhao
5e2481e631 Merge pull request #2136 from atom/check-object-life
Check whether object is destroyed before calling its methods
2015-07-06 21:56:59 +08:00
Cheng Zhao
f8786e9d17 No need to send message to embedder after it is closed 2015-07-06 21:28:09 +08:00
Cheng Zhao
85a4ff83da Some methods can be accessed after object is destroyed 2015-07-06 21:26:50 +08:00
Florian Brinker
7231de7c2b Update using-native-node-modules.md
update to newest version and x64 fix for popular systems
2015-07-06 14:05:15 +02:00
Cheng Zhao
ae52af3870 Check BrowserWindow's lifetime 2015-07-06 18:28:42 +08:00
Cheng Zhao
1569dfa2e8 Remove manual lifetime check for Tray 2015-07-06 18:24:40 +08:00
Cheng Zhao
54dac0f37a Check whether WebContents lives before using its methods
Close #2064.
2015-07-06 18:21:04 +08:00
Cheng Zhao
9cf09b8850 Update native_mate to have ability to check object's live 2015-07-06 18:20:39 +08:00
Cheng Zhao
ae3b47aa75 Inherit current window's node-integration in window.open by default
Fix #2100.
2015-07-06 16:21:08 +08:00
Cheng Zhao
99e8238f90 Merge pull request #2131 from atom/cursors
win: Build with cursors from Chromium
2015-07-06 15:49:11 +08:00
Cheng Zhao
f5a1ffcbd4 win: Build with cursors from Chromium 2015-07-06 15:19:28 +08:00
Cheng Zhao
7042054913 Merge pull request #2128 from atom/no-openssl
Don't force using OpenSSL on linux
2015-07-06 15:18:57 +08:00
Cheng Zhao
16fd56c083 Update libchromiumcontent to include cursors
Refs: #1361.
2015-07-06 14:40:51 +08:00
Cheng Zhao
9afc016ff9 Allow ia32 and arm builds to fail for now
The ia32 and arm libchromiumcontent can not build on CI for now.
2015-07-06 14:39:40 +08:00
Cheng Zhao
3064afbac4 Merge pull request #2119 from deepak1556/linux_doc_patch
doc: linux troubleshooting libtinfo.so.5 not found
2015-07-06 12:29:40 +08:00
Cheng Zhao
1979b42ee7 OpenSSL is still used on Windows and Mac 2015-07-06 12:07:19 +08:00
Cheng Zhao
68155e5fb7 Don't use OpenSSL for networking 2015-07-06 10:53:00 +08:00
Cheng Zhao
9f0571772d Merge pull request #2117 from tommoor/patch-4
Fixed and clarified crash-reporter documentation
2015-07-06 09:55:50 +08:00
Cheng Zhao
07cf2eac4e Merge pull request #2113 from atom/libchromiumcontent-mirror
Allow downloading prebuilt libchromiumcontent binaries from mirror
2015-07-06 09:52:43 +08:00
Cheng Zhao
822efa2f97 Merge pull request #2109 from krainboltgreene/patch-1
Typo in function name for remote
2015-07-05 22:55:09 +08:00
Cheng Zhao
0e888ccf22 Merge pull request #2105 from deepak1556/ppapi_browser_patch
plugin: dont check renderer flags for adding pepper browser host filters
2015-07-05 22:54:35 +08:00
Haojian Wu
f5b502186b 📝 Add mirror address description. 2015-07-05 22:50:36 +08:00
Cheng Zhao
4e94e0c82f Merge pull request #2093 from preco21/master
Translate docs into korean #2 + added link of power-save-blocker API to README
2015-07-05 21:21:56 +08:00
Cheng Zhao
3315e6bda5 Merge pull request #2080 from deepak1556/linux_fullscreen_patch
window: use _NET_WM_STATE_FULLSCREEN before window is mapped
2015-07-05 16:44:42 +08:00
Cheng Zhao
506d6688e0 Merge pull request #2074 from ankitaggarwal011/windows-fullscreen-bug
🐛 Solves issue #2047 [Windows fullscreen bug]
2015-07-05 16:25:26 +08:00
Robo
c7518f84f8 doc: linux troubleshooting libtinfo.so.5 not found 2015-07-04 10:52:18 +05:30
Tom Moor
cb3e758bc6 Fixed and clarified crash-reporter documentation
It was unclear to us until we looked through the atom source code that crashReporter.start must be ran in each renderer process
2015-07-03 11:34:36 -07:00
Cheng Zhao
2bcf8c7bc2 Bump v0.29.1 2015-07-03 23:33:49 +08:00
Cheng Zhao
bea45867d2 Remove ~/.node-gyp in clean script 2015-07-03 23:33:49 +08:00
Cheng Zhao
70987a9029 Checkout boto in our repo 2015-07-03 23:33:49 +08:00
Cheng Zhao
5c85c2e5d5 Update node 2015-07-03 22:12:19 +08:00
Cheng Zhao
6f137d62c7 Revert "Set openssl_fips in config.gypi"
This reverts commit 26525d6b0f.
2015-07-03 22:08:53 +08:00
Cheng Zhao
3533be2f9f Fist line of config.gypi should be empty 2015-07-03 21:41:27 +08:00
Cheng Zhao
a1b28c362d Revert "Get the pending version from the commit message"
This reverts commit 16acd669a7.
2015-07-03 21:21:19 +08:00
Cheng Zhao
26525d6b0f Set openssl_fips in config.gypi 2015-07-03 20:56:49 +08:00
Cheng Zhao
16acd669a7 Get the pending version from the commit message 2015-07-03 20:38:34 +08:00
Cheng Zhao
a3463119e8 Don't warn arch on Windows 2015-07-03 18:03:52 +08:00
Cheng Zhao
9159b06835 Fix uploading headers when release draft exists 2015-07-03 17:44:36 +08:00
Cheng Zhao
4c76112698 Don't check valid upload when -p is specified 2015-07-03 17:28:36 +08:00
Cheng Zhao
d158dbdb68 Don't check build version for arm target 2015-07-03 09:01:16 +00:00
Robo
7576de639b plugin: dont check for renderer flags for adding pepper browser host filters 2015-07-03 13:50:16 +05:30
Haojian Wu
960b279419 Allow downloading prebuilt libchromiumcontent binaries from
LIBCHROMIUMCONENT_MIRROR.
2015-07-03 12:13:40 +08:00
Kurtis Rainbolt-Greene
6902b876a8 Typo in function name for remote 2015-07-02 21:58:31 -05:00
Plusb Preco
dcd10d1e4b Translated API docs, added power-save-blocker API to README 2015-07-01 14:57:14 +09:00
Plusb Preco
783e4bc591 Translate some apis 2015-07-01 03:42:29 +09:00
Robo
b5c5cce725 window: use _NET_WM_STATE_FULLSCREEN before window is mapped 2015-06-29 19:44:56 +05:30
Plusb Preco
fcf4da1097 Fix charsets, add more translated files 2015-06-29 21:41:11 +09:00
ankitaggarwal011
1c907ffa36 🐛 Solves issue #2047 [Windows fullscreen bug] 2015-06-29 00:10:51 +05:30
Plusb Preco
ebb031dafe Fix typos, add more files 2015-06-26 13:06:12 +09:00
Plusb Preco
bf5b084945 Fix some typos and translate more files 2015-06-26 13:06:10 +09:00
165 changed files with 6494 additions and 1414 deletions

3
.gitmodules vendored
View File

@@ -19,3 +19,6 @@
[submodule "vendor/requests"]
path = vendor/requests
url = https://github.com/kennethreitz/requests
[submodule "vendor/boto"]
path = vendor/boto
url = https://github.com/boto/boto.git

View File

@@ -17,5 +17,8 @@ matrix:
env: TARGET_ARCH=arm
- os: linux
env: TARGET_ARCH=ia32
allow_failures:
- env: TARGET_ARCH=arm
- env: TARGET_ARCH=ia32
script: './script/cibuild'

View File

@@ -2,6 +2,9 @@
:+1::tada: First off, thanks for taking the time to contribute! :tada::+1:
This project adheres to the [Open Code of Conduct][code-of-conduct]. By participating, you are expected to uphold this code.
[code-of-conduct]: http://todogroup.org/opencodeofconduct/#Electron/opensource@github.com
The following is a set of guidelines for contributing to Electron.
These are just guidelines, not rules, use your best judgment and feel free to
propose changes to this document in a pull request.

View File

@@ -33,8 +33,8 @@ npm install electron-prebuilt --save-dev
## 참조문서
[docs](https://github.com/preco21/electron/tree/master/docs) 에 프레임워크 사용 가이드와 API 레퍼런스가 있습니다.
또한, Electron을 빌드 하는 방법과 프로젝트에 기여하는 방법 문서에 포함되어 있으니 참고바랍니다.
[docs](https://github.com/atom/electron/tree/master/docs/README-ko.md) 에 프레임워크 사용 가이드와 API 레퍼런스가 있습니다.
추가적으로 Electron을 빌드 하는 방법과 프로젝트에 기여하는 방법 문서에 포함되어 있으니 참고하기 바랍니다.
## 커뮤니티

View File

@@ -14,6 +14,9 @@ editor](https://github.com/atom/atom).
Follow [@ElectronJS](https://twitter.com/electronjs) on Twitter for important
announcements.
This project adheres to the [Open Code of Conduct][code-of-conduct]. By participating, you are expected to uphold this code.
[code-of-conduct]: http://todogroup.org/opencodeofconduct/#Electron/opensource@github.com
## Downloads
Prebuilt binaries and debug symbols of Electron for Linux, Windows and Mac can

View File

@@ -4,7 +4,7 @@
'product_name%': 'Electron',
'company_name%': 'GitHub, Inc',
'company_abbr%': 'github',
'version%': '0.29.0',
'version%': '0.30.1',
},
'includes': [
'filenames.gypi',
@@ -116,6 +116,15 @@
],
}], # OS!="mac"
['OS=="win"', {
'include_dirs': [
'<(libchromiumcontent_dir)/gen/ui/resources',
],
'msvs_settings': {
'VCManifestTool': {
'EmbedManifest': 'true',
'AdditionalManifestFiles': 'atom/browser/resources/win/atom.manifest',
}
},
'copies': [
{
'variables': {
@@ -263,8 +272,9 @@
'libraries': [
'-limm32.lib',
'-loleacc.lib',
'-lComdlg32.lib',
'-lWininet.lib',
'-lcomctl32.lib',
'-lcomdlg32.lib',
'-lwininet.lib',
],
},
'dependencies': [

View File

@@ -41,27 +41,25 @@ namespace {
void ShowMessageBox(int type,
const std::vector<std::string>& buttons,
const std::vector<std::string>& texts,
int cancel_id,
int options,
const std::string& title,
const std::string& message,
const std::string& detail,
const gfx::ImageSkia& icon,
atom::NativeWindow* window,
mate::Arguments* args) {
// FIXME We are exceeding the parameters limit of base::Bind here, so we have
// to pass some parameters in an array. We should remove this once we have
// variadic template support in base::Bind.
const std::string& title = texts[0];
const std::string& message = texts[1];
const std::string& detail = texts[2];
v8::Local<v8::Value> peek = args->PeekNext();
atom::MessageBoxCallback callback;
if (mate::Converter<atom::MessageBoxCallback>::FromV8(args->isolate(),
peek,
&callback)) {
atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons, title,
message, detail, icon, callback);
atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons, cancel_id,
options, title, message, detail, icon, callback);
} else {
int chosen = atom::ShowMessageBox(window, (atom::MessageBoxType)type,
buttons, title, message, detail, icon);
buttons, cancel_id, options, title,
message, detail, icon);
args->Return(chosen);
}
}

View File

@@ -7,6 +7,7 @@
#include "atom/browser/atom_browser_client.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/api/atom_api_session.h"
#include "atom/browser/net/adapter_request_job.h"
#include "atom/browser/net/atom_url_request_job_factory.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
@@ -25,7 +26,7 @@ namespace mate {
template<>
struct Converter<const net::URLRequest*> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const net::URLRequest* val) {
const net::URLRequest* val) {
return mate::ObjectTemplateBuilder(isolate)
.SetValue("method", val->method())
.SetValue("url", val->url().spec())
@@ -34,8 +35,24 @@ struct Converter<const net::URLRequest*> {
}
};
} // namespace mate
template<>
struct Converter<net::URLRequestContextGetter*> {
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
net::URLRequestContextGetter** out) {
if (val->IsNull()) {
*out = nullptr;
return true;
}
atom::api::Session* session;
if (!Converter<atom::api::Session*>::FromV8(isolate, val, &session))
return false;
*out = session->browser_context()->GetRequestContext();
return true;
}
};
} // namespace mate
namespace atom {
@@ -63,16 +80,13 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
registry_(registry) {
}
// AdapterRequestJob:
void GetJobTypeInUI() override {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
void GetJobTypeInUI(const Protocol::JsProtocolHandler& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
v8::Locker locker(registry_->isolate());
v8::HandleScope handle_scope(registry_->isolate());
// Call the JS handler.
Protocol::JsProtocolHandler callback =
registry_->GetProtocolHandler(request()->url().scheme());
v8::Local<v8::Value> result = callback.Run(request());
// Determine the type of the job we are going to create.
@@ -127,13 +141,16 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
} else if (name == "RequestHttpJob") {
GURL url;
std::string method, referrer;
net::URLRequestContextGetter* getter =
registry_->browser_context()->GetRequestContext();
dict.Get("url", &url);
dict.Get("method", &method);
dict.Get("referrer", &referrer);
dict.Get("session", &getter);
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&AdapterRequestJob::CreateHttpJobAndStart, GetWeakPtr(),
registry_->browser_context(), url, method, referrer));
base::Unretained(getter), url, method, referrer));
return;
}
}
@@ -152,6 +169,14 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
GetWeakPtr(), net::ERR_NOT_IMPLEMENTED));
}
// AdapterRequestJob:
void GetJobType() override {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&CustomProtocolRequestJob::GetJobTypeInUI,
base::Unretained(this),
registry_->GetProtocolHandler(request()->url().scheme())));
}
private:
Protocol* registry_; // Weak, the Protocol class is expected to live forever.
};
@@ -189,6 +214,26 @@ class CustomProtocolHandler : public ProtocolHandler {
DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler);
};
std::string ConvertErrorCode(int error_code) {
switch (error_code) {
case Protocol::ERR_SCHEME_REGISTERED:
return "The Scheme is already registered";
case Protocol::ERR_SCHEME_UNREGISTERED:
return "The Scheme has not been registered";
case Protocol::ERR_SCHEME_INTERCEPTED:
return "There is no protocol handler to intercept";
case Protocol::ERR_SCHEME_UNINTERCEPTED:
return "The protocol is not intercepted";
case Protocol::ERR_NO_SCHEME:
return "The Scheme does not exist.";
case Protocol::ERR_SCHEME:
return "Cannot intercept custom protocols";
default:
NOTREACHED();
return std::string();
}
}
} // namespace
Protocol::Protocol(AtomBrowserContext* browser_context)
@@ -202,42 +247,30 @@ Protocol::JsProtocolHandler Protocol::GetProtocolHandler(
return protocol_handlers_[scheme];
}
void Protocol::OnIOActionCompleted(const JsCompletionCallback& callback,
int error) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
if (error) {
callback.Run(v8::Exception::Error(
mate::StringToV8(isolate(), ConvertErrorCode(error))));
return;
}
callback.Run(v8::Null(isolate()));
}
mate::ObjectTemplateBuilder Protocol::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("registerProtocol", &Protocol::RegisterProtocol)
.SetMethod("unregisterProtocol", &Protocol::UnregisterProtocol)
.SetMethod("registerStandardSchemes", &Protocol::RegisterStandardSchemes)
.SetMethod("isHandledProtocol", &Protocol::IsHandledProtocol)
.SetMethod("interceptProtocol", &Protocol::InterceptProtocol)
.SetMethod("uninterceptProtocol", &Protocol::UninterceptProtocol);
}
void Protocol::RegisterProtocol(v8::Isolate* isolate,
const std::string& scheme,
const JsProtocolHandler& callback) {
if (ContainsKey(protocol_handlers_, scheme) ||
job_factory_->IsHandledProtocol(scheme))
return node::ThrowError(isolate, "The scheme is already registered");
protocol_handlers_[scheme] = callback;
BrowserThread::PostTask(BrowserThread::IO,
FROM_HERE,
base::Bind(&Protocol::RegisterProtocolInIO,
base::Unretained(this), scheme));
}
void Protocol::UnregisterProtocol(v8::Isolate* isolate,
const std::string& scheme) {
ProtocolHandlersMap::iterator it(protocol_handlers_.find(scheme));
if (it == protocol_handlers_.end())
return node::ThrowError(isolate, "The scheme has not been registered");
protocol_handlers_.erase(it);
BrowserThread::PostTask(BrowserThread::IO,
FROM_HERE,
base::Bind(&Protocol::UnregisterProtocolInIO,
base::Unretained(this), scheme));
.SetMethod("_registerProtocol", &Protocol::RegisterProtocol)
.SetMethod("_unregisterProtocol", &Protocol::UnregisterProtocol)
.SetMethod("_interceptProtocol", &Protocol::InterceptProtocol)
.SetMethod("_uninterceptProtocol", &Protocol::UninterceptProtocol);
}
void Protocol::RegisterStandardSchemes(
@@ -245,109 +278,127 @@ void Protocol::RegisterStandardSchemes(
atom::AtomBrowserClient::SetCustomSchemes(schemes);
}
bool Protocol::IsHandledProtocol(const std::string& scheme) {
return job_factory_->IsHandledProtocol(scheme);
void Protocol::IsHandledProtocol(const std::string& scheme,
const net::CompletionCallback& callback) {
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
base::Bind(&AtomURLRequestJobFactory::IsHandledProtocol,
base::Unretained(job_factory_), scheme),
callback);
}
void Protocol::RegisterProtocol(v8::Isolate* isolate,
const std::string& scheme,
const JsProtocolHandler& handler,
const JsCompletionCallback& callback) {
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
base::Bind(&Protocol::RegisterProtocolInIO,
base::Unretained(this), scheme, handler),
base::Bind(&Protocol::OnIOActionCompleted,
base::Unretained(this), callback));
}
void Protocol::UnregisterProtocol(v8::Isolate* isolate,
const std::string& scheme,
const JsCompletionCallback& callback) {
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
base::Bind(&Protocol::UnregisterProtocolInIO,
base::Unretained(this), scheme),
base::Bind(&Protocol::OnIOActionCompleted,
base::Unretained(this), callback));
}
void Protocol::InterceptProtocol(v8::Isolate* isolate,
const std::string& scheme,
const JsProtocolHandler& callback) {
if (!job_factory_->HasProtocolHandler(scheme))
return node::ThrowError(isolate, "Scheme does not exist.");
if (ContainsKey(protocol_handlers_, scheme))
return node::ThrowError(isolate, "Cannot intercept custom procotols");
protocol_handlers_[scheme] = callback;
BrowserThread::PostTask(BrowserThread::IO,
FROM_HERE,
base::Bind(&Protocol::InterceptProtocolInIO,
base::Unretained(this), scheme));
const JsProtocolHandler& handler,
const JsCompletionCallback& callback) {
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
base::Bind(&Protocol::InterceptProtocolInIO,
base::Unretained(this), scheme, handler),
base::Bind(&Protocol::OnIOActionCompleted,
base::Unretained(this), callback));
}
void Protocol::UninterceptProtocol(v8::Isolate* isolate,
const std::string& scheme) {
const std::string& scheme,
const JsCompletionCallback& callback) {
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
base::Bind(&Protocol::UninterceptProtocolInIO,
base::Unretained(this), scheme),
base::Bind(&Protocol::OnIOActionCompleted,
base::Unretained(this), callback));
}
int Protocol::RegisterProtocolInIO(const std::string& scheme,
const JsProtocolHandler& handler) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (ContainsKey(protocol_handlers_, scheme) ||
job_factory_->IsHandledProtocol(scheme)) {
return ERR_SCHEME_REGISTERED;
}
protocol_handlers_[scheme] = handler;
job_factory_->SetProtocolHandler(scheme, new CustomProtocolHandler(this));
return OK;
}
int Protocol::UnregisterProtocolInIO(const std::string& scheme) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
ProtocolHandlersMap::iterator it(protocol_handlers_.find(scheme));
if (it == protocol_handlers_.end())
return node::ThrowError(isolate, "The scheme has not been registered");
if (it == protocol_handlers_.end()) {
return ERR_SCHEME_UNREGISTERED;
}
protocol_handlers_.erase(it);
BrowserThread::PostTask(BrowserThread::IO,
FROM_HERE,
base::Bind(&Protocol::UninterceptProtocolInIO,
base::Unretained(this), scheme));
}
void Protocol::RegisterProtocolInIO(const std::string& scheme) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
job_factory_->SetProtocolHandler(scheme, new CustomProtocolHandler(this));
BrowserThread::PostTask(BrowserThread::UI,
FROM_HERE,
base::Bind(&Protocol::EmitEventInUI,
base::Unretained(this),
"registered", scheme));
}
void Protocol::UnregisterProtocolInIO(const std::string& scheme) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
job_factory_->SetProtocolHandler(scheme, NULL);
BrowserThread::PostTask(BrowserThread::UI,
FROM_HERE,
base::Bind(&Protocol::EmitEventInUI,
base::Unretained(this),
"unregistered", scheme));
return OK;
}
void Protocol::InterceptProtocolInIO(const std::string& scheme) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
int Protocol::InterceptProtocolInIO(const std::string& scheme,
const JsProtocolHandler& handler) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!job_factory_->HasProtocolHandler(scheme))
return ERR_NO_SCHEME;
if (ContainsKey(protocol_handlers_, scheme))
return ERR_SCHEME;
protocol_handlers_[scheme] = handler;
ProtocolHandler* original_handler = job_factory_->GetProtocolHandler(scheme);
if (original_handler == NULL) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
&Protocol::EmitEventInUI,
base::Unretained(this),
"error", "There is no protocol handler to intercpet"));
return;
if (original_handler == nullptr) {
return ERR_SCHEME_INTERCEPTED;
}
job_factory_->ReplaceProtocol(
scheme, new CustomProtocolHandler(this, original_handler));
BrowserThread::PostTask(BrowserThread::UI,
FROM_HERE,
base::Bind(&Protocol::EmitEventInUI,
base::Unretained(this),
"intercepted", scheme));
return OK;
}
void Protocol::UninterceptProtocolInIO(const std::string& scheme) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
int Protocol::UninterceptProtocolInIO(const std::string& scheme) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
ProtocolHandlersMap::iterator it(protocol_handlers_.find(scheme));
if (it == protocol_handlers_.end())
return ERR_SCHEME_UNREGISTERED;
protocol_handlers_.erase(it);
CustomProtocolHandler* handler = static_cast<CustomProtocolHandler*>(
job_factory_->GetProtocolHandler(scheme));
if (handler->original_handler() == NULL) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
&Protocol::EmitEventInUI,
base::Unretained(this),
"error", "The protocol is not intercpeted"));
return;
if (handler->original_handler() == nullptr) {
return ERR_SCHEME_UNINTERCEPTED;
}
// Reset the protocol handler to the orignal one and delete current protocol
// handler.
ProtocolHandler* original_handler = handler->ReleaseDefaultProtocolHandler();
delete job_factory_->ReplaceProtocol(scheme, original_handler);
BrowserThread::PostTask(BrowserThread::UI,
FROM_HERE,
base::Bind(&Protocol::EmitEventInUI,
base::Unretained(this),
"unintercepted", scheme));
}
void Protocol::EmitEventInUI(const std::string& event,
const std::string& parameter) {
Emit(event, parameter);
return OK;
}
// static

View File

@@ -12,6 +12,7 @@
#include "atom/browser/api/event_emitter.h"
#include "base/callback.h"
#include "native_mate/handle.h"
#include "net/base/completion_callback.h"
namespace net {
class URLRequest;
@@ -26,8 +27,19 @@ namespace api {
class Protocol : public mate::EventEmitter {
public:
typedef base::Callback<v8::Local<v8::Value>(const net::URLRequest*)>
JsProtocolHandler;
using JsProtocolHandler =
base::Callback<v8::Local<v8::Value>(const net::URLRequest*)>;
using JsCompletionCallback = base::Callback<void(v8::Local<v8::Value>)>;
enum {
OK = 0,
ERR_SCHEME_REGISTERED,
ERR_SCHEME_UNREGISTERED,
ERR_SCHEME_INTERCEPTED,
ERR_SCHEME_UNINTERCEPTED,
ERR_NO_SCHEME,
ERR_SCHEME
};
static mate::Handle<Protocol> Create(
v8::Isolate* isolate, AtomBrowserContext* browser_context);
@@ -46,35 +58,41 @@ class Protocol : public mate::EventEmitter {
private:
typedef std::map<std::string, JsProtocolHandler> ProtocolHandlersMap;
// Callback called after performing action on IO thread.
void OnIOActionCompleted(const JsCompletionCallback& callback,
int error);
// Register schemes to standard scheme list.
void RegisterStandardSchemes(const std::vector<std::string>& schemes);
// Returns whether a scheme has been registered.
void IsHandledProtocol(const std::string& scheme,
const net::CompletionCallback& callback);
// Register/unregister an networking |scheme| which would be handled by
// |callback|.
void RegisterProtocol(v8::Isolate* isolate,
const std::string& scheme,
const JsProtocolHandler& callback);
void UnregisterProtocol(v8::Isolate* isolate, const std::string& scheme);
// Returns whether a scheme has been registered.
// FIXME Should accept a callback and be asynchronous so we do not have to use
// locks.
bool IsHandledProtocol(const std::string& scheme);
const JsProtocolHandler& handler,
const JsCompletionCallback& callback);
void UnregisterProtocol(v8::Isolate* isolate, const std::string& scheme,
const JsCompletionCallback& callback);
// Intercept/unintercept an existing protocol handler.
void InterceptProtocol(v8::Isolate* isolate,
const std::string& scheme,
const JsProtocolHandler& callback);
void UninterceptProtocol(v8::Isolate* isolate, const std::string& scheme);
const JsProtocolHandler& handler,
const JsCompletionCallback& callback);
void UninterceptProtocol(v8::Isolate* isolate, const std::string& scheme,
const JsCompletionCallback& callback);
// The networking related operations have to be done in IO thread.
void RegisterProtocolInIO(const std::string& scheme);
void UnregisterProtocolInIO(const std::string& scheme);
void InterceptProtocolInIO(const std::string& scheme);
void UninterceptProtocolInIO(const std::string& scheme);
// Do protocol.emit(event, parameter) under UI thread.
void EmitEventInUI(const std::string& event, const std::string& parameter);
int RegisterProtocolInIO(const std::string& scheme,
const JsProtocolHandler& handler);
int UnregisterProtocolInIO(const std::string& scheme);
int InterceptProtocolInIO(const std::string& scheme,
const JsProtocolHandler& handler);
int UninterceptProtocolInIO(const std::string& scheme);
AtomBrowserContext* browser_context_;
AtomURLRequestJobFactory* job_factory_;

View File

@@ -5,22 +5,99 @@
#include "atom/browser/api/atom_api_session.h"
#include <string>
#include <vector>
#include "atom/browser/api/atom_api_cookies.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "base/thread_task_runner_handle.h"
#include "base/strings/string_util.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
#include "native_mate/callback.h"
#include "native_mate/object_template_builder.h"
#include "net/base/load_flags.h"
#include "net/disk_cache/disk_cache.h"
#include "net/proxy/proxy_service.h"
#include "net/proxy/proxy_config_service_fixed.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "atom/common/node_includes.h"
using content::BrowserThread;
using content::StoragePartition;
namespace {
struct ClearStorageDataOptions {
GURL origin;
uint32 storage_types = StoragePartition::REMOVE_DATA_MASK_ALL;
uint32 quota_types = StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL;
};
uint32 GetStorageMask(const std::vector<std::string>& storage_types) {
uint32 storage_mask = 0;
for (const auto& it : storage_types) {
auto type = base::StringToLowerASCII(it);
if (type == "appcache")
storage_mask |= StoragePartition::REMOVE_DATA_MASK_APPCACHE;
else if (type == "cookies")
storage_mask |= StoragePartition::REMOVE_DATA_MASK_COOKIES;
else if (type == "filesystem")
storage_mask |= StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS;
else if (type == "indexdb")
storage_mask |= StoragePartition::REMOVE_DATA_MASK_INDEXEDDB;
else if (type == "localstorage")
storage_mask |= StoragePartition::REMOVE_DATA_MASK_LOCAL_STORAGE;
else if (type == "shadercache")
storage_mask |= StoragePartition::REMOVE_DATA_MASK_SHADER_CACHE;
else if (type == "websql")
storage_mask |= StoragePartition::REMOVE_DATA_MASK_WEBSQL;
else if (type == "serviceworkers")
storage_mask |= StoragePartition::REMOVE_DATA_MASK_SERVICE_WORKERS;
}
return storage_mask;
}
uint32 GetQuotaMask(const std::vector<std::string>& quota_types) {
uint32 quota_mask = 0;
for (const auto& it : quota_types) {
auto type = base::StringToLowerASCII(it);
if (type == "temporary")
quota_mask |= StoragePartition::QUOTA_MANAGED_STORAGE_MASK_TEMPORARY;
else if (type == "persistent")
quota_mask |= StoragePartition::QUOTA_MANAGED_STORAGE_MASK_PERSISTENT;
else if (type == "syncable")
quota_mask |= StoragePartition::QUOTA_MANAGED_STORAGE_MASK_SYNCABLE;
}
return quota_mask;
}
} // namespace
namespace mate {
template<>
struct Converter<ClearStorageDataOptions> {
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
ClearStorageDataOptions* out) {
mate::Dictionary options;
if (!ConvertFromV8(isolate, val, &options))
return false;
options.Get("origin", &out->origin);
std::vector<std::string> types;
if (options.Get("storages", &types))
out->storage_types = GetStorageMask(types);
if (options.Get("quotas", &types))
out->quota_types = GetQuotaMask(types);
return true;
}
};
} // namespace mate
namespace atom {
namespace api {
@@ -80,6 +157,54 @@ class ResolveProxyHelper {
DISALLOW_COPY_AND_ASSIGN(ResolveProxyHelper);
};
// Runs the callback in UI thread.
template <typename ...T>
void RunCallbackInUI(const base::Callback<void(T...)>& callback, T... result) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE, base::Bind(callback, result...));
}
// Callback of HttpCache::GetBackend.
void OnGetBackend(disk_cache::Backend** backend_ptr,
const net::CompletionCallback& callback,
int result) {
if (result != net::OK) {
RunCallbackInUI(callback, result);
} else if (backend_ptr && *backend_ptr) {
(*backend_ptr)->DoomAllEntries(base::Bind(&RunCallbackInUI<int>, callback));
} else {
RunCallbackInUI<int>(callback, net::ERR_FAILED);
}
}
void ClearHttpCacheInIO(content::BrowserContext* browser_context,
const net::CompletionCallback& callback) {
auto request_context =
browser_context->GetRequestContext()->GetURLRequestContext();
auto http_cache = request_context->http_transaction_factory()->GetCache();
if (!http_cache)
RunCallbackInUI<int>(callback, net::ERR_FAILED);
// Call GetBackend and make the backend's ptr accessable in OnGetBackend.
using BackendPtr = disk_cache::Backend*;
BackendPtr* backend_ptr = new BackendPtr(nullptr);
net::CompletionCallback on_get_backend =
base::Bind(&OnGetBackend, base::Owned(backend_ptr), callback);
int rv = http_cache->GetBackend(backend_ptr, on_get_backend);
if (rv != net::ERR_IO_PENDING)
on_get_backend.Run(net::OK);
}
void SetProxyInIO(net::URLRequestContextGetter* getter,
const std::string& proxy,
const base::Closure& callback) {
net::ProxyConfig config;
config.proxy_rules().ParseFromString(proxy);
auto proxy_service = getter->GetURLRequestContext()->proxy_service();
proxy_service->ResetConfigService(new net::ProxyConfigServiceFixed(config));
RunCallbackInUI(callback);
}
} // namespace
Session::Session(AtomBrowserContext* browser_context)
@@ -94,6 +219,38 @@ void Session::ResolveProxy(const GURL& url, ResolveProxyCallback callback) {
new ResolveProxyHelper(browser_context_, url, callback);
}
void Session::ClearCache(const net::CompletionCallback& callback) {
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&ClearHttpCacheInIO,
base::Unretained(browser_context_),
callback));
}
void Session::ClearStorageData(mate::Arguments* args) {
// clearStorageData([options, ]callback)
ClearStorageDataOptions options;
args->GetNext(&options);
base::Closure callback;
if (!args->GetNext(&callback)) {
args->ThrowError();
return;
}
auto storage_partition =
content::BrowserContext::GetStoragePartition(browser_context_, nullptr);
storage_partition->ClearData(
options.storage_types, options.quota_types, options.origin,
content::StoragePartition::OriginMatcherFunction(),
base::Time(), base::Time::Max(), callback);
}
void Session::SetProxy(const std::string& proxy,
const base::Closure& callback) {
auto getter = browser_context_->GetRequestContext();
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&SetProxyInIO, base::Unretained(getter), proxy, callback));
}
v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
if (cookies_.IsEmpty()) {
auto handle = atom::api::Cookies::Create(isolate, browser_context_);
@@ -106,6 +263,9 @@ mate::ObjectTemplateBuilder Session::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("resolveProxy", &Session::ResolveProxy)
.SetMethod("clearCache", &Session::ClearCache)
.SetMethod("clearStorageData", &Session::ClearStorageData)
.SetMethod("setProxy", &Session::SetProxy)
.SetProperty("cookies", &Session::Cookies);
}

View File

@@ -8,11 +8,15 @@
#include <string>
#include "atom/browser/api/trackable_object.h"
#include "base/callback.h"
#include "native_mate/handle.h"
#include "net/base/completion_callback.h"
class GURL;
namespace mate {
class Arguments;
}
namespace atom {
class AtomBrowserContext;
@@ -27,6 +31,8 @@ class Session: public mate::TrackableObject<Session> {
static mate::Handle<Session> CreateFrom(
v8::Isolate* isolate, AtomBrowserContext* browser_context);
AtomBrowserContext* browser_context() const { return browser_context_; }
protected:
explicit Session(AtomBrowserContext* browser_context);
~Session();
@@ -37,6 +43,9 @@ class Session: public mate::TrackableObject<Session> {
private:
void ResolveProxy(const GURL& url, ResolveProxyCallback callback);
void ClearCache(const net::CompletionCallback& callback);
void ClearStorageData(mate::Arguments* args);
void SetProxy(const std::string& proxy, const base::Closure& callback);
v8::Local<v8::Value> Cookies(v8::Isolate* isolate);
v8::Global<v8::Value> cookies_;

View File

@@ -60,45 +60,44 @@ void Tray::OnBalloonClosed() {
Emit("balloon-closed");
}
void Tray::OnRightClicked(const gfx::Rect& bounds) {
Emit("right-clicked", bounds);
}
void Tray::OnDropFiles(const std::vector<std::string>& files) {
Emit("drop-files", files);
}
bool Tray::IsDestroyed() const {
return !tray_icon_;
}
void Tray::Destroy() {
tray_icon_.reset();
}
void Tray::SetImage(mate::Arguments* args, const gfx::Image& image) {
if (!CheckTrayLife(args))
return;
tray_icon_->SetImage(image);
}
void Tray::SetPressedImage(mate::Arguments* args, const gfx::Image& image) {
if (!CheckTrayLife(args))
return;
tray_icon_->SetPressedImage(image);
}
void Tray::SetToolTip(mate::Arguments* args, const std::string& tool_tip) {
if (!CheckTrayLife(args))
return;
tray_icon_->SetToolTip(tool_tip);
}
void Tray::SetTitle(mate::Arguments* args, const std::string& title) {
if (!CheckTrayLife(args))
return;
tray_icon_->SetTitle(title);
}
void Tray::SetHighlightMode(mate::Arguments* args, bool highlight) {
if (!CheckTrayLife(args))
return;
tray_icon_->SetHighlightMode(highlight);
}
void Tray::DisplayBalloon(mate::Arguments* args,
const mate::Dictionary& options) {
if (!CheckTrayLife(args))
return;
gfx::Image icon;
options.Get("icon", &icon);
base::string16 title, content;
@@ -111,32 +110,28 @@ void Tray::DisplayBalloon(mate::Arguments* args,
tray_icon_->DisplayBalloon(icon, title, content);
}
void Tray::SetContextMenu(mate::Arguments* args, Menu* menu) {
if (!CheckTrayLife(args))
return;
tray_icon_->SetContextMenu(menu->model());
void Tray::PopContextMenu(mate::Arguments* args) {
gfx::Point pos;
args->GetNext(&pos);
tray_icon_->PopContextMenu(pos);
}
bool Tray::CheckTrayLife(mate::Arguments* args) {
if (!tray_icon_) {
args->ThrowError("Tray is already destroyed");
return false;
} else {
return true;
}
void Tray::SetContextMenu(mate::Arguments* args, Menu* menu) {
tray_icon_->SetContextMenu(menu->model());
}
// static
void Tray::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.SetMethod("destroy", &Tray::Destroy)
.SetMethod("destroy", &Tray::Destroy, true)
.SetMethod("setImage", &Tray::SetImage)
.SetMethod("setPressedImage", &Tray::SetPressedImage)
.SetMethod("setToolTip", &Tray::SetToolTip)
.SetMethod("setTitle", &Tray::SetTitle)
.SetMethod("setHighlightMode", &Tray::SetHighlightMode)
.SetMethod("displayBalloon", &Tray::DisplayBalloon)
.SetMethod("popContextMenu", &Tray::PopContextMenu)
.SetMethod("_setContextMenu", &Tray::SetContextMenu);
}

View File

@@ -6,6 +6,7 @@
#define ATOM_BROWSER_API_ATOM_API_TRAY_H_
#include <string>
#include <vector>
#include "atom/browser/api/event_emitter.h"
#include "atom/browser/ui/tray_icon_observer.h"
@@ -41,11 +42,16 @@ class Tray : public mate::EventEmitter,
virtual ~Tray();
// TrayIconObserver:
void OnClicked(const gfx::Rect&) override;
void OnClicked(const gfx::Rect& bounds) override;
void OnDoubleClicked() override;
void OnBalloonShow() override;
void OnBalloonClicked() override;
void OnBalloonClosed() override;
void OnRightClicked(const gfx::Rect& bounds) override;
void OnDropFiles(const std::vector<std::string>& files) override;
// mate::Wrappable:
bool IsDestroyed() const override;
void Destroy();
void SetImage(mate::Arguments* args, const gfx::Image& image);
@@ -54,11 +60,10 @@ class Tray : public mate::EventEmitter,
void SetTitle(mate::Arguments* args, const std::string& title);
void SetHighlightMode(mate::Arguments* args, bool highlight);
void DisplayBalloon(mate::Arguments* args, const mate::Dictionary& options);
void PopContextMenu(mate::Arguments* args);
void SetContextMenu(mate::Arguments* args, Menu* menu);
private:
bool CheckTrayLife(mate::Arguments* args);
scoped_ptr<TrayIcon> tray_icon_;
DISALLOW_COPY_AND_ASSIGN(Tray);

View File

@@ -40,6 +40,7 @@
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/static_http_user_agent_settings.h"
#include "net/url_request/url_request_context.h"
#include "atom/common/node_includes.h"
@@ -51,6 +52,12 @@ struct PrintSettings {
bool print_background;
};
void SetUserAgentInIO(scoped_refptr<net::URLRequestContextGetter> getter,
std::string user_agent) {
getter->GetURLRequestContext()->set_http_user_agent_settings(
new net::StaticHttpUserAgentSettings("en-us,en", user_agent));
}
} // namespace
namespace mate {
@@ -142,6 +149,7 @@ WebContents::WebContents(content::WebContents* web_contents)
: content::WebContentsObserver(web_contents),
type_(REMOTE) {
AttachAsUserData(web_contents);
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
}
WebContents::WebContents(const mate::Dictionary& options) {
@@ -168,6 +176,8 @@ WebContents::WebContents(const mate::Dictionary& options) {
AttachAsUserData(web_contents);
InitWithWebContents(web_contents);
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
if (is_guest) {
guest_delegate_->Initialize(this);
@@ -250,7 +260,7 @@ void WebContents::MoveContents(content::WebContents* source,
}
void WebContents::CloseContents(content::WebContents* source) {
Emit("closed");
Emit("close");
if (type_ == BROWSER_WINDOW)
owner_window()->CloseContents(source);
}
@@ -547,6 +557,14 @@ bool WebContents::IsCrashed() const {
void WebContents::SetUserAgent(const std::string& user_agent) {
web_contents()->SetUserAgentOverride(user_agent);
scoped_refptr<net::URLRequestContextGetter> getter =
web_contents()->GetBrowserContext()->GetRequestContext();
getter->GetNetworkTaskRunner()->PostTask(FROM_HERE,
base::Bind(&SetUserAgentInIO, getter, user_agent));
}
std::string WebContents::GetUserAgent() {
return web_contents()->GetUserAgentOverride();
}
void WebContents::InsertCSS(const std::string& css) {
@@ -619,9 +637,7 @@ void WebContents::InspectServiceWorker() {
v8::Local<v8::Value> WebContents::Session(v8::Isolate* isolate) {
if (session_.IsEmpty()) {
mate::Handle<api::Session> handle = Session::CreateFrom(
isolate,
static_cast<AtomBrowserContext*>(web_contents()->GetBrowserContext()));
auto handle = Session::CreateFrom(isolate, GetBrowserContext());
session_.Reset(isolate, handle.ToV8());
}
return v8::Local<v8::Value>::New(isolate, session_);
@@ -717,6 +733,14 @@ void WebContents::ReplaceMisspelling(const base::string16& word) {
web_contents()->ReplaceMisspelling(word);
}
void WebContents::Focus() {
web_contents()->Focus();
}
void WebContents::TabTraverse(bool reverse) {
web_contents()->FocusThroughTabTraversal(reverse);
}
bool WebContents::SendIPCMessage(const base::string16& channel,
const base::ListValue& args) {
return Send(new AtomViewMsg_Message(routing_id(), channel, args));
@@ -740,8 +764,8 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
if (template_.IsEmpty())
template_.Reset(isolate, mate::ObjectTemplateBuilder(isolate)
.SetMethod("destroy", &WebContents::Destroy)
.SetMethod("isAlive", &WebContents::IsAlive)
.SetMethod("destroy", &WebContents::Destroy, true)
.SetMethod("isAlive", &WebContents::IsAlive, true)
.SetMethod("getId", &WebContents::GetID)
.SetMethod("equal", &WebContents::Equal)
.SetMethod("_loadUrl", &WebContents::LoadURL)
@@ -755,6 +779,7 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
.SetMethod("_goToOffset", &WebContents::GoToOffset)
.SetMethod("isCrashed", &WebContents::IsCrashed)
.SetMethod("setUserAgent", &WebContents::SetUserAgent)
.SetMethod("getUserAgent", &WebContents::GetUserAgent)
.SetMethod("insertCSS", &WebContents::InsertCSS)
.SetMethod("_executeJavaScript", &WebContents::ExecuteJavaScript)
.SetMethod("openDevTools", &WebContents::OpenDevTools)
@@ -775,7 +800,9 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
.SetMethod("unselect", &WebContents::Unselect)
.SetMethod("replace", &WebContents::Replace)
.SetMethod("replaceMisspelling", &WebContents::ReplaceMisspelling)
.SetMethod("_send", &WebContents::SendIPCMessage)
.SetMethod("focus", &WebContents::Focus)
.SetMethod("tabTraverse", &WebContents::TabTraverse)
.SetMethod("_send", &WebContents::SendIPCMessage, true)
.SetMethod("setSize", &WebContents::SetSize)
.SetMethod("setAllowTransparency", &WebContents::SetAllowTransparency)
.SetMethod("isGuest", &WebContents::IsGuest)
@@ -792,6 +819,14 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
isolate, v8::Local<v8::ObjectTemplate>::New(isolate, template_));
}
bool WebContents::IsDestroyed() const {
return !IsAlive();
}
AtomBrowserContext* WebContents::GetBrowserContext() const {
return static_cast<AtomBrowserContext*>(web_contents()->GetBrowserContext());
}
void WebContents::OnRendererMessage(const base::string16& channel,
const base::ListValue& args) {
// webContents.emit(channel, new Event(), args...);

View File

@@ -27,6 +27,7 @@ class Dictionary;
namespace atom {
struct SetSizeParams;
class AtomBrowserContext;
class WebViewGuestDelegate;
namespace api {
@@ -62,6 +63,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
void GoToOffset(int offset);
bool IsCrashed() const;
void SetUserAgent(const std::string& user_agent);
std::string GetUserAgent();
void InsertCSS(const std::string& css);
void ExecuteJavaScript(const base::string16& code);
void OpenDevTools(mate::Arguments* args);
@@ -94,6 +96,10 @@ class WebContents : public mate::TrackableObject<WebContents>,
void Replace(const base::string16& word);
void ReplaceMisspelling(const base::string16& word);
// Focus.
void Focus();
void TabTraverse(bool reverse);
// Sending messages to browser.
bool SendIPCMessage(const base::string16& channel,
const base::ListValue& args);
@@ -111,6 +117,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
bool IsDestroyed() const override;
// content::WebContentsDelegate:
bool AddMessageToConsole(content::WebContents* source,
@@ -190,6 +197,8 @@ class WebContents : public mate::TrackableObject<WebContents>,
REMOTE, // Thin wrap around an existing WebContents.
};
AtomBrowserContext* GetBrowserContext() const;
// Called when received a message from renderer.
void OnRendererMessage(const base::string16& channel,
const base::ListValue& args);

View File

@@ -177,6 +177,10 @@ mate::Wrappable* Window::New(v8::Isolate* isolate,
return new Window(isolate, options);
}
bool Window::IsDestroyed() const {
return !window_ || window_->IsClosed();
}
void Window::Destroy() {
window_->CloseContents(nullptr);
}
@@ -447,6 +451,12 @@ void Window::ShowDefinitionForSelection() {
}
#endif
void Window::SetAspectRatio(double aspect_ratio, mate::Arguments* args) {
gfx::Size extra_size;
args->GetNext(&extra_size);
window_->SetAspectRatio(aspect_ratio, extra_size);
}
void Window::SetVisibleOnAllWorkspaces(bool visible) {
return window_->SetVisibleOnAllWorkspaces(visible);
}
@@ -477,7 +487,7 @@ v8::Local<v8::Value> Window::DevToolsWebContents(v8::Isolate* isolate) {
void Window::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> prototype) {
mate::ObjectTemplateBuilder(isolate, prototype)
.SetMethod("destroy", &Window::Destroy)
.SetMethod("destroy", &Window::Destroy, true)
.SetMethod("close", &Window::Close)
.SetMethod("isClosed", &Window::IsClosed)
.SetMethod("focus", &Window::Focus)
@@ -494,6 +504,7 @@ void Window::BuildPrototype(v8::Isolate* isolate,
.SetMethod("isMinimized", &Window::IsMinimized)
.SetMethod("setFullScreen", &Window::SetFullScreen)
.SetMethod("isFullScreen", &Window::IsFullscreen)
.SetMethod("setAspectRatio", &Window::SetAspectRatio)
.SetMethod("getBounds", &Window::GetBounds)
.SetMethod("setBounds", &Window::SetBounds)
.SetMethod("getSize", &Window::GetSize)
@@ -540,9 +551,9 @@ void Window::BuildPrototype(v8::Isolate* isolate,
.SetMethod("showDefinitionForSelection",
&Window::ShowDefinitionForSelection)
#endif
.SetProperty("id", &Window::ID)
.SetProperty("webContents", &Window::WebContents)
.SetProperty("devToolsWebContents", &Window::DevToolsWebContents);
.SetProperty("id", &Window::ID, true)
.SetProperty("webContents", &Window::WebContents, true)
.SetProperty("devToolsWebContents", &Window::DevToolsWebContents, true);
}
} // namespace api

View File

@@ -73,6 +73,9 @@ class Window : public mate::TrackableObject<Window>,
void OnDevToolsClosed() override;
void OnExecuteWindowsCommand(const std::string& command_name) override;
// mate::Wrappable:
bool IsDestroyed() const override;
private:
// APIs for NativeWindow.
void Destroy();
@@ -131,6 +134,7 @@ class Window : public mate::TrackableObject<Window>,
bool IsMenuBarAutoHide();
void SetMenuBarVisibility(bool visible);
bool IsMenuBarVisible();
void SetAspectRatio(double aspect_ratio, mate::Arguments* args);
#if defined(OS_MACOSX)
void ShowDefinitionForSelection();

View File

@@ -25,6 +25,13 @@ if process.platform is 'darwin'
show: bindings.dockShow
setMenu: bindings.dockSetMenu
appPath = null
app.setAppPath = (path) ->
appPath = path
app.getAppPath = ->
appPath
# Be compatible with old API.
app.once 'ready', -> @emit 'finish-launching'
app.terminate = app.quit

View File

@@ -16,15 +16,29 @@ BrowserWindow::_init = ->
options = show: true, width: 800, height: 600
ipc.emit 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', event, url, frameName, options
# window.move(...)
# window.resizeTo(...)
# window.moveTo(...)
@webContents.on 'move', (event, size) =>
@setSize size
@setBounds size
# Hide the auto-hide menu when webContents is focused.
@webContents.on 'activate', =>
if process.platform isnt 'darwin' and @isMenuBarAutoHide() and @isMenuBarVisible()
@setMenuBarVisibility false
# Forward the crashed event.
@webContents.on 'crashed', =>
@emit 'crashed'
# Sometimes the webContents doesn't get focus when window is shown, so we have
# to force focusing on webContents in this case. The safest way is to focus it
# when we first start to load URL, if we do it earlier it won't have effect,
# if we do it later we might move focus in the page.
# Though this hack is only needed on OS X when the app is launched from
# Finder, we still do it on all platforms in case of other bugs we don't know.
@webContents.once 'load-url', ->
@focus()
# Redirect focus/blur event to app instance too.
@on 'blur', (event) =>
app.emit 'browser-window-blur', event, this

View File

@@ -9,7 +9,10 @@ fileDialogProperties =
multiSelections: 1 << 2
createDirectory: 1 << 3
messageBoxTypes = ['none', 'info', 'warning']
messageBoxTypes = ['none', 'info', 'warning', 'error', 'question']
messageBoxOptions =
noLink: 1 << 0
parseArgs = (window, options, callback) ->
unless window is null or window?.constructor is BrowserWindow
@@ -93,9 +96,23 @@ module.exports =
options.detail ?= ''
options.icon ?= null
# Choose a default button to get selected when dialog is cancelled.
unless options.cancelId?
options.cancelId = 0
for text, i in options.buttons
if text.toLowerCase() in ['cancel', 'no']
options.cancelId = i
break
flags = if options.noLink then messageBoxOptions.noLink else 0
binding.showMessageBox messageBoxType,
options.buttons,
[options.title, options.message, options.detail],
options.cancelId,
flags,
options.title,
options.message,
options.detail,
options.icon,
window,
callback
@@ -104,4 +121,5 @@ module.exports =
binding.showErrorBox args...
# Mark standard asynchronous functions.
v8Util.setHiddenValue f, 'asynchronous', true for k, f of module.exports
for api in ['showMessageBox', 'showOpenDialog', 'showSaveDialog']
v8Util.setHiddenValue module.exports[api], 'asynchronous', true

View File

@@ -40,6 +40,7 @@ class NavigationController
loadUrl: (url, options={}) ->
@pendingIndex = -1
@webContents._loadUrl url, options
@webContents.emit 'load-url', url, options
getUrl: ->
if @currentIndex is -1

View File

@@ -6,6 +6,29 @@ EventEmitter = require('events').EventEmitter
protocol.__proto__ = EventEmitter.prototype
GetWrappedCallback = (scheme, callback, notification) ->
wrappedCallback = (error) ->
if not callback?
if error
throw error
else
protocol.emit notification, scheme
else
callback error, scheme
# Compatibility with old api.
protocol.registerProtocol = (scheme, handler, callback) ->
protocol._registerProtocol scheme, handler, GetWrappedCallback(scheme, callback, 'registered')
protocol.unregisterProtocol = (scheme, callback) ->
protocol._unregisterProtocol scheme, GetWrappedCallback(scheme, callback, 'unregistered')
protocol.interceptProtocol = (scheme, handler, callback) ->
protocol._interceptProtocol scheme, handler, GetWrappedCallback(scheme, callback, 'intercepted')
protocol.uninterceptProtocol = (scheme, callback) ->
protocol._uninterceptProtocol scheme, GetWrappedCallback(scheme, callback, 'unintercepted')
protocol.RequestStringJob =
class RequestStringJob
constructor: ({mimeType, charset, data}) ->
@@ -36,6 +59,6 @@ class RequestErrorJob
protocol.RequestHttpJob =
class RequestHttpJob
constructor: ({@url, @method, @referrer}) ->
constructor: ({@session, @url, @method, @referrer}) ->
module.exports = protocol

View File

@@ -9,6 +9,7 @@
#include "atom/browser/api/event_emitter.h"
#include "atom/common/id_weak_map.h"
#include "base/memory/scoped_ptr.h"
namespace base {
class SupportsUserData;
@@ -54,7 +55,10 @@ class TrackableObject : public TrackableObjectBase {
public:
// Finds out the TrackableObject from its ID in weak map.
static T* FromWeakMapID(v8::Isolate* isolate, int32_t id) {
v8::MaybeLocal<v8::Object> object = weak_map_.Get(isolate, id);
if (!weak_map_)
return nullptr;
v8::MaybeLocal<v8::Object> object = weak_map_->Get(isolate, id);
if (object.IsEmpty())
return nullptr;
@@ -74,7 +78,10 @@ class TrackableObject : public TrackableObjectBase {
// Returns all objects in this class's weak map.
static std::vector<v8::Local<v8::Object>> GetAll(v8::Isolate* isolate) {
return weak_map_.Values(isolate);
if (weak_map_)
return weak_map_->Values(isolate);
else
return std::vector<v8::Local<v8::Object>>();
}
TrackableObject() {
@@ -83,8 +90,8 @@ class TrackableObject : public TrackableObjectBase {
// Removes this instance from the weak map.
void RemoveFromWeakMap() {
if (weak_map_.Has(weak_map_id()))
weak_map_.Remove(weak_map_id());
if (weak_map_ && weak_map_->Has(weak_map_id()))
weak_map_->Remove(weak_map_id());
}
protected:
@@ -93,23 +100,25 @@ class TrackableObject : public TrackableObjectBase {
}
void AfterInit(v8::Isolate* isolate) override {
weak_map_id_ = weak_map_.Add(isolate, GetWrapper(isolate));
if (!weak_map_)
weak_map_.reset(new atom::IDWeakMap);
weak_map_id_ = weak_map_->Add(isolate, GetWrapper(isolate));
TrackableObjectBase::AfterInit(isolate);
}
private:
// Releases all weak references in weak map, called when app is terminating.
static void ReleaseAllWeakReferences() {
weak_map_.Clear();
weak_map_.reset();
}
static atom::IDWeakMap weak_map_;
static scoped_ptr<atom::IDWeakMap> weak_map_;
DISALLOW_COPY_AND_ASSIGN(TrackableObject);
};
template<typename T>
atom::IDWeakMap TrackableObject<T>::weak_map_;
scoped_ptr<atom::IDWeakMap> TrackableObject<T>::weak_map_;
} // namespace mate

View File

@@ -215,11 +215,8 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches(
void AtomBrowserClient::DidCreatePpapiPlugin(
content::BrowserPpapiHost* host) {
auto command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kEnablePlugins)) {
host->GetPpapiHost()->AddHostFactoryFilter(
make_scoped_ptr(new chrome::ChromeBrowserPepperHostFactory(host)));
}
host->GetPpapiHost()->AddHostFactoryFilter(
make_scoped_ptr(new chrome::ChromeBrowserPepperHostFactory(host)));
}
content::QuotaPermissionContext*

View File

@@ -6,16 +6,22 @@
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/atom_download_manager_delegate.h"
#include "atom/browser/browser.h"
#include "atom/browser/net/atom_url_request_job_factory.h"
#include "atom/browser/net/asar/asar_protocol_handler.h"
#include "atom/browser/net/http_protocol_handler.h"
#include "atom/browser/web_view_manager.h"
#include "atom/common/atom_version.h"
#include "atom/common/chrome_version.h"
#include "atom/common/options_switches.h"
#include "base/command_line.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/worker_pool.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/url_constants.h"
#include "content/public/common/user_agent.h"
#include "net/ftp/ftp_network_layer.h"
#include "net/url_request/data_protocol_handler.h"
#include "net/url_request/ftp_protocol_handler.h"
@@ -37,6 +43,14 @@ class NoCacheBackend : public net::HttpCache::BackendFactory {
}
};
std::string RemoveWhitespace(const std::string& str) {
std::string trimmed;
if (base::RemoveChars(str, " ", &trimmed))
return trimmed;
else
return str;
}
} // namespace
AtomBrowserContext::AtomBrowserContext()
@@ -46,6 +60,23 @@ AtomBrowserContext::AtomBrowserContext()
AtomBrowserContext::~AtomBrowserContext() {
}
std::string AtomBrowserContext::GetUserAgent() {
Browser* browser = Browser::Get();
std::string name = RemoveWhitespace(browser->GetName());
std::string user_agent;
if (name == ATOM_PRODUCT_NAME) {
user_agent = "Chrome/" CHROME_VERSION_STRING " "
ATOM_PRODUCT_NAME "/" ATOM_VERSION_STRING;
} else {
user_agent = base::StringPrintf(
"%s/%s Chrome/%s " ATOM_PRODUCT_NAME "/" ATOM_VERSION_STRING,
name.c_str(),
browser->GetVersion().c_str(),
CHROME_VERSION_STRING);
}
return content::BuildUserAgentFromProduct(user_agent);
}
net::URLRequestJobFactory* AtomBrowserContext::CreateURLRequestJobFactory(
content::ProtocolHandlerMap* handlers,
content::URLRequestInterceptorScopedVector* interceptors) {

View File

@@ -5,6 +5,8 @@
#ifndef ATOM_BROWSER_ATOM_BROWSER_CONTEXT_H_
#define ATOM_BROWSER_ATOM_BROWSER_CONTEXT_H_
#include <string>
#include "brightray/browser/browser_context.h"
namespace atom {
@@ -19,6 +21,7 @@ class AtomBrowserContext : public brightray::BrowserContext {
virtual ~AtomBrowserContext();
// brightray::URLRequestContextGetter::Delegate:
std::string GetUserAgent() override;
net::URLRequestJobFactory* CreateURLRequestJobFactory(
content::ProtocolHandlerMap* handlers,
content::URLRequestInterceptorScopedVector* interceptors) override;

View File

@@ -237,7 +237,7 @@ app.once('ready', function() {
},
{
label: 'Toggle &Developer Tools',
accelerator: 'Alt+Ctrl+I',
accelerator: 'Shift+Ctrl+I',
click: function() {
var focusedWindow = BrowserWindow.getFocusedWindow();
if (focusedWindow)
@@ -291,6 +291,7 @@ if (option.file && !option.webdriver) {
app.setName(packageJson.name);
app.setPath('userData', path.join(app.getPath('appData'), app.getName()));
app.setPath('userCache', path.join(app.getPath('cache'), app.getName()));
app.setAppPath(packagePath);
}
// Run the app.

View File

@@ -21,9 +21,8 @@ createGuest = (embedder, url, frameName, options) ->
# guest is closed by user then we should prevent |embedder| from double
# closing guest.
closedByEmbedder = ->
embedder.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSED', guest.id
guest.removeListener 'closed', closedByUser
guest.destroy() unless guest.isClosed()
guest.destroy()
closedByUser = ->
embedder.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSED', guest.id
embedder.removeListener 'render-view-deleted', closedByEmbedder

View File

@@ -87,6 +87,7 @@ app.commandLine.appendSwitch 'enable-npapi'
# Set the user path according to application's name.
app.setPath 'userData', path.join(app.getPath('appData'), app.getName())
app.setPath 'userCache', path.join(app.getPath('cache'), app.getName())
app.setAppPath packagePath
# Load the chrome extension support.
require './chrome-extension'

View File

@@ -8,13 +8,14 @@
#include <utility>
#include <vector>
#if defined(OS_WIN)
#include <shlobj.h>
#endif
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/browser.h"
#include "atom/browser/window_list.h"
#include "atom/common/api/api_messages.h"
#include "atom/common/atom_version.h"
#include "atom/common/chrome_version.h"
#include "atom/common/native_mate_converters/image_converter.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/options_switches.h"
@@ -24,7 +25,6 @@
#include "base/prefs/pref_service.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "brightray/browser/inspectable_web_contents.h"
#include "brightray/browser/inspectable_web_contents_view.h"
@@ -36,7 +36,6 @@
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/renderer_preferences.h"
#include "content/public/common/user_agent.h"
#include "content/public/common/web_preferences.h"
#include "ipc/ipc_message_macros.h"
#include "native_mate/dictionary.h"
@@ -73,14 +72,6 @@ const char* kWebRuntimeFeatures[] = {
switches::kPageVisibility,
};
std::string RemoveWhitespace(const std::string& str) {
std::string trimmed;
if (base::RemoveChars(str, " ", &trimmed))
return trimmed;
else
return str;
}
} // namespace
NativeWindow::NativeWindow(
@@ -94,6 +85,7 @@ NativeWindow::NativeWindow(
node_integration_(true),
has_dialog_attached_(false),
zoom_factor_(1.0),
aspect_ratio_(0.0),
inspectable_web_contents_(inspectable_web_contents),
weak_factory_(this) {
inspectable_web_contents->GetView()->SetDelegate(this);
@@ -130,16 +122,6 @@ NativeWindow::NativeWindow(
options.Get(switches::kZoomFactor, &zoom_factor_);
WindowList::AddWindow(this);
// Override the user agent to contain application and atom-shell's version.
Browser* browser = Browser::Get();
std::string product_name = base::StringPrintf(
"%s/%s Chrome/%s " ATOM_PRODUCT_NAME "/" ATOM_VERSION_STRING,
RemoveWhitespace(browser->GetName()).c_str(),
browser->GetVersion().c_str(),
CHROME_VERSION_STRING);
web_contents()->GetMutableRendererPrefs()->user_agent_override =
content::BuildUserAgentFromProduct(product_name);
}
NativeWindow::~NativeWindow() {
@@ -189,10 +171,12 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) {
if (options.Get(switches::kAlwaysOnTop, &top) && top) {
SetAlwaysOnTop(true);
}
#if defined(OS_MACOSX) || defined(OS_WIN)
bool fullscreen;
if (options.Get(switches::kFullscreen, &fullscreen) && fullscreen) {
SetFullScreen(true);
}
#endif
bool skip;
if (options.Get(switches::kSkipTaskbar, &skip) && skip) {
SetSkipTaskbar(skip);
@@ -263,6 +247,20 @@ bool NativeWindow::IsMenuBarVisible() {
return true;
}
double NativeWindow::GetAspectRatio() {
return aspect_ratio_;
}
gfx::Size NativeWindow::GetAspectRatioExtraSize() {
return aspect_ratio_extraSize_;
}
void NativeWindow::SetAspectRatio(double aspect_ratio,
const gfx::Size& extra_size) {
aspect_ratio_ = aspect_ratio;
aspect_ratio_extraSize_ = extra_size;
}
bool NativeWindow::HasModalDialog() {
return has_dialog_attached_;
}
@@ -386,6 +384,15 @@ void NativeWindow::AppendExtraCommandLineSwitches(
command_line->AppendSwitchASCII(switches::kZoomFactor,
base::DoubleToString(zoom_factor_));
#if defined(OS_WIN)
// Append --app-user-model-id.
PWSTR current_app_id;
if (SUCCEEDED(GetCurrentProcessExplicitAppUserModelID(&current_app_id))) {
command_line->AppendSwitchNative(switches::kAppUserModelId, current_app_id);
CoTaskMemFree(current_app_id);
}
#endif
if (web_preferences_.IsEmpty())
return;
@@ -417,8 +424,6 @@ void NativeWindow::OverrideWebkitPrefs(content::WebPreferences* prefs) {
std::vector<base::FilePath> list;
if (web_preferences_.Get("javascript", &b))
prefs->javascript_enabled = b;
if (web_preferences_.Get("web-security", &b))
prefs->web_security_enabled = b;
if (web_preferences_.Get("images", &b))
prefs->images_enabled = b;
if (web_preferences_.Get("java", &b))
@@ -429,6 +434,11 @@ void NativeWindow::OverrideWebkitPrefs(content::WebPreferences* prefs) {
prefs->experimental_webgl_enabled = b;
if (web_preferences_.Get("webaudio", &b))
prefs->webaudio_enabled = b;
if (web_preferences_.Get("web-security", &b)) {
prefs->web_security_enabled = b;
prefs->allow_displaying_insecure_content = !b;
prefs->allow_running_insecure_content = !b;
}
if (web_preferences_.Get("extra-plugin-dirs", &list)) {
if (content::PluginService::GetInstance()->NPAPIPluginsSupported()) {
for (size_t i = 0; i < list.size(); ++i)

View File

@@ -163,6 +163,11 @@ class NativeWindow : public content::WebContentsObserver,
virtual void SetMenuBarVisibility(bool visible);
virtual bool IsMenuBarVisible();
// Set the aspect ratio when resizing window.
double GetAspectRatio();
gfx::Size GetAspectRatioExtraSize();
void SetAspectRatio(double aspect_ratio, const gfx::Size& extra_size);
base::WeakPtr<NativeWindow> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
@@ -285,6 +290,11 @@ class NativeWindow : public content::WebContentsObserver,
// Page's default zoom factor.
double zoom_factor_;
// Used to maintain the aspect ratio of a view which is inside of the
// content view.
double aspect_ratio_;
gfx::Size aspect_ratio_extraSize_;
// The page this window is viewing.
brightray::InspectableWebContents* inspectable_web_contents_;

View File

@@ -95,6 +95,44 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
shell_->NotifyWindowBlur();
}
- (NSSize)windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize {
NSSize newSize = frameSize;
double aspectRatio = shell_->GetAspectRatio();
if (aspectRatio > 0.0) {
gfx::Size windowSize = shell_->GetSize();
gfx::Size contentSize = shell_->GetContentSize();
gfx::Size extraSize = shell_->GetAspectRatioExtraSize();
double extraWidthPlusFrame =
windowSize.width() - contentSize.width() + extraSize.width();
double extraHeightPlusFrame =
windowSize.height() - contentSize.height() + extraSize.height();
newSize.width =
roundf((frameSize.height - extraHeightPlusFrame) * aspectRatio +
extraWidthPlusFrame);
// If the new width is less than the frame size use it as the primary
// constraint. This ensures that the value returned by this method will
// never be larger than the users requested window size.
if (newSize.width <= frameSize.width) {
newSize.height =
roundf((newSize.width - extraWidthPlusFrame) / aspectRatio +
extraHeightPlusFrame);
} else {
newSize.height =
roundf((frameSize.width - extraWidthPlusFrame) / aspectRatio +
extraHeightPlusFrame);
newSize.width =
roundf((newSize.height - extraHeightPlusFrame) * aspectRatio +
extraWidthPlusFrame);
}
}
return newSize;
}
- (void)windowDidResize:(NSNotification*)notification {
if (!shell_->has_frame())
shell_->ClipWebView();
@@ -357,7 +395,7 @@ NativeWindowMac::NativeWindowMac(
// On OS X the initial window size doesn't include window frame.
bool use_content_size = false;
options.Get(switches::kUseContentSize, &use_content_size);
if (has_frame_ && !use_content_size)
if (!has_frame_ || !use_content_size)
SetSize(gfx::Size(width, height));
// Enable the NSView to accept first mouse event.
@@ -494,6 +532,11 @@ gfx::Rect NativeWindowMac::GetBounds() {
}
void NativeWindowMac::SetContentSize(const gfx::Size& size) {
if (!has_frame_) {
SetSize(size);
return;
}
NSRect frame_nsrect = [window_ frame];
NSSize frame = frame_nsrect.size;
NSSize content = [window_ contentRectForFrameRect:frame_nsrect].size;
@@ -507,6 +550,9 @@ void NativeWindowMac::SetContentSize(const gfx::Size& size) {
}
gfx::Size NativeWindowMac::GetContentSize() {
if (!has_frame_)
return GetSize();
NSRect bounds = [[window_ contentView] bounds];
return gfx::Size(bounds.size.width, bounds.size.height);
}

View File

@@ -36,6 +36,7 @@
#include "atom/browser/browser.h"
#include "atom/browser/ui/views/global_menu_bar_x11.h"
#include "atom/browser/ui/views/frameless_view.h"
#include "atom/browser/ui/views/native_frame_view.h"
#include "atom/browser/ui/x/window_state_watcher.h"
#include "atom/browser/ui/x/x_window_utils.h"
#include "base/environment.h"
@@ -285,14 +286,21 @@ NativeWindowViews::NativeWindowViews(
// Before the window is mapped the SetWMSpecState can not work, so we have
// to manually set the _NET_WM_STATE.
std::vector<::Atom> state_atom_list;
bool skip_taskbar = false;
if (options.Get(switches::kSkipTaskbar, &skip_taskbar) && skip_taskbar) {
std::vector<::Atom> state_atom_list;
state_atom_list.push_back(GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
ui::SetAtomArrayProperty(GetAcceleratedWidget(), "_NET_WM_STATE", "ATOM",
state_atom_list);
}
// Before the window is mapped, there is no SHOW_FULLSCREEN_STATE.
bool fullscreen = false;
if (options.Get(switches::kFullscreen, & fullscreen) && fullscreen) {
state_atom_list.push_back(GetAtom("_NET_WM_STATE_FULLSCREEN"));
}
ui::SetAtomArrayProperty(GetAcceleratedWidget(), "_NET_WM_STATE", "ATOM",
state_atom_list);
// Set the _NET_WM_WINDOW_TYPE.
std::string window_type;
if (options.Get(switches::kType, &window_type))
@@ -418,17 +426,19 @@ bool NativeWindowViews::IsMinimized() {
}
void NativeWindowViews::SetFullScreen(bool fullscreen) {
#if defined(OS_WIN)
// There is no native fullscreen state on Windows.
window_->SetFullscreen(fullscreen);
if (fullscreen)
NotifyWindowEnterFullScreen();
else
NotifyWindowLeaveFullScreen();
#else
if (IsVisible())
window_->SetFullscreen(fullscreen);
else
window_->native_widget_private()->ShowWithWindowState(
ui::SHOW_STATE_FULLSCREEN);
#if defined(OS_WIN)
// There is no native fullscreen state on Windows.
if (fullscreen)
NotifyWindowEnterFullScreen();
else
NotifyWindowLeaveFullScreen();
#endif
}
@@ -482,14 +492,6 @@ gfx::Size NativeWindowViews::GetContentSize() {
void NativeWindowViews::SetMinimumSize(const gfx::Size& size) {
minimum_size_ = size;
#if defined(USE_X11)
XSizeHints size_hints;
size_hints.flags = PMinSize;
size_hints.min_width = size.width();
size_hints.min_height = size.height();
XSetWMNormalHints(gfx::GetXDisplay(), GetAcceleratedWidget(), &size_hints);
#endif
}
gfx::Size NativeWindowViews::GetMinimumSize() {
@@ -498,14 +500,6 @@ gfx::Size NativeWindowViews::GetMinimumSize() {
void NativeWindowViews::SetMaximumSize(const gfx::Size& size) {
maximum_size_ = size;
#if defined(USE_X11)
XSizeHints size_hints;
size_hints.flags = PMaxSize;
size_hints.max_width = size.width();
size_hints.max_height = size.height();
XSetWMNormalHints(gfx::GetXDisplay(), GetAcceleratedWidget(), &size_hints);
#endif
}
gfx::Size NativeWindowViews::GetMaximumSize() {
@@ -890,7 +884,7 @@ views::NonClientFrameView* NativeWindowViews::CreateNonClientFrameView(
return frame_view;
#else
if (has_frame_) {
return new views::NativeFrameView(widget);
return new NativeFrameView(this, widget);
} else {
FramelessView* frame_view = new FramelessView;
frame_view->Init(this, widget);
@@ -920,7 +914,7 @@ bool NativeWindowViews::ExecuteWindowsCommand(int command_id) {
} else if ((command_id & sc_mask) == SC_MAXIMIZE) {
NotifyWindowMaximize();
} else {
std::string command = AppCommandToString(command_id & sc_mask);
std::string command = AppCommandToString(command_id);
FOR_EACH_OBSERVER(NativeWindowObserver,
observers_,
OnExecuteWindowsCommand(command));

View File

@@ -4,7 +4,6 @@
#include "atom/browser/net/adapter_request_job.h"
#include "atom/browser/atom_browser_context.h"
#include "base/threading/sequenced_worker_pool.h"
#include "atom/browser/net/url_request_buffer_job.h"
#include "atom/browser/net/url_request_fetch_job.h"
@@ -28,11 +27,7 @@ AdapterRequestJob::AdapterRequestJob(ProtocolHandler* protocol_handler,
void AdapterRequestJob::Start() {
DCHECK(!real_job_.get());
content::BrowserThread::PostTask(
content::BrowserThread::UI,
FROM_HERE,
base::Bind(&AdapterRequestJob::GetJobTypeInUI,
weak_factory_.GetWeakPtr()));
GetJobType();
}
void AdapterRequestJob::Kill() {
@@ -44,7 +39,11 @@ bool AdapterRequestJob::ReadRawData(net::IOBuffer* buf,
int buf_size,
int *bytes_read) {
DCHECK(!real_job_.get());
return real_job_->ReadRawData(buf, buf_size, bytes_read);
// Read post-filtered data if available.
if (real_job_->HasFilter())
return real_job_->Read(buf, buf_size, bytes_read);
else
return real_job_->ReadRawData(buf, buf_size, bytes_read);
}
bool AdapterRequestJob::IsRedirectResponse(GURL* location,
@@ -76,6 +75,11 @@ int AdapterRequestJob::GetResponseCode() const {
return real_job_->GetResponseCode();
}
void AdapterRequestJob::GetLoadTimingInfo(
net::LoadTimingInfo* load_timing_info) const {
real_job_->GetLoadTimingInfo(load_timing_info);
}
base::WeakPtr<AdapterRequestJob> AdapterRequestJob::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
@@ -115,7 +119,7 @@ void AdapterRequestJob::CreateFileJobAndStart(const base::FilePath& path) {
}
void AdapterRequestJob::CreateHttpJobAndStart(
AtomBrowserContext* browser_context,
net::URLRequestContextGetter* request_context_getter,
const GURL& url,
const std::string& method,
const std::string& referrer) {
@@ -124,7 +128,7 @@ void AdapterRequestJob::CreateHttpJobAndStart(
return;
}
real_job_ = new URLRequestFetchJob(browser_context, request(),
real_job_ = new URLRequestFetchJob(request_context_getter, request(),
network_delegate(), url, method, referrer);
real_job_->Start();
}
@@ -132,10 +136,13 @@ void AdapterRequestJob::CreateHttpJobAndStart(
void AdapterRequestJob::CreateJobFromProtocolHandlerAndStart() {
real_job_ = protocol_handler_->MaybeCreateJob(request(),
network_delegate());
if (!real_job_.get())
if (!real_job_.get()) {
CreateErrorJobAndStart(net::ERR_NOT_IMPLEMENTED);
else
} else {
// Copy headers from original request.
real_job_->SetExtraRequestHeaders(request()->extra_request_headers());
real_job_->Start();
}
}
} // namespace atom

View File

@@ -10,6 +10,7 @@
#include "base/memory/ref_counted_memory.h"
#include "base/memory/weak_ptr.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_job.h"
#include "net/url_request/url_request_job_factory.h"
#include "v8/include/v8.h"
@@ -45,13 +46,15 @@ class AdapterRequestJob : public net::URLRequestJob {
bool GetCharset(std::string* charset) override;
void GetResponseInfo(net::HttpResponseInfo* info) override;
int GetResponseCode() const override;
void GetLoadTimingInfo(
net::LoadTimingInfo* load_timing_info) const override;
base::WeakPtr<AdapterRequestJob> GetWeakPtr();
ProtocolHandler* default_protocol_handler() { return protocol_handler_; }
// Override this function to determine which job should be started.
virtual void GetJobTypeInUI() = 0;
virtual void GetJobType() = 0;
void CreateErrorJobAndStart(int error_code);
void CreateStringJobAndStart(const std::string& mime_type,
@@ -61,10 +64,11 @@ class AdapterRequestJob : public net::URLRequestJob {
const std::string& charset,
scoped_refptr<base::RefCountedBytes> data);
void CreateFileJobAndStart(const base::FilePath& path);
void CreateHttpJobAndStart(AtomBrowserContext* browser_context,
const GURL& url,
const std::string& method,
const std::string& referrer);
void CreateHttpJobAndStart(
net::URLRequestContextGetter* request_context_getter,
const GURL& url,
const std::string& method,
const std::string& referrer);
void CreateJobFromProtocolHandlerAndStart();
private:

View File

@@ -6,9 +6,12 @@
#include "atom/browser/net/atom_url_request_job_factory.h"
#include "base/stl_util.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/load_flags.h"
#include "net/url_request/url_request.h"
using content::BrowserThread;
namespace atom {
typedef net::URLRequestJobFactory::ProtocolHandler ProtocolHandler;
@@ -22,9 +25,7 @@ AtomURLRequestJobFactory::~AtomURLRequestJobFactory() {
bool AtomURLRequestJobFactory::SetProtocolHandler(
const std::string& scheme,
ProtocolHandler* protocol_handler) {
DCHECK(CalledOnValidThread());
base::AutoLock locked(lock_);
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!protocol_handler) {
ProtocolHandlerMap::iterator it = protocol_handler_map_.find(scheme);
@@ -45,10 +46,9 @@ bool AtomURLRequestJobFactory::SetProtocolHandler(
ProtocolHandler* AtomURLRequestJobFactory::ReplaceProtocol(
const std::string& scheme,
ProtocolHandler* protocol_handler) {
DCHECK(CalledOnValidThread());
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(protocol_handler);
base::AutoLock locked(lock_);
if (!ContainsKey(protocol_handler_map_, scheme))
return nullptr;
ProtocolHandler* original_protocol_handler = protocol_handler_map_[scheme];
@@ -58,9 +58,8 @@ ProtocolHandler* AtomURLRequestJobFactory::ReplaceProtocol(
ProtocolHandler* AtomURLRequestJobFactory::GetProtocolHandler(
const std::string& scheme) const {
DCHECK(CalledOnValidThread());
DCHECK_CURRENTLY_ON(BrowserThread::IO);
base::AutoLock locked(lock_);
ProtocolHandlerMap::const_iterator it = protocol_handler_map_.find(scheme);
if (it == protocol_handler_map_.end())
return nullptr;
@@ -69,7 +68,6 @@ ProtocolHandler* AtomURLRequestJobFactory::GetProtocolHandler(
bool AtomURLRequestJobFactory::HasProtocolHandler(
const std::string& scheme) const {
base::AutoLock locked(lock_);
return ContainsKey(protocol_handler_map_, scheme);
}
@@ -77,9 +75,8 @@ net::URLRequestJob* AtomURLRequestJobFactory::MaybeCreateJobWithProtocolHandler(
const std::string& scheme,
net::URLRequest* request,
net::NetworkDelegate* network_delegate) const {
DCHECK(CalledOnValidThread());
DCHECK_CURRENTLY_ON(BrowserThread::IO);
base::AutoLock locked(lock_);
ProtocolHandlerMap::const_iterator it = protocol_handler_map_.find(scheme);
if (it == protocol_handler_map_.end())
return nullptr;
@@ -101,7 +98,8 @@ net::URLRequestJob* AtomURLRequestJobFactory::MaybeInterceptResponse(
bool AtomURLRequestJobFactory::IsHandledProtocol(
const std::string& scheme) const {
DCHECK(CalledOnValidThread());
DCHECK_CURRENTLY_ON(BrowserThread::IO);
return HasProtocolHandler(scheme) ||
net::URLRequest::IsHandledProtocol(scheme);
}

View File

@@ -56,12 +56,10 @@ class AtomURLRequestJobFactory : public net::URLRequestJobFactory {
bool IsSafeRedirectTarget(const GURL& location) const override;
private:
typedef std::map<std::string, ProtocolHandler*> ProtocolHandlerMap;
using ProtocolHandlerMap = std::map<std::string, ProtocolHandler*>;
ProtocolHandlerMap protocol_handler_map_;
mutable base::Lock lock_;
DISALLOW_COPY_AND_ASSIGN(AtomURLRequestJobFactory);
};

View File

@@ -7,13 +7,14 @@
#include <algorithm>
#include <string>
#include "atom/browser/atom_browser_context.h"
#include "base/strings/string_util.h"
#include "base/thread_task_runner_handle.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_response_writer.h"
#include "net/url_request/url_request_context_builder.h"
#include "net/url_request/url_request_status.h"
namespace atom {
@@ -74,7 +75,7 @@ class ResponsePiper : public net::URLFetcherResponseWriter {
} // namespace
URLRequestFetchJob::URLRequestFetchJob(
AtomBrowserContext* browser_context,
net::URLRequestContextGetter* request_context_getter,
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
const GURL& url,
@@ -90,7 +91,12 @@ URLRequestFetchJob::URLRequestFetchJob(
request_type = GetRequestType(method);
fetcher_.reset(net::URLFetcher::Create(url, request_type, this));
fetcher_->SetRequestContext(browser_context->url_request_context_getter());
// Use request context if provided else create one.
if (request_context_getter)
fetcher_->SetRequestContext(request_context_getter);
else
fetcher_->SetRequestContext(GetRequestContext());
fetcher_->SaveResponseWithWriter(make_scoped_ptr(new ResponsePiper(this)));
// Use |request|'s referrer if |referrer| is not specified.
@@ -107,6 +113,17 @@ URLRequestFetchJob::URLRequestFetchJob(
}
}
net::URLRequestContextGetter* URLRequestFetchJob::GetRequestContext() {
if (!url_request_context_getter_.get()) {
auto task_runner = base::ThreadTaskRunnerHandle::Get();
net::URLRequestContextBuilder builder;
builder.set_proxy_service(net::ProxyService::CreateDirect());
url_request_context_getter_ =
new net::TrivialURLRequestContextGetter(builder.Build(), task_runner);
}
return url_request_context_getter_.get();
}
void URLRequestFetchJob::HeadersCompleted() {
response_info_.reset(new net::HttpResponseInfo);
response_info_->headers = fetcher_->GetResponseHeaders();

View File

@@ -7,6 +7,7 @@
#include <string>
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request_job.h"
@@ -17,13 +18,14 @@ class AtomBrowserContext;
class URLRequestFetchJob : public net::URLRequestJob,
public net::URLFetcherDelegate {
public:
URLRequestFetchJob(AtomBrowserContext* browser_context,
URLRequestFetchJob(net::URLRequestContextGetter* request_context_getter,
net::URLRequest* request,
net::NetworkDelegate* network_delegate,
const GURL& url,
const std::string& method,
const std::string& referrer);
net::URLRequestContextGetter* GetRequestContext();
void HeadersCompleted();
int DataAvailable(net::IOBuffer* buffer, int num_bytes);
@@ -41,6 +43,7 @@ class URLRequestFetchJob : public net::URLRequestJob,
void OnURLFetchComplete(const net::URLFetcher* source) override;
private:
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
scoped_ptr<net::URLFetcher> fetcher_;
scoped_refptr<net::IOBuffer> pending_buffer_;
int pending_buffer_size_;

View File

@@ -17,7 +17,7 @@
<key>CFBundleIconFile</key>
<string>atom.icns</string>
<key>CFBundleVersion</key>
<string>0.29.0</string>
<string>0.30.1</string>
<key>LSMinimumSystemVersion</key>
<string>10.8.0</string>
<key>NSMainNibFile</key>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<dependency>
<dependentAssembly>
<assemblyIdentity type="Win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"></assemblyIdentity>
</dependentAssembly>
</dependency>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" />
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

View File

@@ -1,6 +1,12 @@
// Microsoft Visual C++ generated resource script.
//
#include "grit\\ui_unscaled_resources.h"
#include "resource.h"
#include <winresrc.h>
#ifdef IDC_STATIC
#undef IDC_STATIC
#endif
#define IDC_STATIC (-1)
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
@@ -50,8 +56,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,29,0,0
PRODUCTVERSION 0,29,0,0
FILEVERSION 0,30,1,0
PRODUCTVERSION 0,30,1,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -68,12 +74,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "GitHub, Inc."
VALUE "FileDescription", "Electron"
VALUE "FileVersion", "0.29.0"
VALUE "FileVersion", "0.30.1"
VALUE "InternalName", "electron.exe"
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
VALUE "OriginalFilename", "electron.exe"
VALUE "ProductName", "Electron"
VALUE "ProductVersion", "0.29.0"
VALUE "ProductVersion", "0.30.1"
VALUE "SquirrelAwareVersion", "1"
END
END
@@ -106,3 +112,28 @@ END
IDR_MAINFRAME ICON "atom.ico"
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//
// Cursors
//
IDC_ALIAS CURSOR "ui\\resources\\cursors\\aliasb.cur"
IDC_CELL CURSOR "ui\\resources\\cursors\\cell.cur"
IDC_COLRESIZE CURSOR "ui\\resources\\cursors\\col_resize.cur"
IDC_COPYCUR CURSOR "ui\\resources\\cursors\\copy.cur"
IDC_CURSOR_NONE CURSOR "ui\\resources\\cursors\\none.cur"
IDC_HAND_GRAB CURSOR "ui\\resources\\cursors\\hand_grab.cur"
IDC_HAND_GRABBING CURSOR "ui\\resources\\cursors\\hand_grabbing.cur"
IDC_PAN_EAST CURSOR "ui\\resources\\cursors\\pan_east.cur"
IDC_PAN_MIDDLE CURSOR "ui\\resources\\cursors\\pan_middle.cur"
IDC_PAN_NORTH CURSOR "ui\\resources\\cursors\\pan_north.cur"
IDC_PAN_NORTH_EAST CURSOR "ui\\resources\\cursors\\pan_north_east.cur"
IDC_PAN_NORTH_WEST CURSOR "ui\\resources\\cursors\\pan_north_west.cur"
IDC_PAN_SOUTH CURSOR "ui\\resources\\cursors\\pan_south.cur"
IDC_PAN_SOUTH_EAST CURSOR "ui\\resources\\cursors\\pan_south_east.cur"
IDC_PAN_SOUTH_WEST CURSOR "ui\\resources\\cursors\\pan_south_west.cur"
IDC_PAN_WEST CURSOR "ui\\resources\\cursors\\pan_west.cur"
IDC_ROWRESIZE CURSOR "ui\\resources\\cursors\\row_resize.cur"
IDC_VERTICALTEXT CURSOR "ui\\resources\\cursors\\vertical_text.cur"
IDC_ZOOMIN CURSOR "ui\\resources\\cursors\\zoom_in.cur"
IDC_ZOOMOUT CURSOR "ui\\resources\\cursors\\zoom_out.cur"
/////////////////////////////////////////////////////////////////////////////

View File

@@ -4,49 +4,18 @@
#include "atom/browser/ui/file_dialog.h"
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
// This conflicts with mate::Converter,
#undef True
#undef False
// and V8.
#undef None
#include "atom/browser/native_window.h"
#include "base/callback.h"
#include "base/files/file_util.h"
#include "base/strings/string_util.h"
#include "chrome/browser/ui/libgtk2ui/gtk2_signal.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "chrome/browser/ui/libgtk2ui/gtk2_util.h"
#include "ui/views/widget/desktop_aura/x11_desktop_handler.h"
namespace file_dialog {
namespace {
const char kAuraTransientParent[] = "aura-transient-parent";
void SetGtkTransientForAura(GtkWidget* dialog, aura::Window* parent) {
if (!parent || !parent->GetHost())
return;
gtk_widget_realize(dialog);
GdkWindow* gdk_window = gtk_widget_get_window(dialog);
// TODO(erg): Check to make sure we're using X11 if wayland or some other
// display server ever happens. Otherwise, this will crash.
XSetTransientForHint(GDK_WINDOW_XDISPLAY(gdk_window),
GDK_WINDOW_XID(gdk_window),
parent->GetHost()->GetAcceleratedWidget());
// We also set the |parent| as a property of |dialog|, so that we can unlink
// the two later.
g_object_set_data(G_OBJECT(dialog), kAuraTransientParent, parent);
}
// Makes sure that .jpg also shows .JPG.
gboolean FileFilterCaseInsensitive(const GtkFileFilterInfo* file_info,
std::string* file_extension) {
@@ -65,7 +34,7 @@ class FileChooserDialog {
const std::string& title,
const base::FilePath& default_path,
const Filters& filters)
: dialog_scope_(new atom::NativeWindow::DialogScope(parent_window)) {
: dialog_scope_(parent_window) {
const char* confirm_text = GTK_STOCK_OK;
if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
confirm_text = GTK_STOCK_SAVE;
@@ -81,7 +50,7 @@ class FileChooserDialog {
NULL);
if (parent_window) {
gfx::NativeWindow window = parent_window->GetNativeWindow();
SetGtkTransientForAura(dialog_, window);
libgtk2ui::SetGtkTransientForAura(dialog_, window);
}
if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
@@ -162,13 +131,13 @@ class FileChooserDialog {
private:
void AddFilters(const Filters& filters);
atom::NativeWindow::DialogScope dialog_scope_;
GtkWidget* dialog_;
SaveDialogCallback save_callback_;
OpenDialogCallback open_callback_;
scoped_ptr<atom::NativeWindow::DialogScope> dialog_scope_;
DISALLOW_COPY_AND_ASSIGN(FileChooserDialog);
};

View File

@@ -18,25 +18,11 @@ namespace file_dialog {
namespace {
CFStringRef CreateUTIFromExtension(const std::string& ext) {
base::ScopedCFTypeRef<CFStringRef> ext_cf(base::SysUTF8ToCFStringRef(ext));
return UTTypeCreatePreferredIdentifierForTag(
kUTTagClassFilenameExtension, ext_cf.get(), NULL);
}
void SetAllowedFileTypes(NSSavePanel* dialog, const Filters& filters) {
NSMutableSet* file_type_set = [NSMutableSet set];
for (size_t i = 0; i < filters.size(); ++i) {
const Filter& filter = filters[i];
for (size_t j = 0; j < filter.second.size(); ++j) {
base::ScopedCFTypeRef<CFStringRef> uti(
CreateUTIFromExtension(filter.second[j]));
[file_type_set addObject:base::mac::CFToNSCast(uti.get())];
// Always allow the extension itself, in case the UTI doesn't map
// back to the original extension correctly. This occurs with dynamic
// UTIs on 10.7 and 10.8.
// See http://crbug.com/148840, http://openradar.me/12316273
base::ScopedCFTypeRef<CFStringRef> ext_cf(
base::SysUTF8ToCFStringRef(filter.second[j]));
[file_type_set addObject:base::mac::CFToNSCast(ext_cf.get())];

View File

@@ -120,12 +120,13 @@ struct RunState {
};
bool CreateDialogThread(RunState* run_state) {
base::Thread* thread = new base::Thread(ATOM_PRODUCT_NAME "FileDialogThread");
scoped_ptr<base::Thread> thread(
new base::Thread(ATOM_PRODUCT_NAME "FileDialogThread"));
thread->init_com_with_mta(false);
if (!thread->Start())
return false;
run_state->dialog_thread = thread;
run_state->dialog_thread = thread.release();
run_state->ui_message_loop = base::MessageLoop::current();
return true;
}

View File

@@ -22,7 +22,14 @@ class NativeWindow;
enum MessageBoxType {
MESSAGE_BOX_TYPE_NONE = 0,
MESSAGE_BOX_TYPE_INFORMATION,
MESSAGE_BOX_TYPE_WARNING
MESSAGE_BOX_TYPE_WARNING,
MESSAGE_BOX_TYPE_ERROR,
MESSAGE_BOX_TYPE_QUESTION,
};
enum MessageBoxOptions {
MESSAGE_BOX_NONE = 0,
MESSAGE_BOX_NO_LINK = 1 << 0,
};
typedef base::Callback<void(int code)> MessageBoxCallback;
@@ -30,6 +37,8 @@ typedef base::Callback<void(int code)> MessageBoxCallback;
int ShowMessageBox(NativeWindow* parent_window,
MessageBoxType type,
const std::vector<std::string>& buttons,
int cancel_id,
int options,
const std::string& title,
const std::string& message,
const std::string& detail,
@@ -38,6 +47,8 @@ int ShowMessageBox(NativeWindow* parent_window,
void ShowMessageBox(NativeWindow* parent_window,
MessageBoxType type,
const std::vector<std::string>& buttons,
int cancel_id,
int options,
const std::string& title,
const std::string& message,
const std::string& detail,

View File

@@ -0,0 +1,205 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/ui/message_box.h"
#include "atom/browser/browser.h"
#include "atom/browser/native_window.h"
#include "base/callback.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/libgtk2ui/gtk2_signal.h"
#include "chrome/browser/ui/libgtk2ui/gtk2_util.h"
#include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h"
#include "ui/views/widget/desktop_aura/x11_desktop_handler.h"
#define ANSI_FOREGROUND_RED "\x1b[31m"
#define ANSI_FOREGROUND_BLACK "\x1b[30m"
#define ANSI_TEXT_BOLD "\x1b[1m"
#define ANSI_BACKGROUND_GRAY "\x1b[47m"
#define ANSI_RESET "\x1b[0m"
namespace atom {
namespace {
class GtkMessageBox {
public:
GtkMessageBox(NativeWindow* parent_window,
MessageBoxType type,
const std::vector<std::string>& buttons,
int cancel_id,
const std::string& title,
const std::string& message,
const std::string& detail,
const gfx::ImageSkia& icon)
: dialog_scope_(parent_window),
cancel_id_(cancel_id) {
// Create dialog.
dialog_ = gtk_message_dialog_new(
nullptr, // parent
static_cast<GtkDialogFlags>(0), // no flags
GetMessageType(type), // type
GTK_BUTTONS_NONE, // no buttons
"%s", message.c_str());
if (!detail.empty())
gtk_message_dialog_format_secondary_text(
GTK_MESSAGE_DIALOG(dialog_), "%s", detail.c_str());
if (!title.empty())
gtk_window_set_title(GTK_WINDOW(dialog_), title.c_str());
// Set dialog's icon.
if (!icon.isNull()) {
GdkPixbuf* pixbuf = libgtk2ui::GdkPixbufFromSkBitmap(*icon.bitmap());
GtkWidget* image = gtk_image_new_from_pixbuf(pixbuf);
gtk_message_dialog_set_image(GTK_MESSAGE_DIALOG(dialog_), image);
gtk_widget_show(image);
g_object_unref(pixbuf);
}
// Add buttons.
for (size_t i = 0; i < buttons.size(); ++i) {
gtk_dialog_add_button(GTK_DIALOG(dialog_),
TranslateToStock(i, buttons[i]),
i);
}
// Parent window.
if (parent_window) {
gfx::NativeWindow window = parent_window->GetNativeWindow();
libgtk2ui::SetGtkTransientForAura(dialog_, window);
}
}
~GtkMessageBox() {
gtk_widget_destroy(dialog_);
}
GtkMessageType GetMessageType(MessageBoxType type) {
switch (type) {
case MESSAGE_BOX_TYPE_INFORMATION:
return GTK_MESSAGE_INFO;
case MESSAGE_BOX_TYPE_WARNING:
return GTK_MESSAGE_WARNING;
case MESSAGE_BOX_TYPE_QUESTION:
return GTK_MESSAGE_QUESTION;
case MESSAGE_BOX_TYPE_ERROR:
return GTK_MESSAGE_ERROR;
default:
return GTK_MESSAGE_OTHER;
}
}
const char* TranslateToStock(int id, const std::string& text) {
std::string lower = base::StringToLowerASCII(text);
if (lower == "cancel")
return GTK_STOCK_CANCEL;
else if (lower == "no")
return GTK_STOCK_NO;
else if (lower == "ok")
return GTK_STOCK_OK;
else if (lower == "yes")
return GTK_STOCK_YES;
else
return text.c_str();
}
void Show() {
gtk_widget_show_all(dialog_);
// We need to call gtk_window_present after making the widgets visible to
// make sure window gets correctly raised and gets focus.
int time = views::X11DesktopHandler::get()->wm_user_time_ms();
gtk_window_present_with_time(GTK_WINDOW(dialog_), time);
}
int RunSynchronous() {
gtk_window_set_modal(GTK_WINDOW(dialog_), TRUE);
Show();
int response = gtk_dialog_run(GTK_DIALOG(dialog_));
if (response < 0)
return cancel_id_;
else
return response;
}
void RunAsynchronous(const MessageBoxCallback& callback) {
callback_ = callback;
g_signal_connect(dialog_, "delete-event",
G_CALLBACK(gtk_widget_hide_on_delete), nullptr);
g_signal_connect(dialog_, "response",
G_CALLBACK(OnResponseDialogThunk), this);
Show();
}
CHROMEGTK_CALLBACK_1(GtkMessageBox, void, OnResponseDialog, int);
private:
atom::NativeWindow::DialogScope dialog_scope_;
// The id to return when the dialog is closed without pressing buttons.
int cancel_id_;
GtkWidget* dialog_;
MessageBoxCallback callback_;
DISALLOW_COPY_AND_ASSIGN(GtkMessageBox);
};
void GtkMessageBox::OnResponseDialog(GtkWidget* widget, int response) {
gtk_widget_hide_all(dialog_);
if (response < 0)
callback_.Run(cancel_id_);
else
callback_.Run(response);
delete this;
}
} // namespace
int ShowMessageBox(NativeWindow* parent,
MessageBoxType type,
const std::vector<std::string>& buttons,
int cancel_id,
int options,
const std::string& title,
const std::string& message,
const std::string& detail,
const gfx::ImageSkia& icon) {
return GtkMessageBox(parent, type, buttons, cancel_id, title, message, detail,
icon).RunSynchronous();
}
void ShowMessageBox(NativeWindow* parent,
MessageBoxType type,
const std::vector<std::string>& buttons,
int cancel_id,
int options,
const std::string& title,
const std::string& message,
const std::string& detail,
const gfx::ImageSkia& icon,
const MessageBoxCallback& callback) {
(new GtkMessageBox(parent, type, buttons, cancel_id, title, message, detail,
icon))->RunAsynchronous(callback);
}
void ShowErrorBox(const base::string16& title, const base::string16& content) {
if (Browser::Get()->is_ready()) {
GtkMessageBox(nullptr, MESSAGE_BOX_TYPE_ERROR, { "OK" }, 0, "Error",
base::UTF16ToUTF8(title).c_str(),
base::UTF16ToUTF8(content).c_str(),
gfx::ImageSkia()).RunSynchronous();
} else {
fprintf(stderr,
ANSI_TEXT_BOLD ANSI_BACKGROUND_GRAY
ANSI_FOREGROUND_RED "%s\n"
ANSI_FOREGROUND_BLACK "%s"
ANSI_RESET "\n",
base::UTF16ToUTF8(title).c_str(),
base::UTF16ToUTF8(content).c_str());
}
}
} // namespace atom

View File

@@ -94,6 +94,8 @@ void SetReturnCode(int* ret_code, int result) {
int ShowMessageBox(NativeWindow* parent_window,
MessageBoxType type,
const std::vector<std::string>& buttons,
int cancel_id,
int options,
const std::string& title,
const std::string& message,
const std::string& detail,
@@ -125,6 +127,8 @@ int ShowMessageBox(NativeWindow* parent_window,
void ShowMessageBox(NativeWindow* parent_window,
MessageBoxType type,
const std::vector<std::string>& buttons,
int cancel_id,
int options,
const std::string& title,
const std::string& message,
const std::string& detail,

View File

@@ -1,417 +0,0 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/ui/message_box.h"
#if defined(USE_X11)
#include <gtk/gtk.h>
#endif
#include "atom/browser/native_window.h"
#include "base/callback.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/views/background.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/controls/message_box_view.h"
#include "ui/views/layout/grid_layout.h"
#include "ui/views/layout/layout_constants.h"
#include "ui/views/bubble/bubble_border.h"
#include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/wm/core/shadow_types.h"
#if defined(USE_X11)
#include "atom/browser/browser.h"
#include "ui/views/window/native_frame_view.h"
#endif
#if defined(OS_WIN)
#include "ui/base/win/message_box_win.h"
#endif
#define ANSI_FOREGROUND_RED "\x1b[31m"
#define ANSI_FOREGROUND_BLACK "\x1b[30m"
#define ANSI_TEXT_BOLD "\x1b[1m"
#define ANSI_BACKGROUND_GRAY "\x1b[47m"
#define ANSI_RESET "\x1b[0m"
namespace atom {
namespace {
// The group used by the buttons. This name is chosen voluntarily big not to
// conflict with other groups that could be in the dialog content.
const int kButtonGroup = 1127;
class MessageDialogClientView;
class MessageDialog : public views::WidgetDelegate,
public views::View,
public views::ButtonListener {
public:
MessageDialog(NativeWindow* parent_window,
MessageBoxType type,
const std::vector<std::string>& buttons,
const std::string& title,
const std::string& message,
const std::string& detail,
const gfx::ImageSkia& icon);
virtual ~MessageDialog();
void Show(base::RunLoop* run_loop = NULL);
void Close();
int GetResult() const;
void set_callback(const MessageBoxCallback& callback) {
delete_on_close_ = true;
callback_ = callback;
}
private:
// Overridden from views::WidgetDelegate:
base::string16 GetWindowTitle() const override;
gfx::ImageSkia GetWindowAppIcon() override;
gfx::ImageSkia GetWindowIcon() override;
bool ShouldShowWindowIcon() const override;
views::Widget* GetWidget() override;
const views::Widget* GetWidget() const override;
views::View* GetContentsView() override;
views::View* GetInitiallyFocusedView() override;
ui::ModalType GetModalType() const override;
views::NonClientFrameView* CreateNonClientFrameView(
views::Widget* widget) override;
views::ClientView* CreateClientView(views::Widget* widget) override;
// Overridden from views::View:
gfx::Size GetPreferredSize() const override;
void Layout() override;
bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
// Overridden from views::ButtonListener:
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
gfx::ImageSkia icon_;
bool delete_on_close_;
int result_;
base::string16 title_;
NativeWindow* parent_;
scoped_ptr<views::Widget> widget_;
views::MessageBoxView* message_box_view_;
std::vector<views::LabelButton*> buttons_;
base::RunLoop* run_loop_;
scoped_ptr<NativeWindow::DialogScope> dialog_scope_;
MessageBoxCallback callback_;
DISALLOW_COPY_AND_ASSIGN(MessageDialog);
};
class MessageDialogClientView : public views::ClientView {
public:
MessageDialogClientView(MessageDialog* dialog, views::Widget* widget)
: views::ClientView(widget, dialog),
dialog_(dialog) {
}
// views::ClientView:
bool CanClose() override {
dialog_->Close();
return false;
}
private:
MessageDialog* dialog_;
DISALLOW_COPY_AND_ASSIGN(MessageDialogClientView);
};
////////////////////////////////////////////////////////////////////////////////
// MessageDialog, public:
MessageDialog::MessageDialog(NativeWindow* parent_window,
MessageBoxType type,
const std::vector<std::string>& buttons,
const std::string& title,
const std::string& message,
const std::string& detail,
const gfx::ImageSkia& icon)
: icon_(icon),
delete_on_close_(false),
result_(-1),
title_(base::UTF8ToUTF16(title)),
parent_(parent_window),
message_box_view_(NULL),
run_loop_(NULL),
dialog_scope_(new NativeWindow::DialogScope(parent_window)) {
DCHECK_GT(buttons.size(), 0u);
set_owned_by_client();
if (!parent_)
set_background(views::Background::CreateStandardPanelBackground());
std::string content = message + "\n" + detail;
views::MessageBoxView::InitParams box_params(base::UTF8ToUTF16(content));
message_box_view_ = new views::MessageBoxView(box_params);
AddChildView(message_box_view_);
for (size_t i = 0; i < buttons.size(); ++i) {
views::LabelButton* button = new views::LabelButton(
this, base::UTF8ToUTF16(buttons[i]));
button->set_tag(i);
button->SetMinSize(gfx::Size(60, 30));
button->SetStyle(views::Button::STYLE_BUTTON);
button->SetGroup(kButtonGroup);
buttons_.push_back(button);
AddChildView(button);
}
// First button is always default button.
buttons_[0]->SetIsDefault(true);
buttons_[0]->AddAccelerator(ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE));
views::Widget::InitParams params;
params.delegate = this;
params.type = views::Widget::InitParams::TYPE_WINDOW;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
if (parent_) {
params.parent = parent_->GetNativeWindow();
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
// Use bubble style for dialog has a parent.
params.remove_standard_frame = true;
}
widget_.reset(new views::Widget);
widget_->Init(params);
widget_->UpdateWindowIcon();
// Bind to ESC.
AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
}
MessageDialog::~MessageDialog() {
}
void MessageDialog::Show(base::RunLoop* run_loop) {
run_loop_ = run_loop;
widget_->Show();
}
void MessageDialog::Close() {
dialog_scope_.reset();
if (delete_on_close_) {
callback_.Run(GetResult());
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
} else if (run_loop_) {
run_loop_->Quit();
}
}
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:
base::string16 MessageDialog::GetWindowTitle() const {
return title_;
}
gfx::ImageSkia MessageDialog::GetWindowAppIcon() {
return icon_;
}
gfx::ImageSkia MessageDialog::GetWindowIcon() {
return icon_;
}
bool MessageDialog::ShouldShowWindowIcon() const {
return true;
}
views::Widget* MessageDialog::GetWidget() {
return widget_.get();
}
const views::Widget* MessageDialog::GetWidget() const {
return widget_.get();
}
views::View* MessageDialog::GetContentsView() {
return this;
}
views::View* MessageDialog::GetInitiallyFocusedView() {
if (buttons_.size() > 0)
return buttons_[0];
else
return this;
}
ui::ModalType MessageDialog::GetModalType() const {
return ui::MODAL_TYPE_SYSTEM;
}
views::NonClientFrameView* MessageDialog::CreateNonClientFrameView(
views::Widget* widget) {
if (!parent_) {
#if defined(USE_X11)
return new views::NativeFrameView(widget);
#else
return NULL;
#endif
}
// Create a bubble style frame like Chrome.
views::BubbleFrameView* frame = new views::BubbleFrameView(gfx::Insets());
const SkColor color = widget->GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_DialogBackground);
scoped_ptr<views::BubbleBorder> border(new views::BubbleBorder(
views::BubbleBorder::FLOAT, views::BubbleBorder::SMALL_SHADOW, color));
frame->SetBubbleBorder(border.Pass());
wm::SetShadowType(widget->GetNativeWindow(), wm::SHADOW_TYPE_NONE);
return frame;
}
views::ClientView* MessageDialog::CreateClientView(views::Widget* widget) {
return new MessageDialogClientView(this, widget);
}
gfx::Size MessageDialog::GetPreferredSize() const {
gfx::Size size(0, buttons_[0]->GetPreferredSize().height());
for (size_t i = 0; i < buttons_.size(); ++i)
size.Enlarge(buttons_[i]->GetPreferredSize().width(), 0);
// Button spaces.
size.Enlarge(views::kRelatedButtonHSpacing * (buttons_.size() - 1),
views::kRelatedControlVerticalSpacing);
// The message box view.
gfx::Size contents_size = message_box_view_->GetPreferredSize();
size.Enlarge(0, contents_size.height());
if (contents_size.width() > size.width())
size.set_width(contents_size.width());
return size;
}
void MessageDialog::Layout() {
gfx::Rect bounds = GetContentsBounds();
// Layout the row containing the buttons.
int x = bounds.width();
int height = buttons_[0]->GetPreferredSize().height() +
views::kRelatedControlVerticalSpacing;
// NB: We iterate through the buttons backwards here because
// Mac and Windows buttons are laid out in opposite order.
for (int i = buttons_.size() - 1; i >= 0; --i) {
gfx::Size size = buttons_[i]->GetPreferredSize();
x -= size.width() + views::kRelatedButtonHSpacing;
buttons_[i]->SetBounds(x, bounds.height() - height,
size.width(), size.height());
}
// Layout the message box view.
message_box_view_->SetBounds(bounds.x(), bounds.y(), bounds.width(),
bounds.height() - height);
}
bool MessageDialog::AcceleratorPressed(const ui::Accelerator& accelerator) {
DCHECK_EQ(accelerator.key_code(), ui::VKEY_ESCAPE);
widget_->Close();
return true;
}
void MessageDialog::ButtonPressed(views::Button* sender,
const ui::Event& event) {
result_ = sender->tag();
widget_->Close();
}
} // 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,
const gfx::ImageSkia& icon) {
MessageDialog dialog(
parent_window, type, buttons, title, message, detail, icon);
{
base::MessageLoop::ScopedNestableTaskAllower allow(
base::MessageLoopForUI::current());
base::RunLoop run_loop;
dialog.Show(&run_loop);
run_loop.Run();
}
return dialog.GetResult();
}
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 gfx::ImageSkia& icon,
const MessageBoxCallback& callback) {
// The dialog would be deleted when the dialog is closed.
MessageDialog* dialog = new MessageDialog(
parent_window, type, buttons, title, message, detail, icon);
dialog->set_callback(callback);
dialog->Show();
}
void ShowErrorBox(const base::string16& title, const base::string16& content) {
#if defined(OS_WIN)
ui::MessageBox(NULL, content, title, MB_OK | MB_ICONERROR | MB_TASKMODAL);
#elif defined(USE_X11)
if (Browser::Get()->is_ready()) {
GtkWidget* dialog = gtk_message_dialog_new(
NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
"%s", base::UTF16ToUTF8(title).c_str());
gtk_message_dialog_format_secondary_text(
GTK_MESSAGE_DIALOG(dialog),
"%s", base::UTF16ToUTF8(content).c_str());
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
} else {
fprintf(stderr,
ANSI_TEXT_BOLD ANSI_BACKGROUND_GRAY
ANSI_FOREGROUND_RED "%s\n"
ANSI_FOREGROUND_BLACK "%s"
ANSI_RESET "\n",
base::UTF16ToUTF8(title).c_str(),
base::UTF16ToUTF8(content).c_str());
}
#endif
}
} // namespace atom

View File

@@ -0,0 +1,230 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/ui/message_box.h"
#include <windows.h>
#include <commctrl.h>
#include <map>
#include <vector>
#include "atom/browser/native_window_views.h"
#include "base/callback.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread.h"
#include "base/win/scoped_gdi_object.h"
#include "content/public/browser/browser_thread.h"
#include "ui/gfx/icon_util.h"
namespace atom {
namespace {
// Small command ID values are already taken by Windows, we have to start from
// a large number to avoid conflicts with Windows.
const int kIDStart = 100;
// Get the common ID from button's name.
struct CommonButtonID {
int button;
int id;
};
CommonButtonID GetCommonID(const base::string16& button) {
base::string16 lower = base::StringToLowerASCII(button);
if (lower == L"ok")
return { TDCBF_OK_BUTTON, IDOK };
else if (lower == L"yes")
return { TDCBF_YES_BUTTON, IDYES };
else if (lower == L"no")
return { TDCBF_NO_BUTTON, IDNO };
else if (lower == L"cancel")
return { TDCBF_CANCEL_BUTTON, IDCANCEL };
else if (lower == L"retry")
return { TDCBF_RETRY_BUTTON, IDRETRY };
else if (lower == L"close")
return { TDCBF_CLOSE_BUTTON, IDCLOSE };
return { -1, -1 };
}
// Determine whether the buttons are common buttons, if so map common ID
// to button ID.
void MapToCommonID(const std::vector<base::string16>& buttons,
std::map<int, int>* id_map,
TASKDIALOG_COMMON_BUTTON_FLAGS* button_flags,
std::vector<TASKDIALOG_BUTTON>* dialog_buttons) {
for (size_t i = 0; i < buttons.size(); ++i) {
auto common = GetCommonID(buttons[i]);
if (common.button != -1) {
// It is a common button.
(*id_map)[common.id] = i;
(*button_flags) |= common.button;
} else {
// It is a custom button.
dialog_buttons->push_back({i + kIDStart, buttons[i].c_str()});
}
}
}
int ShowMessageBoxUTF16(HWND parent,
MessageBoxType type,
const std::vector<base::string16>& buttons,
int cancel_id,
int options,
const base::string16& title,
const base::string16& message,
const base::string16& detail,
const gfx::ImageSkia& icon) {
TASKDIALOG_FLAGS flags = TDF_SIZE_TO_CONTENT; // show all content.
if (cancel_id != 0)
flags |= TDF_ALLOW_DIALOG_CANCELLATION; // allow dialog to be cancelled.
TASKDIALOGCONFIG config = { 0 };
config.cbSize = sizeof(config);
config.hwndParent = parent;
config.hInstance = GetModuleHandle(NULL);
config.dwFlags = flags;
if (!title.empty())
config.pszWindowTitle = title.c_str();
base::win::ScopedHICON hicon;
if (!icon.isNull()) {
hicon.Set(IconUtil::CreateHICONFromSkBitmap(*icon.bitmap()));
config.dwFlags |= TDF_USE_HICON_MAIN;
config.hMainIcon = hicon.Get();
} else {
// Show icon according to dialog's type.
switch (type) {
case MESSAGE_BOX_TYPE_INFORMATION:
case MESSAGE_BOX_TYPE_QUESTION:
config.pszMainIcon = TD_INFORMATION_ICON;
break;
case MESSAGE_BOX_TYPE_WARNING:
config.pszMainIcon = TD_WARNING_ICON;
break;
case MESSAGE_BOX_TYPE_ERROR:
config.pszMainIcon = TD_ERROR_ICON;
break;
}
}
// If "detail" is empty then don't make message hilighted.
if (detail.empty()) {
config.pszContent = message.c_str();
} else {
config.pszMainInstruction = message.c_str();
config.pszContent = detail.c_str();
}
// Iterate through the buttons, put common buttons in dwCommonButtons
// and custom buttons in pButtons.
std::map<int, int> id_map;
std::vector<TASKDIALOG_BUTTON> dialog_buttons;
if (options & MESSAGE_BOX_NO_LINK) {
for (size_t i = 0; i < buttons.size(); ++i)
dialog_buttons.push_back({i + kIDStart, buttons[i].c_str()});
} else {
MapToCommonID(buttons, &id_map, &config.dwCommonButtons, &dialog_buttons);
}
if (dialog_buttons.size() > 0) {
config.pButtons = &dialog_buttons.front();
config.cButtons = dialog_buttons.size();
if (!(options & MESSAGE_BOX_NO_LINK))
config.dwFlags |= TDF_USE_COMMAND_LINKS; // custom buttons as links.
}
int id = 0;
TaskDialogIndirect(&config, &id, NULL, NULL);
if (id_map.find(id) != id_map.end()) // common button.
return id_map[id];
else if (id >= kIDStart) // custom button.
return id - kIDStart;
else
return cancel_id;
}
void RunMessageBoxInNewThread(base::Thread* thread,
NativeWindow* parent,
MessageBoxType type,
const std::vector<std::string>& buttons,
int cancel_id,
int options,
const std::string& title,
const std::string& message,
const std::string& detail,
const gfx::ImageSkia& icon,
const MessageBoxCallback& callback) {
int result = ShowMessageBox(parent, type, buttons, cancel_id, options, title,
message, detail, icon);
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE, base::Bind(callback, result));
content::BrowserThread::DeleteSoon(
content::BrowserThread::UI, FROM_HERE, thread);
}
} // namespace
int ShowMessageBox(NativeWindow* parent,
MessageBoxType type,
const std::vector<std::string>& buttons,
int cancel_id,
int options,
const std::string& title,
const std::string& message,
const std::string& detail,
const gfx::ImageSkia& icon) {
std::vector<base::string16> utf16_buttons;
for (const auto& button : buttons)
utf16_buttons.push_back(base::UTF8ToUTF16(button));
HWND hwnd_parent = parent ?
static_cast<atom::NativeWindowViews*>(parent)->GetAcceleratedWidget() :
NULL;
NativeWindow::DialogScope dialog_scope(parent);
return ShowMessageBoxUTF16(hwnd_parent,
type,
utf16_buttons,
cancel_id,
options,
base::UTF8ToUTF16(title),
base::UTF8ToUTF16(message),
base::UTF8ToUTF16(detail),
icon);
}
void ShowMessageBox(NativeWindow* parent,
MessageBoxType type,
const std::vector<std::string>& buttons,
int cancel_id,
int options,
const std::string& title,
const std::string& message,
const std::string& detail,
const gfx::ImageSkia& icon,
const MessageBoxCallback& callback) {
scoped_ptr<base::Thread> thread(
new base::Thread(ATOM_PRODUCT_NAME "MessageBoxThread"));
thread->init_com_with_mta(false);
if (!thread->Start()) {
callback.Run(cancel_id);
return;
}
base::Thread* unretained = thread.release();
unretained->message_loop()->PostTask(
FROM_HERE,
base::Bind(&RunMessageBoxInNewThread, base::Unretained(unretained),
parent, type, buttons, cancel_id, options, title, message,
detail, icon, callback));
}
void ShowErrorBox(const base::string16& title, const base::string16& content) {
ShowMessageBoxUTF16(NULL, MESSAGE_BOX_TYPE_ERROR, {}, 0, 0, L"Error", title,
content, gfx::ImageSkia());
}
} // namespace atom

View File

@@ -26,6 +26,9 @@ void TrayIcon::DisplayBalloon(const gfx::Image& icon,
const base::string16& contents) {
}
void TrayIcon::PopContextMenu(const gfx::Point& pos) {
}
void TrayIcon::NotifyClicked(const gfx::Rect& bounds) {
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnClicked(bounds));
}
@@ -46,4 +49,12 @@ void TrayIcon::NotifyBalloonClosed() {
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnBalloonClosed());
}
void TrayIcon::NotifyRightClicked(const gfx::Rect& bounds) {
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnRightClicked(bounds));
}
void TrayIcon::NotfiyDropFiles(const std::vector<std::string>& files) {
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnDropFiles(files));
}
} // namespace atom

View File

@@ -6,6 +6,7 @@
#define ATOM_BROWSER_UI_TRAY_ICON_H_
#include <string>
#include <vector>
#include "atom/browser/ui/tray_icon_observer.h"
#include "base/observer_list.h"
@@ -46,6 +47,8 @@ class TrayIcon {
const base::string16& title,
const base::string16& contents);
virtual void PopContextMenu(const gfx::Point& pos);
// Set the context menu for this icon.
virtual void SetContextMenu(ui::SimpleMenuModel* menu_model) = 0;
@@ -56,6 +59,8 @@ class TrayIcon {
void NotifyBalloonShow();
void NotifyBalloonClicked();
void NotifyBalloonClosed();
void NotifyRightClicked(const gfx::Rect& bounds = gfx::Rect());
void NotfiyDropFiles(const std::vector<std::string>& files);
protected:
TrayIcon();

View File

@@ -13,7 +13,7 @@
#include "base/mac/scoped_nsobject.h"
@class AtomMenuController;
@class StatusItemController;
@class StatusItemView;
namespace atom {
@@ -27,12 +27,12 @@ class TrayIconCocoa : public TrayIcon {
void SetToolTip(const std::string& tool_tip) override;
void SetTitle(const std::string& title) override;
void SetHighlightMode(bool highlight) override;
void PopContextMenu(const gfx::Point& pos) override;
void SetContextMenu(ui::SimpleMenuModel* menu_model) override;
private:
base::scoped_nsobject<NSStatusItem> item_;
base::scoped_nsobject<StatusItemController> controller_;
// Atom custom view for NSStatusItem.
base::scoped_nsobject<StatusItemView> status_item_view_;
// Status menu shown when right-clicking the system icon.
base::scoped_nsobject<AtomMenuController> menu_;

View File

@@ -9,81 +9,242 @@
#include "ui/gfx/image/image.h"
#include "ui/gfx/screen.h"
@interface StatusItemController : NSObject {
namespace {
const CGFloat kStatusItemLength = 26;
const CGFloat kMargin = 3;
} // namespace
@interface StatusItemView : NSView {
atom::TrayIconCocoa* trayIcon_; // weak
AtomMenuController* menuController_; // weak
BOOL isHighlightEnable_;
BOOL inMouseEventSequence_;
base::scoped_nsobject<NSImage> image_;
base::scoped_nsobject<NSImage> alternateImage_;
base::scoped_nsobject<NSString> title_;
base::scoped_nsobject<NSStatusItem> statusItem_;
}
- (id)initWithIcon:(atom::TrayIconCocoa*)icon;
- (void)handleClick:(id)sender;
- (void)handleDoubleClick:(id)sender;
@end // @interface StatusItemController
@end // @interface StatusItemView
@implementation StatusItemController
@implementation StatusItemView
- (id)initWithIcon:(atom::TrayIconCocoa*)icon {
trayIcon_ = icon;
isHighlightEnable_ = YES;
statusItem_.reset([[[NSStatusBar systemStatusBar] statusItemWithLength:
NSVariableStatusItemLength] retain]);
NSRect frame = NSMakeRect(0,
0,
kStatusItemLength,
[[statusItem_ statusBar] thickness]);
if ((self = [super initWithFrame:frame])) {
[self registerForDraggedTypes:
[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
[statusItem_ setView:self];
}
return self;
}
- (void)handleClick:(id)sender {
// Get the frame of the NSStatusItem.
NSRect frame = [NSApp currentEvent].window.frame;
- (void)removeItem {
[[NSStatusBar systemStatusBar] removeStatusItem:statusItem_];
statusItem_.reset();
}
- (void)drawRect:(NSRect)dirtyRect {
// Draw the tray icon and title that align with NSSStatusItem, layout:
// ----------------
// | icon | title |
/// ----------------
BOOL highlight = [self shouldHighlight];
CGFloat titleWidth = [self titleWidth];
// Calculate the total icon bounds.
NSRect statusItemBounds = NSMakeRect(0,
0,
kStatusItemLength + titleWidth,
[[statusItem_ statusBar] thickness]);
[statusItem_ drawStatusBarBackgroundInRect:statusItemBounds
withHighlight:highlight];
[statusItem_ setLength:titleWidth + kStatusItemLength];
if (title_) {
NSRect titleDrawRect = NSMakeRect(kStatusItemLength,
0,
titleWidth + kStatusItemLength,
[[statusItem_ statusBar] thickness]);
[title_ drawInRect:titleDrawRect
withAttributes:[self titleAttributes]];
}
NSRect iconRect = NSMakeRect(0,
0,
kStatusItemLength,
[[statusItem_ statusBar] thickness]);
if (highlight && alternateImage_) {
[alternateImage_ drawInRect:NSInsetRect(iconRect, kMargin, kMargin)
fromRect:NSZeroRect
operation:NSCompositeSourceOver
fraction:1];
} else {
[image_ drawInRect:NSInsetRect(iconRect, kMargin, kMargin)
fromRect:NSZeroRect
operation:NSCompositeSourceOver
fraction:1];
}
}
- (CGFloat)titleWidth {
if (!title_) return 0;
NSAttributedString* attributes =
[[NSAttributedString alloc] initWithString:title_
attributes:[self titleAttributes]];
return [attributes size].width;
}
- (NSDictionary*)titleAttributes {
NSFont* font = [NSFont menuBarFontOfSize:0];
NSColor* foregroundColor = [NSColor blackColor];
return [NSDictionary dictionaryWithObjectsAndKeys:
font, NSFontAttributeName,
foregroundColor, NSForegroundColorAttributeName,
nil];
}
- (void)setImage:(NSImage*)image {
image_.reset([image copy]);
[self setNeedsDisplay:YES];
}
- (void)setAlternateImage:(NSImage*)image {
alternateImage_.reset([image copy]);
}
- (void)setHighlight:(BOOL)highlight {
isHighlightEnable_ = highlight;
}
- (void)setTitle:(NSString*)title {
title_.reset([title copy]);
[self setNeedsDisplay:YES];
}
- (void)setMenuController:(AtomMenuController*)menu {
menuController_ = menu;
}
- (void)mouseDown:(NSEvent*)event {
inMouseEventSequence_ = YES;
[self setNeedsDisplay:YES];
}
- (void)mouseUp:(NSEvent*)event {
if (!inMouseEventSequence_) {
// If the menu is showing, when user clicked the tray icon, the `mouseDown`
// event will be dissmissed, we need to close the menu at this time.
[self setNeedsDisplay:YES];
return;
}
inMouseEventSequence_ = NO;
if (event.clickCount == 1) {
if (menuController_) {
[statusItem_ popUpStatusItemMenu:[menuController_ menu]];
}
trayIcon_->NotifyClicked([self getBoundsFromEvent:event]);
}
if (event.clickCount == 2 && !menuController_) {
trayIcon_->NotifyDoubleClicked();
}
[self setNeedsDisplay:YES];
}
- (void)popContextMenu {
if (menuController_ && ![menuController_ isMenuOpen]) {
// redraw the dray icon to show highlight if it is enabled.
[self setNeedsDisplay:YES];
[statusItem_ popUpStatusItemMenu:[menuController_ menu]];
// The popUpStatusItemMenu returns only after the showing menu is closed.
// When it returns, we need to redraw the tray icon to not show highlight.
[self setNeedsDisplay:YES];
}
}
- (void)rightMouseUp:(NSEvent*)event {
trayIcon_->NotifyRightClicked([self getBoundsFromEvent:event]);
}
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender {
return NSDragOperationCopy;
}
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender {
NSPasteboard* pboard = [sender draggingPasteboard];
if ([[pboard types] containsObject:NSFilenamesPboardType]) {
std::vector<std::string> dropFiles;
NSArray* files = [pboard propertyListForType:NSFilenamesPboardType];
for (NSString* file in files)
dropFiles.push_back(base::SysNSStringToUTF8(file));
trayIcon_->NotfiyDropFiles(dropFiles);
return YES;
}
return NO;
}
- (BOOL)shouldHighlight {
BOOL is_menu_open = [menuController_ isMenuOpen];
return isHighlightEnable_ && (inMouseEventSequence_ || is_menu_open);
}
- (gfx::Rect)getBoundsFromEvent:(NSEvent*)event {
NSRect frame = event.window.frame;
gfx::Rect bounds(frame.origin.x, 0, NSWidth(frame), NSHeight(frame));
// Flip coordinates to gfx (0,0 in top-left corner) using current screen.
NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
bounds.set_y(NSHeight([screen frame]) - NSMaxY(frame));
trayIcon_->NotifyClicked(bounds);
return bounds;
}
- (void)handleDoubleClick:(id)sender {
trayIcon_->NotifyDoubleClicked();
}
@end
namespace atom {
TrayIconCocoa::TrayIconCocoa() {
controller_.reset([[StatusItemController alloc] initWithIcon:this]);
item_.reset([[[NSStatusBar systemStatusBar]
statusItemWithLength:NSVariableStatusItemLength] retain]);
[item_ setEnabled:YES];
[item_ setTarget:controller_];
[item_ setAction:@selector(handleClick:)];
[item_ setDoubleAction:@selector(handleDoubleClick:)];
[item_ setHighlightMode:YES];
status_item_view_.reset([[StatusItemView alloc] initWithIcon:this]);
}
TrayIconCocoa::~TrayIconCocoa() {
// Remove the status item from the status bar.
[[NSStatusBar systemStatusBar] removeStatusItem:item_];
[status_item_view_ removeItem];
}
void TrayIconCocoa::SetImage(const gfx::Image& image) {
[item_ setImage:image.AsNSImage()];
[status_item_view_ setImage:image.AsNSImage()];
}
void TrayIconCocoa::SetPressedImage(const gfx::Image& image) {
[item_ setAlternateImage:image.AsNSImage()];
[status_item_view_ setAlternateImage:image.AsNSImage()];
}
void TrayIconCocoa::SetToolTip(const std::string& tool_tip) {
[item_ setToolTip:base::SysUTF8ToNSString(tool_tip)];
[status_item_view_ setToolTip:base::SysUTF8ToNSString(tool_tip)];
}
void TrayIconCocoa::SetTitle(const std::string& title) {
[item_ setTitle:base::SysUTF8ToNSString(title)];
[status_item_view_ setTitle:base::SysUTF8ToNSString(title)];
}
void TrayIconCocoa::SetHighlightMode(bool highlight) {
[item_ setHighlightMode:highlight];
[status_item_view_ setHighlight:highlight];
}
void TrayIconCocoa::PopContextMenu(const gfx::Point& pos) {
[status_item_view_ popContextMenu];
}
void TrayIconCocoa::SetContextMenu(ui::SimpleMenuModel* menu_model) {
menu_.reset([[AtomMenuController alloc] initWithModel:menu_model]);
[item_ setMenu:[menu_ menu]];
[status_item_view_ setMenuController:menu_.get()];
}
// static

View File

@@ -5,6 +5,9 @@
#ifndef ATOM_BROWSER_UI_TRAY_ICON_OBSERVER_H_
#define ATOM_BROWSER_UI_TRAY_ICON_OBSERVER_H_
#include <string>
#include <vector>
namespace gfx {
class Rect;
}
@@ -13,11 +16,13 @@ namespace atom {
class TrayIconObserver {
public:
virtual void OnClicked(const gfx::Rect&) {}
virtual void OnClicked(const gfx::Rect& bounds) {}
virtual void OnDoubleClicked() {}
virtual void OnBalloonShow() {}
virtual void OnBalloonClicked() {}
virtual void OnBalloonClosed() {}
virtual void OnRightClicked(const gfx::Rect& bounds) {}
virtual void OnDropFiles(const std::vector<std::string>& files) {}
protected:
virtual ~TrayIconObserver() {}

View File

@@ -0,0 +1,35 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/ui/views/native_frame_view.h"
#include "atom/browser/native_window_views.h"
namespace atom {
namespace {
const char kViewClassName[] = "AtomNativeFrameView";
} // namespace
NativeFrameView::NativeFrameView(NativeWindowViews* window,
views::Widget* widget)
: views::NativeFrameView(widget),
window_(window) {
}
gfx::Size NativeFrameView::GetMinimumSize() const {
return window_->GetMinimumSize();
}
gfx::Size NativeFrameView::GetMaximumSize() const {
return window_->GetMaximumSize();
}
const char* NativeFrameView::GetClassName() const {
return kViewClassName;
}
} // namespace atom

View File

@@ -0,0 +1,34 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_UI_VIEWS_NATIVE_FRAME_VIEW_H_
#define ATOM_BROWSER_UI_VIEWS_NATIVE_FRAME_VIEW_H_
#include "ui/views/window/native_frame_view.h"
namespace atom {
class NativeWindowViews;
// Like the views::NativeFrameView, but returns the min/max size from the
// NativeWindowViews.
class NativeFrameView : public views::NativeFrameView {
public:
NativeFrameView(NativeWindowViews* window, views::Widget* widget);
protected:
// views::View:
gfx::Size GetMinimumSize() const override;
gfx::Size GetMaximumSize() const override;
const char* GetClassName() const override;
private:
NativeWindowViews* window_; // weak ref.
DISALLOW_COPY_AND_ASSIGN(NativeFrameView);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_VIEWS_NATIVE_FRAME_VIEW_H_

View File

@@ -47,38 +47,22 @@ NotifyIcon::~NotifyIcon() {
void NotifyIcon::HandleClickEvent(const gfx::Point& cursor_pos,
bool left_mouse_click) {
NOTIFYICONIDENTIFIER icon_id;
memset(&icon_id, 0, sizeof(NOTIFYICONIDENTIFIER));
icon_id.uID = icon_id_;
icon_id.hWnd = window_;
icon_id.cbSize = sizeof(NOTIFYICONIDENTIFIER);
RECT rect = { 0 };
Shell_NotifyIconGetRect(&icon_id, &rect);
// Pass to the observer if appropriate.
if (left_mouse_click) {
NOTIFYICONIDENTIFIER icon_id;
memset(&icon_id, 0, sizeof(NOTIFYICONIDENTIFIER));
icon_id.uID = icon_id_;
icon_id.hWnd = window_;
icon_id.cbSize = sizeof(NOTIFYICONIDENTIFIER);
RECT rect = { 0 };
Shell_NotifyIconGetRect(&icon_id, &rect);
NotifyClicked(gfx::Rect(rect));
return;
}
if (!menu_model_)
return;
// Set our window as the foreground window, so the context menu closes when
// we click away from it.
if (!SetForegroundWindow(window_))
return;
views::MenuRunner menu_runner(
menu_model_,
views::MenuRunner::CONTEXT_MENU | views::MenuRunner::HAS_MNEMONICS);
ignore_result(menu_runner.RunMenuAt(
NULL,
NULL,
gfx::Rect(cursor_pos, gfx::Size()),
views::MENU_ANCHOR_TOPLEFT,
ui::MENU_SOURCE_MOUSE));
NotifyRightClicked(gfx::Rect(rect));
PopContextMenu(cursor_pos);
}
void NotifyIcon::ResetIcon() {
@@ -151,6 +135,23 @@ void NotifyIcon::DisplayBalloon(const gfx::Image& icon,
LOG(WARNING) << "Unable to create status tray balloon.";
}
void NotifyIcon::PopContextMenu(const gfx::Point& pos) {
// Set our window as the foreground window, so the context menu closes when
// we click away from it.
if (!SetForegroundWindow(window_))
return;
views::MenuRunner menu_runner(
menu_model_,
views::MenuRunner::CONTEXT_MENU | views::MenuRunner::HAS_MNEMONICS);
ignore_result(menu_runner.RunMenuAt(
NULL,
NULL,
gfx::Rect(pos, gfx::Size()),
views::MENU_ANCHOR_TOPLEFT,
ui::MENU_SOURCE_MOUSE));
}
void NotifyIcon::SetContextMenu(ui::SimpleMenuModel* menu_model) {
menu_model_ = menu_model;
}

View File

@@ -49,6 +49,7 @@ class NotifyIcon : public TrayIcon {
void DisplayBalloon(const gfx::Image& icon,
const base::string16& title,
const base::string16& contents) override;
void PopContextMenu(const gfx::Point& pos) override;
void SetContextMenu(ui::SimpleMenuModel* menu_model) override;
private:

View File

@@ -4,17 +4,66 @@
#include "atom/browser/web_dialog_helper.h"
#include <string>
#include <vector>
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/native_window.h"
#include "atom/browser/ui/file_dialog.h"
#include "base/bind.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/prefs/pref_service.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/file_chooser_file_info.h"
#include "net/base/mime_util.h"
#include "ui/shell_dialogs/selected_file_info.h"
namespace {
const char kSelectFileLastDirectory[] = "selectfile.last_directory";
file_dialog::Filters GetFileTypesFromAcceptType(
const std::vector<base::string16>& accept_types) {
file_dialog::Filters filters;
if (accept_types.empty())
return filters;
std::vector<base::FilePath::StringType> extensions;
for (const auto& accept_type : accept_types) {
std::string ascii_type = base::UTF16ToASCII(accept_type);
if (ascii_type[0] == '.') {
// If the type starts with a period it is assumed to be a file extension,
// like `.txt`, // so we just have to add it to the list.
base::FilePath::StringType extension(
ascii_type.begin(), ascii_type.end());
// Skip the first character.
extensions.push_back(extension.substr(1));
} else {
if (ascii_type == "image/*" || ascii_type == "audio/*" ||
ascii_type == "video/*") {
// For MIME Type
net::GetExtensionsForMimeType(ascii_type, &extensions);
}
}
}
filters.push_back(file_dialog::Filter());
for (const auto& extension : extensions) {
#if defined(OS_WIN)
filters[0].second.push_back(base::UTF16ToASCII(extension));
#else
filters[0].second.push_back(extension);
#endif
}
return filters;
}
} // namespace
namespace atom {
WebDialogHelper::WebDialogHelper(NativeWindow* window)
@@ -25,15 +74,18 @@ WebDialogHelper::WebDialogHelper(NativeWindow* window)
WebDialogHelper::~WebDialogHelper() {
}
void WebDialogHelper::RunFileChooser(content::WebContents* web_contents,
const content::FileChooserParams& params) {
std::vector<content::FileChooserFileInfo> result;
file_dialog::Filters filters = GetFileTypesFromAcceptType(
params.accept_types);
if (params.mode == content::FileChooserParams::Save) {
base::FilePath path;
if (file_dialog::ShowSaveDialog(window_,
base::UTF16ToUTF8(params.title),
params.default_file_name,
file_dialog::Filters(),
filters,
&path)) {
content::FileChooserFileInfo info;
info.file_path = path;
@@ -56,10 +108,14 @@ void WebDialogHelper::RunFileChooser(content::WebContents* web_contents,
}
std::vector<base::FilePath> paths;
AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>(
window_->web_contents()->GetBrowserContext());
base::FilePath default_file_path = browser_context->prefs()->GetFilePath(
kSelectFileLastDirectory).Append(params.default_file_name);
if (file_dialog::ShowOpenDialog(window_,
base::UTF16ToUTF8(params.title),
params.default_file_name,
file_dialog::Filters(),
default_file_path,
filters,
flags,
&paths)) {
for (auto& path : paths) {
@@ -68,6 +124,10 @@ void WebDialogHelper::RunFileChooser(content::WebContents* web_contents,
info.display_name = path.BaseName().value();
result.push_back(info);
}
if (!paths.empty()) {
browser_context->prefs()->SetFilePath(kSelectFileLastDirectory,
paths[0].DirName());
}
}
}

View File

@@ -7,6 +7,7 @@
#include "atom/common/native_mate_converters/image_converter.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "base/strings/utf_string_conversions.h"
#include "native_mate/arguments.h"
#include "native_mate/dictionary.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -50,9 +51,35 @@ std::string Read(const std::string& format_string,
return data;
}
void Write(const mate::Dictionary& data,
mate::Arguments* args) {
ui::ScopedClipboardWriter writer(GetClipboardType(args));
base::string16 text, html;
gfx::Image image;
if (data.Get("text", &text))
writer.WriteText(text);
if (data.Get("html", &html))
writer.WriteHTML(html, std::string());
if (data.Get("image", &image))
writer.WriteImage(image.AsBitmap());
}
base::string16 ReadText(mate::Arguments* args) {
base::string16 data;
ui::Clipboard::GetForCurrentThread()->ReadText(GetClipboardType(args), &data);
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
auto type = GetClipboardType(args);
if (clipboard->IsFormatAvailable(
ui::Clipboard::GetPlainTextWFormatType(), type)) {
clipboard->ReadText(type, &data);
} else if (clipboard->IsFormatAvailable(
ui::Clipboard::GetPlainTextFormatType(), type)) {
std::string result;
clipboard->ReadAsciiText(type, &result);
data = base::ASCIIToUTF16(result);
}
return data;
}
@@ -99,6 +126,7 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
dict.SetMethod("availableFormats", &AvailableFormats);
dict.SetMethod("has", &Has);
dict.SetMethod("read", &Read);
dict.SetMethod("write", &Write);
dict.SetMethod("readText", &ReadText);
dict.SetMethod("writeText", &WriteText);
dict.SetMethod("readHtml", &ReadHtml);

View File

@@ -54,6 +54,11 @@ bool GetChildNode(const base::DictionaryValue* root,
const std::string& name,
const base::DictionaryValue* dir,
const base::DictionaryValue** out) {
if (name == "") {
*out = root;
return true;
}
const base::DictionaryValue* files = NULL;
return GetFilesNode(root, dir, &files) &&
files->GetDictionaryWithoutPathExpansion(name, out);

View File

@@ -6,8 +6,8 @@
#define ATOM_VERSION_H
#define ATOM_MAJOR_VERSION 0
#define ATOM_MINOR_VERSION 29
#define ATOM_PATCH_VERSION 0
#define ATOM_MINOR_VERSION 30
#define ATOM_PATCH_VERSION 1
#define ATOM_VERSION_IS_RELEASE 1

View File

@@ -4,6 +4,8 @@
#include "atom/common/event_emitter_caller.h"
#include "atom/common/node_includes.h"
namespace mate {
namespace internal {
@@ -11,21 +13,8 @@ namespace internal {
v8::Local<v8::Value> CallEmitWithArgs(v8::Isolate* isolate,
v8::Local<v8::Object> obj,
ValueVector* args) {
v8::Local<v8::String> emit_name = StringToSymbol(isolate, "emit");
v8::Local<v8::Value> emit = obj->Get(emit_name);
if (emit.IsEmpty() || !emit->IsFunction()) {
isolate->ThrowException(v8::Exception::TypeError(
StringToV8(isolate, "\"emit\" is not a function")));
return v8::Undefined(isolate);
}
v8::MaybeLocal<v8::Value> result = emit.As<v8::Function>()->Call(
isolate->GetCurrentContext(), obj, args->size(), &args->front());
if (result.IsEmpty()) {
return v8::Undefined(isolate);
}
return result.ToLocalChecked();
return node::MakeCallback(
isolate, obj, "emit", args->size(), &args->front());
}
} // namespace internal

View File

@@ -107,6 +107,9 @@ const char kDisableHttpCache[] = "disable-http-cache";
// Register schemes to standard.
const char kRegisterStandardSchemes[] = "register-standard-schemes";
// The browser process app model ID
const char kAppUserModelId[] = "app-user-model-id";
} // namespace switches
} // namespace atom

View File

@@ -58,6 +58,8 @@ extern const char kPageVisibility[];
extern const char kDisableHttpCache[];
extern const char kRegisterStandardSchemes[];
extern const char kAppUserModelId[];
} // namespace switches
} // namespace atom

View File

@@ -27,6 +27,10 @@
#include "atom/common/node_includes.h"
#if defined(OS_WIN)
#include <shlobj.h>
#endif
namespace atom {
namespace {
@@ -102,6 +106,15 @@ void AtomRendererClient::WebKitInitialized() {
void AtomRendererClient::RenderThreadStarted() {
content::RenderThread::Get()->AddObserver(this);
#if defined(OS_WIN)
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
base::string16 app_id =
command_line->GetSwitchValueNative(switches::kAppUserModelId);
if (!app_id.empty()) {
SetCurrentProcessExplicitAppUserModelID(app_id.c_str());
}
#endif
}
void AtomRendererClient::RenderFrameCreated(

View File

@@ -77,7 +77,7 @@ if nodeIntegration in ['true', 'all', 'except-iframe', 'manual-enable-iframe']
global.__dirname = __dirname
# Redirect window.onerror to uncaughtException.
window.onerror = (error) ->
window.onerror = (message, filename, lineno, colno, error) ->
if global.process.listeners('uncaughtException').length > 0
global.process.emit 'uncaughtException', error
true
@@ -93,6 +93,7 @@ else
delete global.process
delete global.setImmediate
delete global.clearImmediate
delete global.global
# Load the script specfied by the "preload" attribute.
if preloadScript

View File

@@ -2,6 +2,12 @@ process = global.process
ipc = require 'ipc'
remote = require 'remote'
# Helper function to resolve relative url.
a = window.top.document.createElement 'a'
resolveUrl = (url) ->
a.href = url
a.href
# Window object returned by "window.open".
class BrowserWindowProxy
constructor: (@guestId) ->
@@ -49,8 +55,17 @@ window.open = (url, frameName='', features='') ->
options.width ?= 800
options.height ?= 600
# Resolve relative urls.
url = resolveUrl url
(options[name] = parseInt(options[name], 10) if options[name]?) for name in ints
# Inherit the node-integration option of current window.
unless options['node-integration']
for arg in process.argv when arg.indexOf('--node-integration=') is 0
options['node-integration'] = arg.substr(-4) is 'true'
break
guestId = ipc.sendSync 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', url, frameName, options
if guestId
new BrowserWindowProxy(guestId)

View File

@@ -269,6 +269,7 @@ registerWebViewElement = ->
"goToOffset"
"isCrashed"
"setUserAgent"
"getUserAgent"
"executeJavaScript"
"insertCSS"
"openDevTools"

View File

@@ -18,7 +18,7 @@
* [개요](api/synopsis-ko.md)
* [프로세스 객체](api/process-ko.md)
* [크롬 Command-Line 스위치에 대한 지원](api/chrome-command-line-switches-ko.md)
* [크롬 Command-Line 스위치 지원](api/chrome-command-line-switches-ko.md)
커스텀 DOM Element:
@@ -38,6 +38,7 @@
* [menu](api/menu-ko.md)
* [menu-item](api/menu-item-ko.md)
* [power-monitor](api/power-monitor-ko.md)
* [power-save-blocker](api/power-save-blocker-ko.md)
* [protocol](api/protocol-ko.md)
* [tray](api/tray-ko.md)
@@ -58,12 +59,10 @@
## 개발자용
* [코딩 스타일](development/coding-style-ko.md)
* [소스코드 구조](development/source-code-directory-structure-ko.md)
* [소스 코드 디렉터리 구조](development/source-code-directory-structure-ko.md)
* [NW.js와 기술적으로 다른점 (이전 node-webkit)](development/atom-shell-vs-node-webkit-ko.md)
* [빌드 시스템 개요](development/build-system-overview-ko.md)
* [빌드 설명서 (Mac)](development/build-instructions-mac-ko.md)
* [빌드 설명서 (Windows)](development/build-instructions-windows-ko.md)
* [빌드 설명서 (Linux)](development/build-instructions-linux-ko.md)
* [디버거에서 디버그 심볼 서버 설정](development/setting-up-symbol-server-ko.md)
이 문서는 (@preco21)[https://github.com/preco21]이 번역하였습니다.

View File

@@ -38,6 +38,7 @@ Modules for the main process:
* [menu](api/menu.md)
* [menu-item](api/menu-item.md)
* [power-monitor](api/power-monitor.md)
* [power-save-blocker](api/power-save-blocker.md)
* [protocol](api/protocol.md)
* [tray](api/tray.md)

View File

@@ -1,4 +1,4 @@
# Accelerator
# Accelerator
Accelerator는 키보드 단축키를 표현하는 문자열입니다, 여러 혼합키와 키코드를 `+` 문자를
이용하여 결합할 수 있습니다.

317
docs/api/app-ko.md Normal file
View File

@@ -0,0 +1,317 @@
# app
The `app` module is responsible for controlling the application's life time.
The example of quitting the whole application when the last window is closed:
```javascript
var app = require('app');
app.on('window-all-closed', function() {
app.quit();
});
```
## Event: will-finish-launching
Emitted when application has done basic startup. On Windows and Linux it is the
same with `ready` event, on OS X this event represents the
`applicationWillFinishLaunching` message of `NSApplication`, usually you would
setup listeners to `open-file` and `open-url` events here, and start the crash
reporter and auto updater.
Under most cases you should just do everything in `ready` event.
## Event: ready
Emitted when Electron has done everything initialization.
## Event: window-all-closed
Emitted when all windows have been closed.
This event is only emitted when the application is not going to quit. If a
user pressed `Cmd + Q`, or the developer called `app.quit()`, Electron would
first try to close all windows and then emit the `will-quit` event, and in
this case the `window-all-closed` would not be emitted.
## Event: before-quit
* `event` Event
Emitted before the application starts closing its windows.
Calling `event.preventDefault()` will prevent the default behaviour, which is
terminating the application.
## Event: will-quit
* `event` Event
Emitted when all windows have been closed and the application will quit.
Calling `event.preventDefault()` will prevent the default behaviour, which is
terminating the application.
See description of `window-all-closed` for the differences between `will-quit`
and it.
## Event: quit
Emitted when application is quitting.
## Event: open-file
* `event` Event
* `path` String
Emitted when user wants to open a file with the application, it usually happens
when the application is already opened and then OS wants to reuse the
application to open file. But it is also emitted when a file is dropped onto the
dock and the application is not yet running. Make sure to listen to open-file
very early in your application startup to handle this case (even before the
`ready` event is emitted).
You should call `event.preventDefault()` if you want to handle this event.
## Event: open-url
* `event` Event
* `url` String
Emitted when user wants to open a URL with the application, this URL scheme
must be registered to be opened by your application.
You should call `event.preventDefault()` if you want to handle this event.
## Event: activate-with-no-open-windows
Emitted when the application is activated while there is no opened windows. It
usually happens when user has closed all of application's windows and then
click on the application's dock icon.
## Event: browser-window-blur
* `event` Event
* `window` BrowserWindow
Emitted when a [browserWindow](browser-window-ko.md) gets blurred.
## Event: browser-window-focus
* `event` Event
* `window` BrowserWindow
Emitted when a [browserWindow](browser-window-ko.md) gets focused.
### Event: 'select-certificate'
Emitted when client certificate is requested.
* `event` Event
* `webContents` [WebContents](browser-window-ko.md#class-webcontents)
* `url` String
* `certificateList` [Objects]
* `data` PEM encoded data
* `issuerName` Issuer's Common Name
* `callback` Function
```
app.on('select-certificate', function(event, host, url, list, callback) {
event.preventDefault();
callback(list[0]);
})
```
`url` corresponds to the navigation entry requesting the client certificate,
`callback` needs to be called with an entry filtered from the list.
`event.preventDefault()` prevents from using the first certificate from
the store.
### Event: 'gpu-process-crashed'
Emitted when the gpu process is crashed.
## app.quit()
Try to close all windows. The `before-quit` event will first be emitted. If all
windows are successfully closed, the `will-quit` event will be emitted and by
default the application would be terminated.
This method guarantees all `beforeunload` and `unload` handlers are correctly
executed. It is possible that a window cancels the quitting by returning
`false` in `beforeunload` handler.
## app.getPath(name)
* `name` String
Retrieves a path to a special directory or file associated with `name`. On
failure an `Error` would throw.
You can request following paths by the names:
* `home`: User's home directory
* `appData`: Per-user application data directory, by default it is pointed to:
* `%APPDATA%` on Windows
* `$XDG_CONFIG_HOME` or `~/.config` on Linux
* `~/Library/Application Support` on OS X
* `userData`: The directory for storing your app's configuration files, by
default it is the `appData` directory appended with your app's name
* `cache`: Per-user application cache directory, by default it is pointed to:
* `%APPDATA%` on Window, which doesn't has a universal place for cache
* `$XDG_CACHE_HOME` or `~/.cache` on Linux
* `~/Library/Caches` on OS X
* `userCache`: The directory for placing your app's caches, by default it is the
`cache` directory appended with your app's name
* `temp`: Temporary directory
* `userDesktop`: The current user's Desktop directory
* `exe`: The current executable file
* `module`: The `libchromiumcontent` library
## app.setPath(name, path)
* `name` String
* `path` String
Overrides the `path` to a special directory or file associated with `name`. if
the path specifies a directory that does not exist, the directory will be
created by this method. On failure an `Error` would throw.
You can only override paths of `name`s defined in `app.getPath`.
By default web pages' cookies and caches will be stored under `userData`
directory, if you want to change this location, you have to override the
`userData` path before the `ready` event of `app` module gets emitted.
## app.getVersion()
Returns the version of loaded application, if no version is found in
application's `package.json`, the version of current bundle or executable would
be returned.
## app.getName()
Returns current application's name, the name in `package.json` would be
used.
Usually the `name` field of `package.json` is a short lowercased name, according
to the spec of npm modules. So usually you should also specify a `productName`
field, which is your application's full capitalized name, and it will be
preferred over `name` by Electron.
## app.resolveProxy(url, callback)
* `url` URL
* `callback` Function
Resolves the proxy information for `url`, the `callback` would be called with
`callback(proxy)` when the request is done.
## app.addRecentDocument(path)
* `path` String
Adds `path` to recent documents list.
This list is managed by the system, on Windows you can visit the list from task
bar, and on Mac you can visit it from dock menu.
## app.clearRecentDocuments()
Clears the recent documents list.
## app.setUserTasks(tasks)
* `tasks` Array - Array of `Task` objects
Adds `tasks` to the [Tasks][tasks] category of JumpList on Windows.
The `tasks` is an array of `Task` objects in following format:
* `Task` Object
* `program` String - Path of the program to execute, usually you should
specify `process.execPath` which opens current program
* `arguments` String - The arguments of command line when `program` is
executed
* `title` String - The string to be displayed in a JumpList
* `description` String - Description of this task
* `iconPath` String - The absolute path to an icon to be displayed in a
JumpList, it can be arbitrary resource file that contains an icon, usually
you can specify `process.execPath` to show the icon of the program
* `iconIndex` Integer - The icon index in the icon file. If an icon file
consists of two or more icons, set this value to identify the icon. If an
icon file consists of one icon, this value is 0
**Note:** This API is only available on 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.
## app.commandLine.appendArgument(value)
Append an argument to Chromium's command line. The argument will quoted properly.
**Note:** This will not affect `process.argv`.
## app.dock.bounce([type])
* `type` String - Can be `critical` or `informational`, the default is
`informational`
When `critical` is passed, the dock icon will bounce until either the
application becomes active or the request is canceled.
When `informational` is passed, the dock icon will bounce for one second. The
request, though, remains active until either the application becomes active or
the request is canceled.
An ID representing the request would be returned.
**Note:** This API is only available on Mac.
## app.dock.cancelBounce(id)
* `id` Integer
Cancel the bounce of `id`.
**Note:** This API is only available on Mac.
## app.dock.setBadge(text)
* `text` String
Sets the string to be displayed in the docks badging area.
**Note:** This API is only available on Mac.
## app.dock.getBadge()
Returns the badge string of the dock.
**Note:** This API is only available on Mac.
## app.dock.hide()
Hides the dock icon.
**Note:** This API is only available on Mac.
## app.dock.show()
Shows the dock icon.
**Note:** This API is only available on Mac.
## app.dock.setMenu(menu)
* `menu` Menu
Sets the application [dock menu][dock-menu].
**Note:** This API is only available on Mac.
[dock-menu]:https://developer.apple.com/library/mac/documentation/Carbon/Conceptual/customizing_docktile/concepts/dockconcepts.html#//apple_ref/doc/uid/TP30000986-CH2-TPXREF103
[tasks]:http://msdn.microsoft.com/en-us/library/windows/desktop/dd378460(v=vs.85).aspx#tasks

View File

@@ -1,8 +1,8 @@
# app
The `app` module is responsible for controlling the application's life time.
The `app` module is responsible for controlling the application's lifecycle.
The example of quitting the whole application when the last window is closed:
The following example shows how to quit the application when the last window is closed:
```javascript
var app = require('app');
@@ -13,26 +13,26 @@ app.on('window-all-closed', function() {
## Event: will-finish-launching
Emitted when application has done basic startup. On Windows and Linux it is the
same with `ready` event, on OS X this event represents the
`applicationWillFinishLaunching` message of `NSApplication`, usually you would
setup listeners to `open-file` and `open-url` events here, and start the crash
reporter and auto updater.
Emitted when the application has finished basic startup. On Windows and Linux,
the `will-finish-launching` event is the same as the `ready` event; on OS X,
this event represents the `applicationWillFinishLaunching` notification of `NSApplication`.
You would usually set up listeners for the `open-file` and `open-url` events here,
and start the crash reporter and auto updater.
Under most cases you should just do everything in `ready` event.
In most cases, you should just do everything in the `ready` event handler.
## Event: ready
Emitted when Electron has done everything initialization.
Emitted when Electron has finsished initialization.
## Event: window-all-closed
Emitted when all windows have been closed.
This event is only emitted when the application is not going to quit. If a
This event is only emitted when the application is not going to quit. If the
user pressed `Cmd + Q`, or the developer called `app.quit()`, Electron would
first try to close all windows and then emit the `will-quit` event, and in
this case the `window-all-closed` would not be emitted.
first try to close all the windows and then emit the `will-quit` event, and in
this case the `window-all-closed` event would not be emitted.
## Event: before-quit
@@ -50,23 +50,23 @@ Emitted when all windows have been closed and the application will quit.
Calling `event.preventDefault()` will prevent the default behaviour, which is
terminating the application.
See description of `window-all-closed` for the differences between `will-quit`
and it.
See the description of the `window-all-closed` event for the differences between the `will-quit`
and `window-all-closed` events.
## Event: quit
Emitted when application is quitting.
Emitted when the application is quitting.
## Event: open-file
* `event` Event
* `path` String
Emitted when user wants to open a file with the application, it usually happens
when the application is already opened and then OS wants to reuse the
application to open file. But it is also emitted when a file is dropped onto the
dock and the application is not yet running. Make sure to listen to open-file
very early in your application startup to handle this case (even before the
Emitted when the user wants to open a file with the application. The `open-file` event
is usually emitted when the application is already open and the OS wants to reuse the
application to open the file. `open-file` is also emitted when a file is dropped onto the
dock and the application is not yet running. Make sure to listen for the `open-file`
event very early in your application startup to handle this case (even before the
`ready` event is emitted).
You should call `event.preventDefault()` if you want to handle this event.
@@ -76,16 +76,16 @@ You should call `event.preventDefault()` if you want to handle this event.
* `event` Event
* `url` String
Emitted when user wants to open a URL with the application, this URL scheme
Emitted when the user wants to open a URL with the application. The URL scheme
must be registered to be opened by your application.
You should call `event.preventDefault()` if you want to handle this event.
## Event: activate-with-no-open-windows
Emitted when the application is activated while there is no opened windows. It
usually happens when user has closed all of application's windows and then
click on the application's dock icon.
Emitted when the application is activated while there are no open windows, which
usually happens when the user has closed all of the application's windows and then
clicks on the application's dock icon.
## Event: browser-window-blur
@@ -103,7 +103,7 @@ Emitted when a [browserWindow](browser-window.md) gets focused.
### Event: 'select-certificate'
Emitted when client certificate is requested.
Emitted when a client certificate is requested.
* `event` Event
* `webContents` [WebContents](browser-window.md#class-webcontents)
@@ -120,43 +120,47 @@ app.on('select-certificate', function(event, host, url, list, callback) {
})
```
`url` corresponds to the navigation entry requesting the client certificate,
`url` corresponds to the navigation entry requesting the client certificate.
`callback` needs to be called with an entry filtered from the list.
`event.preventDefault()` prevents from using the first certificate from
the store.
`event.preventDefault()` prevents the application from using the first certificate
from the store.
### Event: 'gpu-process-crashed'
Emitted when the gpu process is crashed.
Emitted when the gpu process crashes.
## app.quit()
Try to close all windows. The `before-quit` event will first be emitted. If all
windows are successfully closed, the `will-quit` event will be emitted and by
default the application would be terminated.
default the application will terminate.
This method guarantees all `beforeunload` and `unload` handlers are correctly
This method guarantees that all `beforeunload` and `unload` event handlers are correctly
executed. It is possible that a window cancels the quitting by returning
`false` in `beforeunload` handler.
`false` in the `beforeunload` event handler.
## app.getAppPath()
Returns the current application directory.
## app.getPath(name)
* `name` String
Retrieves a path to a special directory or file associated with `name`. On
failure an `Error` would throw.
failure an `Error` is thrown.
You can request following paths by the names:
You can request the following paths by the name:
* `home`: User's home directory
* `appData`: Per-user application data directory, by default it is pointed to:
* `appData`: Per-user application data directory, which by default points to:
* `%APPDATA%` on Windows
* `$XDG_CONFIG_HOME` or `~/.config` on Linux
* `~/Library/Application Support` on OS X
* `userData`: The directory for storing your app's configuration files, by
* `userData`: The directory for storing your app's configuration files, which by
default it is the `appData` directory appended with your app's name
* `cache`: Per-user application cache directory, by default it is pointed to:
* `%APPDATA%` on Window, which doesn't has a universal place for cache
* `cache`: Per-user application cache directory, which by default points to:
* `%APPDATA%` on Windows (which doesn't have a universal cache location)
* `$XDG_CACHE_HOME` or `~/.cache` on Linux
* `~/Library/Caches` on OS X
* `userCache`: The directory for placing your app's caches, by default it is the
@@ -171,30 +175,30 @@ You can request following paths by the names:
* `name` String
* `path` String
Overrides the `path` to a special directory or file associated with `name`. if
Overrides the `path` to a special directory or file associated with `name`. If
the path specifies a directory that does not exist, the directory will be
created by this method. On failure an `Error` would throw.
created by this method. On failure an `Error` is thrown.
You can only override paths of `name`s defined in `app.getPath`.
By default web pages' cookies and caches will be stored under `userData`
directory, if you want to change this location, you have to override the
`userData` path before the `ready` event of `app` module gets emitted.
By default, web pages' cookies and caches will be stored under the `userData`
directory. If you want to change this location, you have to override the
`userData` path before the `ready` event of the `app` module is emitted.
## app.getVersion()
Returns the version of loaded application, if no version is found in
application's `package.json`, the version of current bundle or executable would
be returned.
Returns the version of the loaded application. If no version is found in the
application's `package.json` file, the version of the current bundle or executable is
returned.
## app.getName()
Returns current application's name, the name in `package.json` would be
used.
Returns the current application's name, which is the name in the application's
`package.json` file.
Usually the `name` field of `package.json` is a short lowercased name, according
to the spec of npm modules. So usually you should also specify a `productName`
field, which is your application's full capitalized name, and it will be
to the npm modules spec. You should usually also specify a `productName`
field, which is your application's full capitalized name, and which will be
preferred over `name` by Electron.
## app.resolveProxy(url, callback)
@@ -202,17 +206,17 @@ preferred over `name` by Electron.
* `url` URL
* `callback` Function
Resolves the proxy information for `url`, the `callback` would be called with
`callback(proxy)` when the request is done.
Resolves the proxy information for `url`. The `callback` will be called with
`callback(proxy)` when the request is performed.
## app.addRecentDocument(path)
* `path` String
Adds `path` to recent documents list.
Adds `path` to the recent documents list.
This list is managed by the system, on Windows you can visit the list from task
bar, and on Mac you can visit it from dock menu.
This list is managed by the OS. On Windows you can visit the list from the task
bar, and on OS X you can visit it from dock menu.
## app.clearRecentDocuments()
@@ -222,20 +226,20 @@ Clears the recent documents list.
* `tasks` Array - Array of `Task` objects
Adds `tasks` to the [Tasks][tasks] category of JumpList on Windows.
Adds `tasks` to the [Tasks][tasks] category of the JumpList on Windows.
The `tasks` is an array of `Task` objects in following format:
`tasks` is an array of `Task` objects in following format:
* `Task` Object
* `program` String - Path of the program to execute, usually you should
specify `process.execPath` which opens current program
* `arguments` String - The arguments of command line when `program` is
specify `process.execPath` which opens the current program
* `arguments` String - The command line arguments when `program` is
executed
* `title` String - The string to be displayed in a JumpList
* `description` String - Description of this task
* `iconPath` String - The absolute path to an icon to be displayed in a
JumpList, it can be arbitrary resource file that contains an icon, usually
you can specify `process.execPath` to show the icon of the program
JumpList, which can be an arbitrary resource file that contains an icon. You can
usually specify `process.execPath` to show the icon of the program
* `iconIndex` Integer - The icon index in the icon file. If an icon file
consists of two or more icons, set this value to identify the icon. If an
icon file consists of one icon, this value is 0
@@ -251,25 +255,25 @@ to control some low-level Chromium behaviors.
## app.commandLine.appendArgument(value)
Append an argument to Chromium's command line. The argument will quoted properly.
Append an argument to Chromium's command line. The argument will be quoted correctly.
**Note:** This will not affect `process.argv`.
## app.dock.bounce([type])
* `type` String - Can be `critical` or `informational`, the default is
* `type` String - Can be `critical` or `informational`. The default is
`informational`
When `critical` is passed, the dock icon will bounce until either the
application becomes active or the request is canceled.
When `informational` is passed, the dock icon will bounce for one second. The
request, though, remains active until either the application becomes active or
When `informational` is passed, the dock icon will bounce for one second. However,
the request remains active until either the application becomes active or
the request is canceled.
An ID representing the request would be returned.
An ID representing the request is returned.
**Note:** This API is only available on Mac.
**Note:** This API is only available on OS X.
## app.dock.cancelBounce(id)
@@ -277,7 +281,7 @@ An ID representing the request would be returned.
Cancel the bounce of `id`.
**Note:** This API is only available on Mac.
**Note:** This API is only available on OS X.
## app.dock.setBadge(text)
@@ -285,33 +289,33 @@ Cancel the bounce of `id`.
Sets the string to be displayed in the docks badging area.
**Note:** This API is only available on Mac.
**Note:** This API is only available on OS X.
## app.dock.getBadge()
Returns the badge string of the dock.
**Note:** This API is only available on Mac.
**Note:** This API is only available on OS X.
## app.dock.hide()
Hides the dock icon.
**Note:** This API is only available on Mac.
**Note:** This API is only available on OS X.
## app.dock.show()
Shows the dock icon.
**Note:** This API is only available on Mac.
**Note:** This API is only available on OS X.
## app.dock.setMenu(menu)
* `menu` Menu
Sets the application [dock menu][dock-menu].
Sets the application's [dock menu][dock-menu].
**Note:** This API is only available on Mac.
**Note:** This API is only available on OS X.
[dock-menu]:https://developer.apple.com/library/mac/documentation/Carbon/Conceptual/customizing_docktile/concepts/dockconcepts.html#//apple_ref/doc/uid/TP30000986-CH2-TPXREF103
[tasks]:http://msdn.microsoft.com/en-us/library/windows/desktop/dd378460(v=vs.85).aspx#tasks

143
docs/api/auto-updater-ko.md Normal file
View File

@@ -0,0 +1,143 @@
# auto-updater
**This module has only been implemented for OS X.**
Check out [atom/grunt-electron-installer](https://github.com/atom/grunt-electron-installer)
for building a Windows installer for your app.
The `auto-updater` module is a simple wrap around the
[Squirrel.Mac](https://github.com/Squirrel/Squirrel.Mac) framework.
Squirrel.Mac requires that your `.app` folder is signed using the
[codesign](https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/codesign.1.html)
utility for updates to be installed.
## Squirrel
Squirrel is an OS X framework focused on making application updates **as safe
and transparent as updates to a website**.
Instead of publishing a feed of versions from which your app must select,
Squirrel updates to the version your server tells it to. This allows you to
intelligently update your clients based on the request you give to Squirrel.
Your request can include authentication details, custom headers or a request
body so that your server has the context it needs in order to supply the most
suitable update.
The update JSON Squirrel requests should be dynamically generated based on
criteria in the request, and whether an update is required. Squirrel relies
on server side support for determining whether an update is required, see
[Server Support](#server-support).
Squirrel's installer is also designed to be fault tolerant, and ensure that any
updates installed are valid.
## Update Requests
Squirrel is indifferent to the request the client application provides for
update checking. `Accept: application/json` is added to the request headers
because Squirrel is responsible for parsing the response.
For the requirements imposed on the responses and the body format of an update
response see [Server Support](#server-support).
Your update request must *at least* include a version identifier so that the
server can determine whether an update for this specific version is required. It
may also include other identifying criteria such as operating system version or
username, to allow the server to deliver as fine grained an update as you
would like.
How you include the version identifier or other criteria is specific to the
server that you are requesting updates from. A common approach is to use query
parameters, like this:
```javascript
// On the main process
var app = require('app');
var autoUpdater = require('auto-updater');
autoUpdater.setFeedUrl('http://mycompany.com/myapp/latest?version=' + app.getVersion());
```
## Server Support
Your server should determine whether an update is required based on the
[Update Request](#update-requests) your client issues.
If an update is required your server should respond with a status code of
[200 OK](http://tools.ietf.org/html/rfc2616#section-10.2.1) and include the
[update JSON](#update-json-format) in the body. Squirrel **will** download and
install this update, even if the version of the update is the same as the
currently running version. To save redundantly downloading the same version
multiple times your server must not inform the client to update.
If no update is required your server must respond with a status code of
[204 No Content](http://tools.ietf.org/html/rfc2616#section-10.2.5). Squirrel
will check for an update again at the interval you specify.
## Update JSON Format
When an update is available, Squirrel expects the following schema in response
to the update request provided:
```json
{
"url": "http://mycompany.com/myapp/releases/myrelease",
"name": "My Release Name",
"notes": "Theses are some release notes innit",
"pub_date": "2013-09-18T12:29:53+01:00",
}
```
The only required key is "url", the others are optional.
Squirrel will request "url" with `Accept: application/zip` and only supports
installing ZIP updates. If future update formats are supported their MIME type
will be added to the `Accept` header so that your server can return the
appropriate format.
`pub_date` if present must be formatted according to ISO 8601.
## Event: error
* `event` Event
* `message` String
Emitted when there is an error updating.
## Event: checking-for-update
Emitted when checking for update has started.
## Event: update-available
Emitted when there is an available update, the update would be downloaded
automatically.
## Event: update-not-available
Emitted when there is no available update.
## Event: update-downloaded
* `event` Event
* `releaseNotes` String
* `releaseName` String
* `releaseDate` Date
* `updateUrl` String
* `quitAndUpdate` Function
Emitted when update has been downloaded, calling `quitAndUpdate()` would restart
the application and install the update.
## autoUpdater.setFeedUrl(url)
* `url` String
Set the `url` and initialize the auto updater. The `url` could not be changed
once it is set.
## autoUpdater.checkForUpdates()
Ask the server whether there is an update, you have to call `setFeedUrl` before
using this API.

View File

@@ -85,7 +85,7 @@ to the update request provided:
"url": "http://mycompany.com/myapp/releases/myrelease",
"name": "My Release Name",
"notes": "Theses are some release notes innit",
"pub_date": "2013-09-18T12:29:53+01:00",
"pub_date": "2013-09-18T12:29:53+01:00"
}
```

File diff suppressed because it is too large Load Diff

View File

@@ -361,6 +361,19 @@ Sets whether the window should be in fullscreen mode.
Returns whether the window is in fullscreen mode.
### BrowserWindow.setAspectRatio(aspectRatio[, extraSize])
* `aspectRatio` The aspect ratio we want to maintain for some portion of the content view.
* `rect` Object - The extra size to not be included in the aspect ratio to be maintained.
* `width` Integer
* `height` Integer
This will have a window maintain an aspect ratio. The extra size allows a developer to be able to have space, specifified in pixels, not included within the aspect ratio calculations. This API already takes into account the difference between a window's size and it's content size.
Consider a normal window with an HD video player and associated controls. Perhaps there are 15 pixels of controls on the left edge, 25 pixels of controls on the right edge and 50 pixels of controls below the player. In order to maintain a 16:9 aspect ratio (standard aspect ratio for HD @1920x1080) within the player itself we would call this function with arguments of 16/9 and [ 40, 50 ]. The second argument doesn't care where the extra width and height are within the content view — only that they exist. Just sum any extra width and height areas you have within the overall content view.
__Note__: This API is only implemented on OS X.
### BrowserWindow.setBounds(options)
* `options` Object
@@ -760,7 +773,7 @@ Calling `event.preventDefault()` can prevent creating new windows.
* `event` Event
* `url` String
Emitted when user or the page wants to start an navigation, it can happen when
Emitted when user or the page wants to start a navigation, it can happen when
`window.location` object is changed or user clicks a link in the page.
This event will not emit when the navigation is started programmatically with APIs
@@ -784,6 +797,10 @@ Emitted when a plugin process is crashed.
Emitted when the WebContents is destroyed.
### WebContents.session
Returns the `Session` object used by this WebContents.
### WebContents.loadUrl(url, [options])
* `url` URL
@@ -871,6 +888,10 @@ Whether the renderer process has crashed.
Overrides the user agent for this page.
### WebContents.getUserAgent()
Returns a `String` represents the user agent for this page.
### WebContents.insertCSS(css)
* `css` String
@@ -1055,11 +1076,13 @@ app.on('ready', function() {
2. There is no way to send synchronous messages from the main process to a
renderer process, because it would be very easy to cause dead locks.
## Class: WebContents.session.cookies
## Class: Session
### Session.cookies
The `cookies` gives you ability to query and modify cookies, an example is:
```javascipt
```javascript
var BrowserWindow = require('browser-window');
var win = new BrowserWindow({ width: 800, height: 600 });
@@ -1091,7 +1114,7 @@ win.webContents.on('did-finish-load', function() {
});
```
### WebContents.session.cookies.get(details, callback)
### Session.cookies.get(details, callback)
* `details` Object
* `url` String - Retrieves cookies which are associated with `url`.
@@ -1118,7 +1141,7 @@ win.webContents.on('did-finish-load', function() {
the number of seconds since the UNIX epoch. Not provided for session cookies.
### WebContents.session.cookies.set(details, callback)
### Session.cookies.set(details, callback)
* `details` Object
* `url` String - Retrieves cookies which are associated with `url`
@@ -1134,10 +1157,66 @@ win.webContents.on('did-finish-load', function() {
* `callback` Function - function(error)
* `error` Error
### WebContents.session.cookies.remove(details, callback)
### Session.cookies.remove(details, callback)
* `details` Object
* `url` String - The URL associated with the cookie
* `name` String - The name of cookie to remove
* `callback` Function - function(error)
* `error` Error
### Session.clearCache(callback)
* `callback` Function - Called when operation is done
Clears the session's HTTP cache.
### Session.clearStorageData([options, ]callback)
* `options` Object
* `origin` String - Should follow `window.location.origin`'s representation
`scheme://host:port`
* `storages` Array - The types of storages to clear, can contain:
`appcache`, `cookies`, `filesystem`, `indexdb`, `localstorage`,
`shadercache`, `websql`, `serviceworkers`
* `quotas` Array - The types of quotas to clear, can contain:
`temporary`, `persistent`, `syncable`
* `callback` Function - Called when operation is done
Clears the data of web storages.
### Session.setProxy(config, callback)
* `config` String
* `callback` Function - Called when operation is done
Parses the `config` indicating which proxies to use for the session.
```
config = scheme-proxies[";"<scheme-proxies>]
scheme-proxies = [<url-scheme>"="]<proxy-uri-list>
url-scheme = "http" | "https" | "ftp" | "socks"
proxy-uri-list = <proxy-uri>[","<proxy-uri-list>]
proxy-uri = [<proxy-scheme>"://"]<proxy-host>[":"<proxy-port>]
For example:
"http=foopy:80;ftp=foopy2" -- use HTTP proxy "foopy:80" for http://
URLs, and HTTP proxy "foopy2:80" for
ftp:// URLs.
"foopy:80" -- use HTTP proxy "foopy:80" for all URLs.
"foopy:80,bar,direct://" -- use HTTP proxy "foopy:80" for all URLs,
failing over to "bar" if "foopy:80" is
unavailable, and after that using no
proxy.
"socks4://foopy" -- use SOCKS v4 proxy "foopy:1080" for all
URLs.
"http=foopy,socks5://bar.com -- use HTTP proxy "foopy" for http URLs,
and fail over to the SOCKS5 proxy
"bar.com" if "foopy" is unavailable.
"http=foopy,direct:// -- use HTTP proxy "foopy" for http URLs,
and use no proxy if "foopy" is
unavailable.
"http=foopy;socks=foopy2 -- use HTTP proxy "foopy" for http URLs,
and use socks4://foopy2 for all other
URLs.
```

View File

@@ -0,0 +1,109 @@
# 크롬 Command-Line 스위치 지원
The following command lines switches in Chrome browser are also supported in
Electron, you can use [app.commandLine.appendSwitch][append-switch] to append
them in your app's main script before the [ready][ready] event of [app][app]
module is emitted:
```javascript
var app = require('app');
app.commandLine.appendSwitch('remote-debugging-port', '8315');
app.commandLine.appendSwitch('host-rules', 'MAP * 127.0.0.1');
app.on('ready', function() {
// Your code here
});
```
## --client-certificate=`path`
Sets `path` of client certificate file.
## --ignore-connections-limit=`domains`
Ignore the connections limit for `domains` list seperated by `,`.
## --disable-http-cache
Disables the disk cache for HTTP requests.
## --remote-debugging-port=`port`
Enables remote debug over HTTP on the specified `port`.
## --proxy-server=`address:port`
Uses a specified proxy server, overrides system settings. This switch only
affects HTTP and HTTPS requests.
## --no-proxy-server
Don't use a proxy server, always make direct connections. Overrides any other
proxy server flags that are passed.
## --host-rules=`rules`
Comma-separated list of `rules` that control how hostnames are mapped.
For example:
* `MAP * 127.0.0.1` Forces all hostnames to be mapped to 127.0.0.1
* `MAP *.google.com proxy` Forces all google.com subdomains to be resolved to
"proxy".
* `MAP test.com [::1]:77` Forces "test.com" to resolve to IPv6 loopback. Will
also force the port of the resulting socket address to be 77.
* `MAP * baz, EXCLUDE www.google.com` Remaps everything to "baz", except for
"www.google.com".
These mappings apply to the endpoint host in a net request (the TCP connect
and host resolver in a direct connection, and the `CONNECT` in an http proxy
connection, and the endpoint host in a `SOCKS` proxy connection).
## --host-resolver-rules=`rules`
Like `--host-rules` but these `rules` only apply to the host resolver.
[app]: app-ko.md
[append-switch]: app-ko.md#appcommandlineappendswitchswitch-value
[ready]: app-ko.md#event-ready
## --ignore-certificate-errors
Ignores certificate related errors.
## --ppapi-flash-path=`path`
Sets `path` of pepper flash plugin.
## --ppapi-flash-version=`version`
Sets `version` of pepper flash plugin.
## --log-net-log=`path`
Enables saving net log events and writes them to `path`.
## --v=`log_level`
Gives the default maximal active V-logging level; 0 is the default. Normally
positive values are used for V-logging levels.
Passing `--v=-1` will disable logging.
## --vmodule=`pattern`
Gives the per-module maximal V-logging levels to override the value given by
`--v`. E.g. `my_module=2,foo*=3` would change the logging level for all code in
source files `my_module.*` and `foo*.*`.
Any pattern containing a forward or backward slash will be tested against the
whole pathname and not just the module. E.g. `*/foo/bar/*=2` would change the
logging level for all code in source files under a `foo/bar` directory.
To disable all chromium related logs and only enable your application logs you
can do:
```javascript
app.commandLine.appendSwitch('v', -1);
app.commandLine.appendSwitch('vmodule', 'console=0');
```

View File

@@ -36,6 +36,10 @@ Enables remote debug over HTTP on the specified `port`.
Uses a specified proxy server, overrides system settings. This switch only
affects HTTP and HTTPS requests.
## --proxy-pac-url=`url`
Uses the PAC script at the specified `url`.
## --no-proxy-server
Don't use a proxy server, always make direct connections. Overrides any other

88
docs/api/clipboard-ko.md Normal file
View File

@@ -0,0 +1,88 @@
# clipboard
`clipboard`는 복사/붙여넣기 작업을 수행하는 방법을 제공합니다. 다음 예제는 클립보드에 문자열을 씁니다:
```javascript
var clipboard = require('clipboard');
clipboard.writeText('Example String');
```
X Window 시스템에선 selection 클립보드도 존재합니다. 이를 사용하려면 인자 뒤에 `selection` 문자열을 같이 지정해주어야 합니다:
```javascript
var clipboard = require('clipboard');
clipboard.writeText('Example String', 'selection');
console.log(clipboard.readText('selection'));
```
## clipboard.readText([type])
* `type` String
클립보드 컨텐츠를 `plain text`로 반환합니다.
## clipboard.writeText(text[, type])
* `text` String
* `type` String
클립보드에 `plain text`로 문자열을 씁니다.
## clipboard.readHtml([type])
* `type` String
클립보드 컨텐츠를 `markup`으로 반환합니다.
## clipboard.writeHtml(markup[, type])
* `markup` String
* `type` String
클립보드에 `markup`으로 씁니다.
## clipboard.readImage([type])
* `type` String
클립보드로부터 [NativeImage](native-image-ko.md)로 이미지를 읽어들입니다.
## clipboard.writeImage(image[, type])
* `image` [NativeImage](native-image-ko.md)
* `type` String
클립보드에 `image`를 씁니다.
## clipboard.clear([type])
* `type` String
클립보드에 저장된 모든 컨텐츠를 삭제합니다.
## clipboard.availableFormats([type])
클립보드의 `type`에 해당하는 지원하는 `format`을 문자열로 반환합니다.
## clipboard.has(data[, type])
* `data` String
* `type` String
클립보드가 지정한 `data`의 형식을 지원하는지 확인합니다.
```javascript
var clipboard = require('clipboard');
console.log(clipboard.has('<p>selection</p>'));
```
**알림:** 이 API는 실험적인 기능이며 차후 최신버전에서 제외될 수 있습니다.
## clipboard.read(data[, type])
* `data` String
* `type` String
클립보드로부터 `data`를 읽어들입니다.
**알림:** 이 API는 실험적인 기능이며 차후 최신버전에서 제외될 수 있습니다.

View File

@@ -88,3 +88,17 @@ console.log(clipboard.has('<p>selection</p>'));
Reads the `data` in clipboard.
**Note:** This API is experimental and could be removed in future.
## clipboard.write(data[, type])
* `data` Object
* `text` String
* `html` String
* `image` [NativeImage](native-image.md)
* `type` String
```javascript
var clipboard = require('clipboard');
clipboard.write({text: 'test', html: "<b>test</b>"});
```
Writes the `data` iinto clipboard.

View File

@@ -0,0 +1,137 @@
# content-tracing
The `content-trace` module is used to collect tracing data generated by the
underlying Chromium content module. This module does not include a web interface
so you need to open `chrome://tracing/` in a Chrome browser and load the generated
file to view the result.
```javascript
var tracing = require('content-tracing');
tracing.startRecording('*', tracing.DEFAULT_OPTIONS, function() {
console.log('Tracing started');
setTimeout(function() {
tracing.stopRecording('', function(path) {
console.log('Tracing data recorded to ' + path);
});
}, 5000);
});
```
## tracing.getCategories(callback)
* `callback` Function
Get a set of category groups. The category groups can change as new code paths
are reached.
Once all child processes have acked to the `getCategories` request, `callback`
is invoked with an array of category groups.
## tracing.startRecording(categoryFilter, options, callback)
* `categoryFilter` String
* `options` Integer
* `callback` Function
Start recording on all processes.
Recording begins immediately locally, and asynchronously on child processes
as soon as they receive the EnableRecording request. Once all child processes
have acked to the `startRecording` request, `callback` will be called back.
`categoryFilter` is a filter to control what category groups should be
traced. A filter can have an optional `-` prefix to exclude category groups
that contain a matching category. Having both included and excluded
category patterns in the same list is not supported.
Examples:
* `test_MyTest*`,
* `test_MyTest*,test_OtherStuff`,
* `"-excluded_category1,-excluded_category2`
`options` controls what kind of tracing is enabled, it could be a OR-ed
combination of `tracing.DEFAULT_OPTIONS`, `tracing.ENABLE_SYSTRACE`,
`tracing.ENABLE_SAMPLING` and `tracing.RECORD_CONTINUOUSLY`.
## tracing.stopRecording(resultFilePath, callback)
* `resultFilePath` String
* `callback` Function
Stop recording on all processes.
Child processes typically are caching trace data and only rarely flush and send
trace data back to the main process. That is because it may be an expensive
operation to send the trace data over IPC, and we would like to avoid much
runtime overhead of tracing. So, to end tracing, we must asynchronously ask all
child processes to flush any pending trace data.
Once all child processes have acked to the `stopRecording` request, `callback`
will be called back with a file that contains the traced data.
Trace data will be written into `resultFilePath` if it is not empty, or into a
temporary file. The actual file path will be passed to `callback` if it's not
null.
## tracing.startMonitoring(categoryFilter, options, callback)
* `categoryFilter` String
* `options` Integer
* `callback` Function
Start monitoring on all processes.
Monitoring begins immediately locally, and asynchronously on child processes as
soon as they receive the `startMonitoring` request.
Once all child processes have acked to the `startMonitoring` request,
`callback` will be called back.
## tracing.stopMonitoring(callback);
* `callback` Function
Stop monitoring on all processes.
Once all child processes have acked to the `stopMonitoring` request, `callback`
is called back.
## tracing.captureMonitoringSnapshot(resultFilePath, callback)
* `resultFilePath` String
* `callback` Function
Get the current monitoring traced data.
Child processes typically are caching trace data and only rarely flush and send
trace data back to the main process. That is because it may be an expensive
operation to send the trace data over IPC, and we would like to avoid unneeded
runtime overhead of tracing. So, to end tracing, we must asynchronously ask all
child processes to flush any pending trace data.
Once all child processes have acked to the `captureMonitoringSnapshot` request,
the `callback` will be invoked with a file that contains the traced data.
## tracing.getTraceBufferUsage(callback)
* `callback` Function
Get the maximum across processes of trace buffer percent full state. When the
TraceBufferUsage value is determined, the `callback` is called.
## tracing.setWatchEvent(categoryName, eventName, callback)
* `categoryName` String
* `eventName` String
* `callback` Function
`callback` will will be called every time the given event occurs on any
process.
## tracing.cancelWatchEvent()
Cancel the watch event. If tracing is enabled, this may race with the watch
event callback.

View File

@@ -0,0 +1,61 @@
# crash-reporter
An example of automatically submitting crash reporters to remote server:
```javascript
crashReporter = require('crash-reporter');
crashReporter.start({
productName: 'YourName',
companyName: 'YourCompany',
submitUrl: 'https://your-domain.com/url-to-submit',
autoSubmit: true
});
```
## crashReporter.start(options)
* `options` Object
* `productName` String, default: Electron
* `companyName` String, default: GitHub, Inc
* `submitUrl` String, default: http://54.249.141.255:1127/post
* URL that crash reports would be sent to as POST
* `autoSubmit` Boolean, default: true
* Send the crash report without user interaction
* `ignoreSystemCrashHandler` Boolean, default: false
* `extra` Object
* An object you can define which content will be send along with the report.
* Only string properties are send correctly.
* Nested objects are not supported.
Developers are required to call the API before using other crashReporter APIs.
**Note:** On OS X, electron uses a new `crashpad` client, which is different
with the `breakpad` on Windows and Linux. To enable crash collection feature,
you are required to call `crashReporter.start` API to initiliaze `crashpad` in
main process, even you only collect crash report in renderer process.
## crashReporter.getLastCrashReport()
Returns the date and ID of last crash report, when there was no crash report
sent or the crash reporter is not started, `null` will be returned.
## crashReporter.getUploadedReports()
Returns all uploaded crash reports, each report contains date and uploaded ID.
# crash-reporter payload
The crash reporter will send the following data to the `submitUrl` as `POST`:
* `rept` String - e.g. 'electron-crash-service'
* `ver` String - The version of Electron
* `platform` String - e.g. 'win32'
* `process_type` String - e.g. 'renderer'
* `ptime` Number
* `_version` String - The version in `package.json`
* `_productName` String - The product name in the crashReporter `options` object
* `prod` String - Name of the underlying product. In this case Electron
* `_companyName` String - The company name in the crashReporter `options` object
* `upload_file_minidump` File - The crashreport as file
* All level one properties of the `extra` object in the crashReporter `options` object

View File

@@ -1,6 +1,6 @@
# crash-reporter
An example of automatically submitting crash reporters to remote server:
An example of automatically submitting crash reporters to a remote server:
```javascript
crashReporter = require('crash-reporter');
@@ -24,20 +24,20 @@ crashReporter.start({
* `ignoreSystemCrashHandler` Boolean, default: false
* `extra` Object
* An object you can define which content will be send along with the report.
* Only string properties are send correctly.
* Only string properties are sent correctly.
* Nested objects are not supported.
Developers are required to call the API before using other crashReporter APIs.
Developers are required to call this method before using other crashReporter APIs.
**Note:** On OS X, electron uses a new `crashpad` client, which is different
with the `breakpad` on Windows and Linux. To enable crash collection feature,
you are required to call `crashReporter.start` API to initiliaze `crashpad` in
main process, even you only collect crash report in renderer process.
you are required to call `crashReporter.start` API to initialize `crashpad` in
main process and in each renderer process that you wish to collect crash reports.
## crashReporter.getLastCrashReport()
Returns the date and ID of last crash report, when there was no crash report
Returns the date and ID of the last crash report, when there was no crash report
sent or the crash reporter is not started, `null` will be returned.
## crashReporter.getUploadedReports()

92
docs/api/dialog-ko.md Normal file
View File

@@ -0,0 +1,92 @@
# dialog
The `dialog` module provides APIs to show native system dialogs, so web
applications can deliver the same user experience as native applications.
An example of showing a dialog to select multiple files and directories:
```javascript
var win = ...; // window in which to show the dialog
var dialog = require('dialog');
console.log(dialog.showOpenDialog({ properties: [ 'openFile', 'openDirectory', 'multiSelections' ]}));
```
**Note for OS X**: If you want to present dialogs as sheets, the only thing you have to do is provide a `BrowserWindow` reference in the `browserWindow` parameter.
## dialog.showOpenDialog([browserWindow], [options], [callback])
* `browserWindow` BrowserWindow
* `options` Object
* `title` String
* `defaultPath` String
* `filters` Array
* `properties` Array - Contains which features the dialog should use, can
contain `openFile`, `openDirectory`, `multiSelections` and
`createDirectory`
* `callback` Function
On success, returns an array of file paths chosen by the user, otherwise
returns `undefined`.
The `filters` specifies an array of file types that can be displayed or
selected, an example is:
```javascript
{
filters: [
{ name: 'Images', extensions: ['jpg', 'png', 'gif'] },
{ name: 'Movies', extensions: ['mkv', 'avi', 'mp4'] },
{ name: 'Custom File Type', extensions: ['as'] }
]
}
```
If a `callback` is passed, the API call would be asynchronous and the result
would be passed via `callback(filenames)`
**Note:** On Windows and Linux, an open dialog can not be both a file selector
and a directory selector, so if you set `properties` to
`['openFile', 'openDirectory']` on these platforms, a directory selector will be shown.
## dialog.showSaveDialog([browserWindow], [options], [callback])
* `browserWindow` BrowserWindow
* `options` Object
* `title` String
* `defaultPath` String
* `filters` Array
* `callback` Function
On success, returns the path of the file chosen by the user, otherwise returns
`undefined`.
The `filters` specifies an array of file types that can be displayed, see
`dialog.showOpenDialog` for an example.
If a `callback` is passed, the API call will be asynchronous and the result
will be passed via `callback(filename)`
## dialog.showMessageBox([browserWindow], options, [callback])
* `browserWindow` BrowserWindow
* `options` Object
* `type` String - Can be `"none"`, `"info"` or `"warning"`
* `buttons` Array - Array of texts for buttons
* `title` String - Title of the message box, some platforms will not show it
* `message` String - Content of the message box
* `detail` String - Extra information of the message
* `icon` [NativeImage](native-image-ko.md)
* `callback` Function
Shows a message box, it will block until the message box is closed. It returns
the index of the clicked button.
If a `callback` is passed, the API call will be asynchronous and the result
will be passed via `callback(response)`
## dialog.showErrorBox(title, content)
Runs a modal dialog that shows an error message.
This API can be called safely before the `ready` event of `app` module emits, it
is usually used to report errors in early stage of startup.

View File

@@ -70,12 +70,22 @@ will be passed via `callback(filename)`
* `browserWindow` BrowserWindow
* `options` Object
* `type` String - Can be `"none"`, `"info"` or `"warning"`
* `type` String - Can be `"none"`, `"info"`, `"error"`, `"question"` or `"warning"`. On Windows, "question" displays the same icon as "info", unless if you set an icon using the "icon" option
* `buttons` Array - Array of texts for buttons
* `title` String - Title of the message box, some platforms will not show it
* `message` String - Content of the message box
* `detail` String - Extra information of the message
* `icon` [NativeImage](native-image.md)
* `cancelId` Integer - The value will be returned when user cancels the dialog
instead of clicking the buttons of the dialog. By default it is the index
of the buttons that have "cancel" or "no" as label, or 0 if there is no such
buttons. On OS X and Windows the index of "Cancel" button will always be
used as `cancelId`, not matter whether it is already specified
* `noLink` Boolean - On Windows Electron would try to figure out which ones of
the `buttons` are common buttons (like "Cancel" or "Yes"), and show the
others as command links in the dialog, this can make the dialog appear in
the style of modern Windows apps. If you don't like this behavior, you can
specify `noLink` to `true`
* `callback` Function
Shows a message box, it will block until the message box is closed. It returns

View File

@@ -0,0 +1,28 @@
# `File` 객체
DOM의 File 인터페이스는 네이티브 파일을 추상화 합니다. 유저가 직접적으로 HTML5 File API를 사용하여 작업할 때 파일의 경로를
알 수 있도록 Electron은 파일시스템의 실제 파일 경로를 담은 `path` 속성을 File 인터페이스에 추가하였습니다.
다음 예제는 drag n drop한 파일의 실제 경로를 가져옵니다:
```html
<div id="holder">
Drag your file here
</div>
<script>
var holder = document.getElementById('holder');
holder.ondragover = function () {
return false;
};
holder.ondragleave = holder.ondragend = function () {
return false;
};
holder.ondrop = function (e) {
e.preventDefault();
var file = e.dataTransfer.files[0];
console.log('File you dragged here is', file.path);
return false;
};
</script>
```

View File

@@ -0,0 +1,89 @@
# Frameless window
A frameless window is a window that has no chrome.
## Create a frameless window
To create a frameless window, you only need to specify `frame` to `false` in
[BrowserWindow](browser-window-ko.md)'s `options`:
```javascript
var BrowserWindow = require('browser-window');
var win = new BrowserWindow({ width: 800, height: 600, frame: false });
```
## Transparent window
By setting the `transparent` option to `true`, you can also make the frameless
window transparent:
```javascript
var win = new BrowserWindow({ transparent: true, frame: false });
```
### Limitations
* You can not click through the transparent area, we are going to introduce an
API to set window shape to solve this, but currently blocked at an
[upstream bug](https://code.google.com/p/chromium/issues/detail?id=387234).
* Transparent window is not resizable, setting `resizable` to `true` may make
transparent window stop working on some platforms.
* The `blur` filter only applies to the web page, so there is no way to apply
blur effect to the content below the window.
* On Windows transparent window will not work when DWM is disabled.
* On Linux users have to put `--enable-transparent-visuals --disable-gpu` in
command line to disable GPU and allow ARGB to make transparent window, this is
caused by an upstream bug that [alpha channel doesn't work on some NVidia
drivers](https://code.google.com/p/chromium/issues/detail?id=369209) on Linux.
* On Mac the native window shadow will not show for transparent window.
## Draggable region
By default, the frameless window is non-draggable. Apps need to specify
`-webkit-app-region: drag` in CSS to tell Electron which regions are draggable
(like the OS's standard titlebar), and apps can also use
`-webkit-app-region: no-drag` to exclude the non-draggable area from the
draggable region. Note that only rectangular shape is currently supported.
To make the whole window draggable, you can add `-webkit-app-region: drag` as
`body`'s style:
```html
<body style="-webkit-app-region: drag">
</body>
```
And note that if you have made the whole window draggable, you must also mark
buttons as non-draggable, otherwise it would be impossible for users to click on
them:
```css
button {
-webkit-app-region: no-drag;
}
```
If you're only using a custom titlebar, you also need to make buttons in
titlebar non-draggable.
## Text selection
One thing on frameless window is that the dragging behaviour may conflict with
selecting text, for example, when you drag the titlebar, you may accidentally
select the text on titlebar. To prevent this, you need to disable text
selection on dragging area like this:
```css
.titlebar {
-webkit-user-select: none;
-webkit-app-region: drag;
}
```
## Context menu
On some platforms, the draggable area would be treated as non-client frame, so
when you right click on it a system menu would be popuped. To make context menu
behave correctly on all platforms, you should never custom context menu on
draggable areas.

View File

@@ -0,0 +1,47 @@
# global-shortcut
`global-shortcut` 모듈은 사용자가 다양한 단축키 작업을 정의 할 수 있도록 운영체제의 전역 키보드 단축키를 설정 등록/해제 하는 방법을 제공합니다.
참고로 설정된 단축키는 어플리케이션이 백그라운드로 작동(창이 포커스 되지 않음) 할 때도 여전히 계속 작동합니다.
```javascript
var globalShortcut = require('global-shortcut');
// 'ctrl+x' 단축키를 리스너에 등록합니다.
var ret = globalShortcut.register('ctrl+x', function() { console.log('ctrl+x is pressed'); })
if (!ret) {
console.log('registration failed');
}
// 단축키가 등록되었는지 확인합니다.
console.log(globalShortcut.isRegistered('ctrl+x'));
// 단축키의 등록을 해제합니다.
globalShortcut.unregister('ctrl+x');
// 모든 단축키의 등록을 해제합니다.
globalShortcut.unregisterAll();
```
## globalShortcut.register(accelerator, callback)
* `accelerator` [Accelerator](accelerator-ko.md)
* `callback` Function
`accelerator`로 표현된 전역 단축키를 등록합니다. 유저로부터 등록된 단축키가 눌렸을 경우 `callback` 함수가 호출됩니다.
## globalShortcut.isRegistered(accelerator)
* `accelerator` [Accelerator](accelerator-ko.md)
지정된 `accelerator` 단축키가 등록되었는지 여부를 확인합니다. 반환값은 boolean(true, false) 입니다.
## globalShortcut.unregister(accelerator)
* `accelerator` [Accelerator](accelerator-ko.md)
`키코드`에 해당하는 전역 단축키를 등록 해제합니다.
## globalShortcut.unregisterAll()
모든 전역 단축키 등록을 해제합니다.

View File

@@ -1,27 +1,35 @@
# global-shortcut
The `global-shortcut` module can register/unregister a global keyboard shortcut
in operating system, so that you can customize the operations for various shortcuts.
Note that the shortcut is global, even if the app does not get focused, it will still work.
with the operating system, so that you can customize the operations for various shortcuts.
Note that the shortcut is global; it will work even if the app does not have the keyboard focus.
You should not use this module until the `ready` event of the app module is emitted.
```javascript
var app = require('app');
var globalShortcut = require('global-shortcut');
// Register a 'ctrl+x' shortcut listener.
var ret = globalShortcut.register('ctrl+x', function() { console.log('ctrl+x is pressed'); })
app.on('ready', function() {
// Register a 'ctrl+x' shortcut listener.
var ret = globalShortcut.register('ctrl+x', function() {
console.log('ctrl+x is pressed');
})
if (!ret) {
console.log('registration failed');
}
if (!ret) {
console.log('registration failed');
}
// Check whether a shortcut is registered.
console.log(globalShortcut.isRegistered('ctrl+x'));
// Check whether a shortcut is registered.
console.log(globalShortcut.isRegistered('ctrl+x'));
});
// Unregister a shortcut.
globalShortcut.unregister('ctrl+x');
app.on('will-quit', function() {
// Unregister a shortcut.
globalShortcut.unregister('ctrl+x');
// Unregister all shortcuts.
globalShortcut.unregisterAll();
// Unregister all shortcuts.
globalShortcut.unregisterAll();
});
```
## globalShortcut.register(accelerator, callback)
@@ -29,14 +37,14 @@ globalShortcut.unregisterAll();
* `accelerator` [Accelerator](accelerator.md)
* `callback` Function
Registers a global shortcut of `accelerator`, the `callback` would be called when
the registered shortcut is pressed by user.
Registers a global shortcut of `accelerator`. The `callback` is called when
the registered shortcut is pressed by the user.
## globalShortcut.isRegistered(accelerator)
* `accelerator` [Accelerator](accelerator.md)
Returns `true` or `false` depending on if the shortcut `accelerator` is registered.
Returns `true` or `false` depending on whether the shortcut `accelerator` is registered.
## globalShortcut.unregister(accelerator)

View File

@@ -0,0 +1,46 @@
# ipc (main process)
랜더러 프로세스(웹 페이지)로 부터 동기 또는 비동기로 메시지를 받아 처리합니다.
랜더러로부터 발신된 메시지들은 모두 이 모듈에서 `channel` 이라는 특정 이벤트 이름을 통해 수신할 수 있습니다.
동기 메시지는 `event.returnValue`를 이용하여 반환값(답장)을 설정할 수 있습니다. 비동기 메시지라면 `event.sender.send(...)`를 사용하면 됩니다.
또한 메인 프로세스에서 랜더러 프로세스로 메시지를 보내는 것도 가능합니다.
자세한 내용은 [WebContents.send](browser-window-ko.md#webcontentssendchannel-args)를 참고 하세요.
보내진 메시지들을 처리하는 예제입니다:
```javascript
// 메인 프로세스에서 처리.
var ipc = require('ipc');
ipc.on('asynchronous-message', function(event, arg) {
console.log(arg); // prints "ping"
event.sender.send('asynchronous-reply', 'pong');
});
ipc.on('synchronous-message', function(event, arg) {
console.log(arg); // prints "ping"
event.returnValue = 'pong';
});
```
```javascript
// 랜더러 프로세스에서의 처리 (web page).
var ipc = require('ipc');
console.log(ipc.sendSync('synchronous-message', 'ping')); // prints "pong"
ipc.on('asynchronous-reply', function(arg) {
console.log(arg); // prints "pong"
});
ipc.send('asynchronous-message', 'ping');
```
## Class: Event
### Event.returnValue
동기 메시지를 설정합니다.
### Event.sender
메시지를 보내온 sender `WebContents` 객체입니다.

View File

@@ -0,0 +1,25 @@
# ipc (renderer)
`ipc` 모듈은 메인 프로세스로 메시지를 동기 또는 비동기로 보내고 받을 수 있는 몇 가지 방법을 제공합니다.
만약 랜더러 프로세스에서 메인 프로세스의 모듈을 직접적으로 사용하고 싶다면 [remote](remote-ko.md) 모듈을 사용하는 것을 고려해보는 것이 좋습니다.
[ipc (main process)](ipc-main-process-ko.md)에서 예제를 볼 수 있습니다.
## ipc.send(channel[, args...])
지정한 `channel`을 통해 `args..`를 비동기로 메시지를 보냅니다. 메인 프로세스는 `ipc` 모듈의 `channel` 이벤트를 통해 메시지를 받을 수 있습니다.
## ipc.sendSync(channel[, args...])
지정한 `channel`을 통해 `args..`를 동기로 메시지를 보냅니다. 그리고 메인 프로세스에서 보낸 결과를 반환합니다.
메인 프로세스는 `ipc` 모듈의 `channel` 이벤트를 통해 메시지를 받을 수 있습니다. 그리고 `event.returnValue`를 통해 반환값을 설정할 수 있습니다.
역자 주: `channel`은 이벤트 이름입니다.
**알림:** 보통 개발자들은 해당 API를 사용하려 하지 않습니다. 동기 ipc 작업은 랜더러 프로세스의 모든 작업을 중단시킵니다.
## ipc.sendToHost(channel[, args...])
`ipc.send`와 비슷하지만 메시지를 메인 프로세스 대신 호스트 페이지로 보냅니다.
이 메소드는 보통 `<webview>`와 호스트 페이지 간의 통신에 사용됩니다.

View File

@@ -1,20 +1,20 @@
# menu-item
# menu-item
## Class: MenuItem
### new MenuItem(options)
* `options` Object
* `click` Function - 메뉴 아이템이 클릭될 때 호출되는 콜백함수
* `selector` String - First Responder가 클릭될 때 호출 되는 선택자 (OS X 전용)
* `type` String - `MenuItem`의 타입 `normal`, `separator`, `submenu`, `checkbox` 또는 `radio` 사용가능
* `click` Function - 메뉴 아이템이 클릭될 때 호출되는 콜백함수
* `selector` String - First Responder가 클릭될 때 호출 되는 선택자 (OS X 전용)
* `type` String - `MenuItem`의 타입 `normal`, `separator`, `submenu`, `checkbox` 또는 `radio` 사용가능
* `label` String
* `sublabel` String
* `accelerator` [Accelerator](accelerator.md)
* `icon` [NativeImage](native-image.md)
* `accelerator` [Accelerator](accelerator-ko.md)
* `icon` [NativeImage](native-image-ko.md)
* `enabled` Boolean
* `visible` Boolean
* `checked` Boolean
* `submenu` Menu - 보조메뉴를 설정합니다. `type``submenu`일 경우 반드시 설정해야합니다. 일반 메뉴 아이템일 경우 생략할 수 있습니다.
* `id` String - 현재 메뉴 아이템에 대해 유일키를 지정합니다. 이 키는 이후 `position` 옵션에서 사용할 수 있습니다.
* `position` String - 미리 지정한 `id`를 이용하여 메뉴 아이템의 위치를 세밀하게 조정합니다.
* `submenu` Menu - 보조메뉴를 설정합니다. `type``submenu`일 경우 반드시 설정해야합니다. 일반 메뉴 아이템일 경우 생략할 수 있습니다.
* `id` String - 현재 메뉴 아이템에 대해 유일키를 지정합니다. 이 키는 이후 `position` 옵션에서 사용할 수 있습니다.
* `position` String - 미리 지정한 `id`를 이용하여 메뉴 아이템의 위치를 세밀하게 조정합니다.

330
docs/api/menu-ko.md Normal file
View File

@@ -0,0 +1,330 @@
# menu
The `Menu` class is used to create native menus that can be used as
application menus and context menus. Each menu consists of multiple menu
items, and each menu item can have a submenu.
Below is an example of creating a menu dynamically in a web page by using
the [remote](remote-ko.md) module, and showing it when the user right clicks
the page:
```html
<!-- index.html -->
<script>
var remote = require('remote');
var Menu = remote.require('menu');
var MenuItem = remote.require('menu-item');
var menu = new Menu();
menu.append(new MenuItem({ label: 'MenuItem1', click: function() { console.log('item 1 clicked'); } }));
menu.append(new MenuItem({ type: 'separator' }));
menu.append(new MenuItem({ label: 'MenuItem2', type: 'checkbox', checked: true }));
window.addEventListener('contextmenu', function (e) {
e.preventDefault();
menu.popup(remote.getCurrentWindow());
}, false);
</script>
```
Another example of creating the application menu with the simple template API:
```html
<!-- index.html -->
<script>
var remote = require('remote');
var Menu = remote.require('menu');
var template = [
{
label: 'Electron',
submenu: [
{
label: 'About Electron',
selector: 'orderFrontStandardAboutPanel:'
},
{
type: 'separator'
},
{
label: 'Services',
submenu: []
},
{
type: 'separator'
},
{
label: 'Hide Electron',
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',
selector: 'terminate:'
},
]
},
{
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() { remote.getCurrentWindow().reload(); }
},
{
label: 'Toggle DevTools',
accelerator: 'Alt+Command+I',
click: function() { remote.getCurrentWindow().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:'
}
]
},
{
label: 'Help',
submenu: []
}
];
menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
</script>
```
## Class: Menu
### new Menu()
Creates a new menu.
### Class Method: Menu.setApplicationMenu(menu)
* `menu` Menu
Sets `menu` as the application menu on OS X. On Windows and Linux, the `menu`
will be set as each window's top menu.
### Class Method: Menu.sendActionToFirstResponder(action)
* `action` String
Sends the `action` to the first responder of application, this is used for
emulating default Cocoa menu behaviors, usually you would just use the
`selector` property of `MenuItem`.
**Note:** This method is OS X only.
### Class Method: Menu.buildFromTemplate(template)
* `template` Array
Generally, the `template` is just an array of `options` for constructing
[MenuItem](menu-item-ko.md), the usage can be referenced above.
You can also attach other fields to element of the `template`, and they will
become properties of the constructed menu items.
### Menu.popup(browserWindow, [x, y])
* `browserWindow` BrowserWindow
* `x` Number
* `y` Number
Popups this menu as a context menu in the `browserWindow`. You can optionally
provide a `(x,y)` coordinate to place the menu at, otherwise it will be placed
at the current mouse cursor position.
### Menu.append(menuItem)
* `menuItem` MenuItem
Appends the `menuItem` to the menu.
### Menu.insert(pos, menuItem)
* `pos` Integer
* `menuItem` MenuItem
Inserts the `menuItem` to the `pos` position of the menu.
### Menu.items
Get the array containing the menu's items.
## Notes on OS X application menu
OS X has a completely different style of application menu from Windows and
Linux, and here are some notes on making your app's menu more native-like.
### Standard menus
On OS X there are many system defined standard menus, like the `Services` and
`Windows` menus. To make your menu a standard menu, you can just set your menu's
label to one of followings, and Electron will recognize them and make them
become standard menus:
* `Window`
* `Help`
* `Services`
### Standard menu item actions
OS X has provided standard actions for some menu items (which are called
`selector`s), like `About xxx`, `Hide xxx`, and `Hide Others`. To set the action
of a menu item to a standard action, you can set the `selector` attribute of the
menu item.
### Main menu's name
On OS X the label of application menu's first item is always your app's name,
no matter what label you set. To change it you have to change your app's name
by modifying your app bundle's `Info.plist` file. See
[About Information Property List Files](https://developer.apple.com/library/ios/documentation/general/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html)
for more.
## Menu item position
You can make use of `position` and `id` to control how the item would be placed
when building a menu with `Menu.buildFromTemplate`.
The `position` attribute of `MenuItem` has the form `[placement]=[id]` where
placement is one of `before`, `after`, or `endof` and `id` is the unique ID of
an existing item in the menu:
* `before` - Inserts this item before the id referenced item. If the
referenced item doesn't exist the item will be inserted at the end of
the menu.
* `after` - Inserts this item after id referenced item. If the referenced
item doesn't exist the item will be inserted at the end of the menu.
* `endof` - Inserts this item at the end of the logical group containing
the id referenced item. (Groups are created by separator items). If
the referenced item doesn't exist a new separator group is created with
the given id and this item is inserted after that separator.
When an item is positioned following unpositioned items are inserted after
it, until a new item is positioned. So if you want to position a group of
menu items in the same location you only need to specify a position for
the first item.
### Examples
Template:
```javascript
[
{label: '4', id: '4'},
{label: '5', id: '5'},
{label: '1', id: '1', position: 'before=4'},
{label: '2', id: '2'},
{label: '3', id: '3'}
]
```
Menu:
```
- 1
- 2
- 3
- 4
- 5
```
Template:
```javascript
[
{label: 'a', position: 'endof=letters'},
{label: '1', position: 'endof=numbers'},
{label: 'b', position: 'endof=letters'},
{label: '2', position: 'endof=numbers'},
{label: 'c', position: 'endof=letters'},
{label: '3', position: 'endof=numbers'}
]
```
Menu:
```
- ---
- a
- b
- c
- ---
- 1
- 2
- 3
```

127
docs/api/native-image-ko.md Normal file
View File

@@ -0,0 +1,127 @@
# NativeImage
Electron은 파일 경로나 `NativeImage` 인스턴스를 전달하여 사용하는 이미지 API를 가지고 있습니다. `null`을 전달할 경우 빈 이미지가 사용됩니다.
예를 들어 트레이 메뉴를 만들거나 윈도우의 아이콘을 설정할 때 다음과 같이 `문자열`인 파일 경로를 전달할 수 있습니다:
```javascript
var appIcon = new Tray('/Users/somebody/images/icon.png');
var window = new BrowserWindow({icon: '/Users/somebody/images/window.png'});
```
또는 클립보드로부터 이미지를 읽어올 수 있습니다:
```javascript
var clipboard = require('clipboard');
var image = clipboard.readImage();
var appIcon = new Tray(image);
```
## 지원하는 포맷
현재 `PNG``JPEG` 포맷을 지원하고 있습니다. 손실 없는 이미지 압축과 투명도 지원을 위해 `PNG` 사용을 권장합니다.
## 고해상도 이미지
플랫폼이 high-DPI를 지원하는 경우 `@2x`와 같이 이미지의 파일명 뒤에 접미사를 추가하여 고해상도 이미지로 지정할 수 있습니다.
예를 들어 `icon.png` 라는 기본 해상도의 이미지를 기준으로 크기를 두 배로 늘린 이미지를 `icon@2x.png`와 같이 이름을 지정하면 고해상도 이미지로 처리됩니다.
서로 다른 해상도(DPI)의 이미지를 지원하고 싶다면 다중 해상도의 이미지를 접미사를 붙여 한 폴더에 넣으면 됩니다. 이 이미지를 사용(로드)할 땐 접미사를 붙이지 않습니다:
```text
images/
├── icon.png
├── icon@2x.png
└── icon@3x.png
```
```javascript
var appIcon = new Tray('/Users/somebody/images/icon.png');
```
지원하는 DPI 접미사는 다음과 같습니다:
* `@1x`
* `@1.25x`
* `@1.33x`
* `@1.4x`
* `@1.5x`
* `@1.8x`
* `@2x`
* `@2.5x`
* `@3x`
* `@4x`
* `@5x`
## 템플릿 이미지
템플릿 이미지는 검은색과 명확한 색상(알파 채널)으로 이루어져 있습니다.
템플릿 이미지는 단독 이미지로 사용되지 않고 다른 컨텐츠와 혼합되어 최종 외관 만드는데 사용됩니다.
가장 일반적으로 템플릿 이미지는 밝고 어두운 테마 색상으로 변경할 수 있는 메뉴 바 아이콘 등에 사용되고 있습니다.
템플릿 이미지는 Mac 운영체제만 지원합니다.
템플릿 이미지를 지정하려면 다음 예제와 같이 파일명에 `Template` 문자열을 추가해야 합니다:
* `xxxTemplate.png`
* `xxxTemplate@2x.png`
## nativeImage.createEmpty()
`NativeImage` 인스턴스를 만듭니다.
## nativeImage.createFromPath(path)
* `path` String
`path`로부터 이미지를 로드하여 새로운 `NativeImage` 인스턴스를 만듭니다.
## nativeImage.createFromBuffer(buffer[, scaleFactor])
* `buffer` [Buffer][buffer]
* `scaleFactor` Double
`buffer`로부터 이미지를 로드하여 새로운 `NativeImage` 인스턴스를 만듭니다. `scaleFactor`는 1.0이 기본입니다.
## nativeImage.createFromDataUrl(dataUrl)
* `dataUrl` String
`dataUrl`로부터 이미지를 로드하여 새로운 `NativeImage` 인스턴스를 만듭니다.
## Class: NativeImage
이미지를 표현한 클래스입니다.
### NativeImage.toPng()
`PNG` 이미지를 인코딩한 데이터를 [Buffer][buffer]로 반환합니다.
### NativeImage.toJpeg(quality)
* `quality` Integer
`JPEG` 이미지를 인코딩한 데이터를 [Buffer][buffer]로 반환합니다.
### NativeImage.toDataUrl()
이미지의 data URL을 반환합니다.
### NativeImage.isEmpty()
이미지가 비었는지를 체크합니다.
### NativeImage.getSize()
이미지의 사이즈를 반환합니다.
### NativeImage.setTemplateImage(option)
* `option` Boolean
해당 이미지를 템플릿 이미지로 설정합니다.
[buffer]: https://iojs.org/api/buffer.html#buffer_class_buffer

View File

@@ -114,7 +114,7 @@ Returns a [Buffer][buffer] that contains image's `PNG` encoded data.
### NativeImage.toJpeg(quality)
* `quality` Integer
* `quality` Integer between 0 - 100 (required)
Returns a [Buffer][buffer] that contains image's `JPEG` encoded data.

View File

@@ -1,4 +1,4 @@
# power-monitor
# power-monitor
`power-monitor` 모듈은 PC의 파워 상태를 나타냅니다. (주로 노트북 등에서 사용됩니다)
이 모듈은 메인 프로세스에서만 사용할 수 있으며, (remote 모듈(RPC)을 사용해도 작동이 됩니다)

View File

@@ -0,0 +1,43 @@
# power-save-blocker
`power-save-blocker` 모듈은 시스템이 저전력 모드(슬립)로 진입하는 것을 막고 앱 및 화면이 항상 활성화되어 있는 상태를 만들 수 있도록 해줍니다.
예제:
```javascript
var powerSaveBlocker = require('power-save-blocker');
var id = powerSaveBlocker.start('prevent-display-sleep');
console.log(powerSaveBlocker.isStarted(id));
powerSaveBlocker.stop(id);
```
## powerSaveBlocker.start(type)
* `type` String - Power save blocker 종류
* `prevent-app-suspension` - 저전력 모드 등으로 인한 어플리케이션 작동 중단을 방지합니다.
시스템을 항시 활성화 상태로 만듭니다, 하지만 화면은 자동으로 꺼질 수 있습니다. 사용 예시: 파일 다운로드, 음악 재생 등.
* `prevent-display-sleep`- 슬립 모드 등으로 인한 어플리케이션의 작동 중단을 방지합니다.
시스템을 항시 활성화 상태로 만들고 슬립 모드(화면 꺼짐)를 방지합니다. 사용 예시: 비디오 재생 등.
Power save blocker를 시작하고 시스템이 저전력 모드(슬립)로 진입하는 것을 막습니다. 정수로 된 식별 ID를 반환합니다.
**알림:**
`prevent-display-sleep` 모드는 `prevent-app-suspension` 보다 우선순위가 높습니다.
가장 높은 우선순위의 모드만 작동합니다. 다시 말해 `prevent-display-sleep` 모드는 언제나 `prevent-app-suspension` 모드의 효과를 덮어씌웁니다.
예를 들어 A-요청이 `prevent-app-suspension` 모드를 사용하고 B-요청이 `prevent-display-sleep`를 사용하는 API 호출이 있었다 치면
`prevent-display-sleep` 모드를 사용하는 B의 작동이 중단(stop)되기 전까지 작동하다 B가 중단되면 `prevent-app-suspension` 모드를 사용하는 A가 작동하기 시작합니다.
## powerSaveBlocker.stop(id)
* `id` Integer - `powerSaveBlocker.start`로 부터 반환되는 power save blocker 식별 ID.
설정한 power save blocker를 중지합니다.
## powerSaveBlocker.isStarted(id)
* `id` Integer - `powerSaveBlocker.start`로 부터 반환되는 power save blocker 식별 ID.
해당하는 id의 `powerSaveBlocker`가 실행중인지 확인합니다.

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