Compare commits

..

411 Commits

Author SHA1 Message Date
Cheng Zhao
b4e836bf2e Bump v0.30.4 2015-08-10 16:50:48 +08:00
Cheng Zhao
a296b4ef33 Merge pull request #2465 from atom/fix-incept-scheme
Force request context to initialize beforing incepting protocol
2015-08-10 15:47:12 +08:00
Cheng Zhao
140ba2858a Fix cpplint warnings 2015-08-10 15:37:03 +08:00
Cheng Zhao
3379641fe2 Force request context to initialize beforing incepting protocol 2015-08-10 15:31:29 +08:00
Cheng Zhao
0644129fbe Pass net::URLRequestContextGetter in scoped_refptr 2015-08-10 15:28:18 +08:00
Cheng Zhao
c295979270 BrowserContext::GetRequestContext can only be called on UI thread 2015-08-10 15:02:16 +08:00
Cheng Zhao
e4a7352b62 Merge pull request #2462 from atom/tray-event
More fixes of Tray
2015-08-10 13:45:35 +08:00
Cheng Zhao
33eadad139 popContextMenu => popUpContextMenu 2015-08-10 13:00:15 +08:00
Cheng Zhao
225140bd64 win: Don't emit right-clicked event when there is menu attached 2015-08-10 12:52:55 +08:00
Cheng Zhao
58dee04d5c mac: Redraw icon when menu is closed 2015-08-10 12:52:35 +08:00
Cheng Zhao
4b9ff309ec Add our own MenuModel class 2015-08-10 12:39:05 +08:00
Cheng Zhao
a3f3a35fd1 mac: Don't emit "clicked" event if there is menu attached 2015-08-10 12:18:00 +08:00
Cheng Zhao
aa03eb5b6c Merge pull request #2461 from atom/fix-webview-crash
Delay the call of element resize callback to next tick
2015-08-10 12:07:58 +08:00
Cheng Zhao
ebe70435ef Merge pull request #2460 from atom/iojs-new-headers
Upload node headers with new filenames
2015-08-10 12:00:17 +08:00
Cheng Zhao
0a49dcc623 Delay the call of element resize callback to next tick 2015-08-10 11:56:42 +08:00
Cheng Zhao
52d07eb30f Update checksums for new filenames 2015-08-10 11:42:14 +08:00
Cheng Zhao
70be04a2d3 Upload headers with new filenames 2015-08-10 11:28:43 +08:00
Cheng Zhao
eaaf52483e Merge pull request #2443 from ialexryan/patch-1
Fixed typo
2015-08-10 11:22:06 +08:00
Cheng Zhao
ebfd03570f Merge pull request #2456 from etiktin/update_build_md
Add a comment to build instructions about cpplint
2015-08-10 11:21:51 +08:00
Eran Tiktin
de441916d6 Add a comment to build instructions about cpplint
I added a mention of `cpplint.py` in the build instructions.
The reason, is because it's easy to miss it's existence. Even if you
noticed it's mentioned in `coding-style.md` you might mistakenly think
that `test.py` runs it).
2015-08-08 23:25:27 +03:00
Cheng Zhao
0bf5effe58 Bump v0.30.3 2015-08-07 22:04:59 +08:00
Cheng Zhao
b65e089028 Merge pull request #2447 from atom/fix-microtask-checkpoint
Make sure microtask checkpoint is performed after Node.js calls
2015-08-07 22:03:51 +08:00
Cheng Zhao
c51f349dfa Run microtask before handling pending process.nextTick tasks
This follows the behavior of Node.js.
2015-08-07 21:26:24 +08:00
Cheng Zhao
1bb0dde360 Use WebScopedRunV8Script in converted C++ functions 2015-08-07 19:37:17 +08:00
Cheng Zhao
5c18d89453 Reimplement callback.h with C++11 2015-08-07 19:35:35 +08:00
Cheng Zhao
2ff104d012 Move callback converter from native mate to electron 2015-08-07 19:35:35 +08:00
Cheng Zhao
3402871741 spec: Check the time when Promise's callback is called 2015-08-07 19:35:35 +08:00
Cheng Zhao
74fa2c809d Make every JS function call is wrapped with V8RecursionScope 2015-08-07 19:35:35 +08:00
Cheng Zhao
ab44edd294 Perform microtask checkpoint after diving into libuv 2015-08-07 19:35:35 +08:00
Cheng Zhao
5d3445cebb Style fix 2015-08-07 19:35:35 +08:00
Cheng Zhao
24ba712aa5 Update libchromiumcontent to have WebScopedRunV8Script 2015-08-07 19:35:34 +08:00
Alex Ryan
fb60f7946f Fixed typo 2015-08-06 22:15:59 -07:00
Cheng Zhao
744059b8bd Check button size 2015-08-06 15:22:17 +08:00
Cheng Zhao
8864498065 Merge pull request #2431 from atom/clean-up-native-window-2
Clean up NativeWindow code, phase 2
2015-08-06 13:25:35 +08:00
Cheng Zhao
454085eb95 Fix cpplint warning 2015-08-06 13:07:39 +08:00
Cheng Zhao
6e75af5c0f Move SetOverlayIcon to TaskbarHost 2015-08-06 13:07:00 +08:00
Cheng Zhao
8da7803f3e Save the taskbar object 2015-08-06 12:58:40 +08:00
Cheng Zhao
2d6f8350cb Move SetProgressBar to TaskbarHost 2015-08-06 12:54:00 +08:00
Cheng Zhao
958658513c Refactor code in taskbarHost 2015-08-06 12:44:07 +08:00
Cheng Zhao
a28f70e85c Decouple TaskbarHost from NativeWindow 2015-08-06 11:10:34 +08:00
Cheng Zhao
8f8c3aef87 ThumbarHost => TaskbarHost 2015-08-06 10:30:22 +08:00
Cheng Zhao
39af10cc8d Move thumbar_host_ from TreeHost to NativeWindow 2015-08-06 10:25:50 +08:00
Cheng Zhao
d175a68586 Add MessageHandlerDelegate 2015-08-06 10:15:27 +08:00
Cheng Zhao
f740684f41 Merge pull request #2400 from atom/thumbar_button
Implement API for supporting thumbnail toolbars
2015-08-06 09:55:26 +08:00
Cheng Zhao
20a8e7838f Merge pull request #2424 from deepak1556/web_contents_patch
webcontents: minor patches
2015-08-06 09:52:16 +08:00
Haojian Wu
2f1cb8b52a Expose NativeWindow.setThumbarButtons API to all platforms. 2015-08-05 22:30:05 +08:00
Robo
0a7a4c0d0a webview: adding load-commit event 2015-08-05 19:22:30 +05:30
Robo
6b8d4a43a3 override: intialise BrowserWindowProxy.closed 2015-08-05 19:22:30 +05:30
Haojian Wu
78eac4116c Polish thumbar code.
* Fix a memory leak in thumbar initialization.
* Check the number of thumbar buttons, should be <= 7.
* Correct to check thumbar button click event.
2015-08-05 19:38:12 +08:00
Cheng Zhao
5a2f94f415 Merge pull request #2423 from atom/fix-release-leak
Fix memory leak when creating NativeImage
2015-08-05 15:55:52 +08:00
Cheng Zhao
2f04f76e69 ImageSkiaRep doesn't release memory 2015-08-05 15:49:37 +08:00
Cheng Zhao
b8d364f11e Merge pull request #2422 from atom/resizable-resize
mac: Disable resizing window when changing style mask
2015-08-05 14:44:31 +08:00
Cheng Zhao
5871428c83 spec: BrowserWindow.setResizable should not change window size 2015-08-05 14:25:53 +08:00
Cheng Zhao
1505dc207b mac: Disable resizing window when changing style mask 2015-08-05 14:12:55 +08:00
Haojian Wu
dfd076a3e5 Move atom_desktop_window_tree_host_win to atom/browser/ui/win directory. 2015-08-05 13:55:06 +08:00
Haojian Wu
ad01a1731a 📝 say more about thumbnail toolbar. 2015-08-05 13:55:04 +08:00
Haojian Wu
97ab780305 📝 BrowserWindow.setThumbarButton API. 2015-08-05 13:55:04 +08:00
Haojian Wu
54af048f04 win: Add BrowserWindow.setThumbarButtons API. 2015-08-05 13:55:02 +08:00
Cheng Zhao
488a69d461 Merge pull request #2419 from atom/clean-native-window
Clean up NativeWindow code
2015-08-05 13:28:09 +08:00
Cheng Zhao
bbd6c927b1 Remove a few unused headers 2015-08-05 13:18:41 +08:00
Cheng Zhao
adbb909b39 Move ShouldUseGlobalMenuBar to x_window_utils 2015-08-05 13:16:03 +08:00
Cheng Zhao
58b1172025 Avoid exposing data members to subclass 2015-08-05 12:46:32 +08:00
Cheng Zhao
438a5acc0f Use ranged for loop 2015-08-05 12:34:45 +08:00
Cheng Zhao
58c0486236 Remove duplicate UpdateDraggableRegions 2015-08-05 12:32:22 +08:00
Cheng Zhao
1c4f50b2df Merge pull request #2418 from deepak1556/content_tracing_api_patch
tracing: fix api and docs
2015-08-05 10:42:18 +08:00
Cheng Zhao
dc60bfa885 Merge pull request #2410 from atom/pop_context_menu_issue
Check context menu when calling popContextMenu API.
2015-08-05 10:04:26 +08:00
Robo
3b05b135a5 tracing: fix api and docs 2015-08-05 02:29:55 +05:30
Cheng Zhao
6b65a66119 Update brightray for #2263 2015-08-04 22:53:03 +08:00
Cheng Zhao
97c15c463e Merge pull request #2412 from atom/dialog-title
win: Use app name as default title of message box
2015-08-04 22:52:20 +08:00
Cheng Zhao
50f226e34e win: Use app name as default title of message box
TaskDialogIndirect doesn't allow empty name, if we set empty title
it will show "electron.exe" in title.
2015-08-04 21:57:00 +08:00
Cheng Zhao
2d18f91e57 Merge pull request #2411 from atom/fix-crash-reporter
Fix crash reporter process not exiting if there is another one running
2015-08-04 21:22:18 +08:00
Machisté N. Quintana
7910fe7785 Only build pushes on Travis for master branch [ci skip] 2015-08-04 08:27:17 -04:00
Haojian Wu
613e5c77ea Check context menu when calling popContextMenu API. 2015-08-04 19:45:44 +08:00
Cheng Zhao
c872b1a770 Use different name for window class name 2015-08-04 19:35:46 +08:00
Cheng Zhao
db58048077 Use different name for wait events for different apps 2015-08-04 19:30:35 +08:00
Cheng Zhao
14803e4cf8 Close handle when waiting is end 2015-08-04 19:18:12 +08:00
Cheng Zhao
1347c61c8e Set AppUserModelID for all renderer processes 2015-08-04 17:13:05 +08:00
Cheng Zhao
69b20d25ee Update brightray for #2294 2015-08-04 16:48:10 +08:00
Cheng Zhao
9642cd286e Merge pull request #2408 from atom/window-opener
Only set window.opener for windows opened by window.open
2015-08-04 16:13:09 +08:00
Cheng Zhao
2a30520799 Only set window.opener for windows opened by window.open 2015-08-04 15:47:12 +08:00
Cheng Zhao
039d4aaecb spec: Test window.opener 2015-08-04 15:46:59 +08:00
Cheng Zhao
9e922dd0c7 spec: Don't set window to fullscreen unless under travis 2015-08-04 15:40:31 +08:00
Cheng Zhao
4ac59e2674 Merge pull request #2391 from seanchas116/support-remote-promise
Support Promise over remote objects
2015-08-03 15:22:36 +08:00
Cheng Zhao
7c5d443284 Merge pull request #2394 from DerNivel/fix-typos
Fix typos
2015-08-03 15:04:13 +08:00
Cheng Zhao
666a2233a7 Merge pull request #2389 from atom/resize-mask-flag
Fix a bug calling setResizable multiple times will take no effect on OS X.
2015-08-03 14:52:40 +08:00
Cheng Zhao
7c75329b18 Merge pull request #2375 from deepak1556/web_frame_api_patch
webFrame: api to make scheme bypass CSP
2015-08-03 14:46:40 +08:00
Cheng Zhao
e135bcb5b7 docs: userGesture is optional 2015-08-03 14:43:01 +08:00
Cheng Zhao
d455232eb1 Merge pull request #2383 from deepak1556/render_script_execution_patch
render: executejavascript with option to create usergesture context
2015-08-03 14:37:29 +08:00
Ryohei Ikegami
c8a794ac34 Use constructor name to check if Promise 2015-08-01 12:20:16 +09:00
Jonathan
c0ce8723d4 Fix typo 2015-07-31 20:16:26 +02:00
Jonathan
9dab6e02ca Fix typo 2015-07-31 20:14:50 +02:00
Robo
9fb03d584c add spec and fix docs 2015-07-31 12:30:17 +05:30
Ryohei Ikegami
428ad20807 Change spec to test Promise in both side 2015-07-31 14:52:48 +09:00
Ryohei Ikegami
92af275f98 Support remote Promise in browser 2015-07-31 14:52:48 +09:00
Ryohei Ikegami
c7d1f4f6b2 Add spec for remote Promise 2015-07-31 14:52:48 +09:00
Ryohei Ikegami
ddf2cfd48d Support remote Promise in renderer 2015-07-31 14:52:37 +09:00
Haojian Wu
c69002b0dd Fix: browser window will be resiable when calling window.setResizable(false) twice. 2015-07-31 09:57:08 +08:00
Robo
92ea533aee webFrame: api to make scheme bypass CSP 2015-07-30 22:36:02 +05:30
Robo
239d535cac render: executejavascript with option to simulate usergesture 2015-07-30 15:38:46 +05:30
Cheng Zhao
2eaaad610d Merge pull request #2382 from jiaz/patch-3
Add missing dependency for ubuntu build
2015-07-30 16:53:57 +08:00
Jiaji Zhou
e0a117414b Add missing dependency for ubuntu build
I tried to follow the document to build electron on a fresh clean built Ubuntu 15.04.
I encountered the following error message when trying to run ./script/bootstrap.py -v

Package nss was not found in the pkg-config search path. 
Perhaps you should add the directory containing `nss.pc' 
to the PKG_CONFIG_PATH environment variable 
No package 'nss' found 

After installing libnss3-dev, the build can pass.
2015-07-30 01:21:17 -07:00
Cheng Zhao
2ab079dc7d Bump v0.30.2 2015-07-30 14:17:43 +08:00
Cheng Zhao
03e03a5daa Merge pull request #2381 from atom/my-status-item
mac: Make the tray icon behave more like the official one
2015-07-30 14:17:26 +08:00
Cheng Zhao
be24d3e78c mac: Make the tray icon behave more like the official one 2015-07-30 13:58:53 +08:00
Cheng Zhao
0e779e20c3 Fix compilation error caused by #2340 2015-07-30 10:38:04 +08:00
Cheng Zhao
2d5c0ac9ee Coffeescript declares variable before assigning it 2015-07-30 10:31:49 +08:00
Cheng Zhao
8d09f13bad Fix running callback when global.global is deleted
Close #2366.
2015-07-30 10:28:24 +08:00
Cheng Zhao
b68356b9b9 Merge pull request #2377 from CtrlVP/master
Replaced 'browser' with 'main'
2015-07-30 09:39:53 +08:00
Cheng Zhao
764a6e1d76 Merge pull request #2376 from timruffles/patch-2
more accuracy around why to use ASAR
2015-07-30 09:39:36 +08:00
Cheng Zhao
bbce2c7e2f Merge pull request #2372 from atom/allow-insecure-content
Add allowing-insecure-content option
2015-07-30 09:38:27 +08:00
Vivek Patel
2ded7497b6 Merge pull request #1 from CtrlVP/CtrlVP-patch-1
Replaced 'browser' with 'main'
2015-07-29 15:09:34 +02:00
Vivek Patel
90bd32c680 Replaced 'browser' with 'main'
"A JavaScript error occured in the browser process" is confusing. Replacing it with 'main', just like everywhere else.
2015-07-29 15:04:34 +02:00
Tim Ruffles
f9d5915542 more accuracy around why to use ASAR
'protect' implies a lot more security than ASAR provides (none). I asked around #2374 to get some understanding of what ASAR does do for you.
2015-07-29 13:45:30 +01:00
Cheng Zhao
643ed27fd4 Check whether entry is null
This fixes the crash in #7877.
2015-07-29 18:26:20 +08:00
Haojian Wu
f154da38e6 Make 'allow-displaying-insecure-content' and
'allow-running-insecure-content' higher priority than `web-security`.
2015-07-29 18:08:44 +08:00
Cheng Zhao
046a8e8a08 Merge pull request #2368 from dataich/master
do not overwrite `node-integration` option
2015-07-29 17:25:30 +08:00
Cheng Zhao
80f45f6226 Merge pull request #2370 from atom/osx-tray
Use NSImageView to draw tray icon.
2015-07-29 17:22:47 +08:00
Cheng Zhao
898a838ad7 Merge pull request #2340 from atom/set_download_path_api
Implement setDownloadPath API.
2015-07-29 17:19:02 +08:00
Cheng Zhao
b311969f0e Update brightray for #2327 2015-07-29 17:16:23 +08:00
Cheng Zhao
d719244d1e Merge pull request #2327 from deepak1556/devtools_api_patch
webContents: api to add/remove path from devtools workspace
2015-07-29 17:16:02 +08:00
Haojian Wu
1d0568dd5b 📝 allow-running-insecure-content and
`allow-displaying-insecure-content`.
2015-07-29 16:17:14 +08:00
Haojian Wu
77a8a3d33c Add allow-running-insecure-content, allow-display-insecure-content
in BrowserWindow option.
2015-07-29 16:15:03 +08:00
Cheng Zhao
d5893d8c9f Merge pull request #2369 from atom/better-modifiers
Fix a few things of Tray
2015-07-29 15:22:27 +08:00
Cheng Zhao
409c6155c2 Merge pull request #2363 from atom/mime-check
Fix a missing the specified mime type check in <input> accept attribute.
2015-07-29 14:52:20 +08:00
Cheng Zhao
b786772819 Update brightray for #2324 2015-07-29 14:50:56 +08:00
Cheng Zhao
b2f03fc2d8 Add metaKey 2015-07-29 14:44:08 +08:00
Cheng Zhao
3e1a5b229c docs: modifiers removed 2015-07-29 14:27:32 +08:00
Cheng Zhao
8d22eeb3be Use DOM's way of telling modifiers 2015-07-29 14:25:12 +08:00
Cheng Zhao
625143426a Enable using custom events when emitting 2015-07-29 14:24:45 +08:00
Haojian Wu
f40155645c 📝 say more about setDownloadPath API. 2015-07-29 14:13:28 +08:00
Haojian Wu
877830e4a1 No need for default_download_path_ member. 2015-07-29 14:04:14 +08:00
Haojian Wu
45f5a10d5d Use NSImageView to draw tray icon.
* Fixes Tempate image doesn't show correctly in dark mode.
* Fixes the tray icon is stretched showing in menubar.
* Fixes title color will not reversed in dark mode.
2015-07-29 13:45:01 +08:00
Cheng Zhao
d42fd6fc7e win: Pass modifers in 'clicked' events 2015-07-29 13:10:51 +08:00
Cheng Zhao
74248253f5 win: Set GUID when getting icon's bounds 2015-07-29 12:55:44 +08:00
Cheng Zhao
15273c1f7a docs: Don't say things that are expected 2015-07-29 12:41:40 +08:00
Taichiro Yoshida
fc92ceb0b6 do not overwrite node-integration option
If `node-integration` option pass to window.open, do not overwrite by current window's one
2015-07-29 13:41:11 +09:00
Cheng Zhao
9afa94f4b8 win: Implement double-clicked event 2015-07-29 12:36:01 +08:00
Cheng Zhao
edde653d60 Merge branch 'feature/modifiers-click-tray' of https://github.com/nishanths/electron into nishanths-feature/modifiers-click-tray 2015-07-29 12:19:17 +08:00
Robo
66553eea1a webContents: api to add/remove path from devtools workspace 2015-07-29 09:29:38 +05:30
Cheng Zhao
2c97cd64cf Minor style fix for #2352 2015-07-29 11:48:40 +08:00
Cheng Zhao
ff6b9d0907 Merge pull request #2352 from nishanths/feature/native-image-is-template
Add NativeImage.isTemplateImage method
2015-07-29 11:47:00 +08:00
Cheng Zhao
c500c9b289 Merge pull request #2349 from atom/mq-run-your-app
Reorganize the Run Your App section
2015-07-29 11:46:02 +08:00
Cheng Zhao
9afb973498 Merge pull request #2347 from deepak1556/fetch_job_headers_patch
protocol: fix request headers in urlRequestFetchJob
2015-07-29 11:44:47 +08:00
Cheng Zhao
1bc49487ad Merge pull request #2314 from UsabilityEtc/update-api-docs
Update api docs
2015-07-29 11:35:14 +08:00
Cheng Zhao
f485a9894c Merge pull request #2318 from craigshoemaker/patch-1
📝 Windows/Linux compatibility changes
2015-07-29 11:34:46 +08:00
Cheng Zhao
c140077d53 Merge pull request #2338 from atom/page_size_option
Add 'pageSize' option in printToPDF API.
2015-07-29 11:32:49 +08:00
Cheng Zhao
42ce91323c docs: Small style fix for #2337 2015-07-29 11:28:20 +08:00
Cheng Zhao
0ca9dfbc12 Merge pull request #2337 from nishanths/feature/bounds-tray-dblclick
Send bounding Rect on tray double click events
2015-07-29 11:27:04 +08:00
Cheng Zhao
b08af89473 Style fix for #2328 2015-07-29 11:22:12 +08:00
Cheng Zhao
b9cf0f2126 Merge pull request #2328 from atom/tray-settings-propagate
Propagate User App Model ID to Tray Icon
2015-07-29 11:08:35 +08:00
Jeffrey Morgan
b10560a5b0 Fix typo in auto-updater.md 2015-07-28 16:51:41 +01:00
Cheng Zhao
f4d8e32c9f Merge pull request #2350 from matiasinsaurralde/master
Basic Spanish docs
2015-07-28 16:22:11 +08:00
Haojian Wu
617bff8ec8 Fix a missing the specified mime type check in <input> accept attribute. 2015-07-28 10:32:13 +08:00
Nishanth Shanmugham
a44f14d76e Fix code formatting issues 2015-07-27 03:33:15 -07:00
Nishanth Shanmugham
74b4522195 Add keyboard modifiers payload to tray click events
* Add keyboard and mouse button bitsum to Tray click events payload
* Move getBoundsFromRect: to common event_util file
* Update documentation
2015-07-27 03:15:51 -07:00
Nishanth Shanmugham
99a8f29de9 Move event type functions to a common event_util file 2015-07-27 00:41:20 -07:00
Nishanth Shanmugham
51111430b3 Add NativeImage docs for IsTemplateImage 2015-07-26 21:59:43 -07:00
Nishanth Shanmugham
9211109088 Add NativeImage.IsTemplateImage method
* Rename internal function that determines template image filename patterns
* Add the new IsTemplateMethod
2015-07-26 21:58:48 -07:00
Matias Insaurralde
ad7e4a77db custom dom texts 2015-07-26 22:59:19 -04:00
Matias Insaurralde
faf10183d8 first docs 2015-07-26 22:57:43 -04:00
Haojian Wu
59c3efd44b Correct the override comment. 2015-07-27 09:09:32 +08:00
Machisté N. Quintana
f2b2c58758 📝 🎨 Grammar fix 2015-07-26 20:31:01 -04:00
Machisté N. Quintana
b6f6bf9778 📝 Reorganize the Run Your App section 2015-07-26 20:26:10 -04:00
Robo
b0e73532de protocol: fix request headers in urlRequestFetchJob 2015-07-27 02:51:41 +05:30
Haojian Wu
7f0cb0ce1b 📝 session.setDownloadPath API. 2015-07-26 16:52:02 +08:00
Haojian Wu
fef53d18c4 Add session.setDownloadPath API. 2015-07-26 16:51:27 +08:00
Haojian Wu
2aa17debc8 prefs' key needs to be registered before using. 2015-07-26 16:17:55 +08:00
Haojian Wu
0700f08d6d Copy pref_names files from Chromium. 2015-07-26 16:08:29 +08:00
Nishanth Shanmugham
1a074bb148 Update tray double-click docs
* Mention bounds payload
2015-07-25 21:16:15 -07:00
Haojian Wu
74f2e9f102 📝 pageSize option. 2015-07-26 11:57:53 +08:00
Nishanth Shanmugham
f53995d555 Send bounding Rect on tray double click events 2015-07-25 20:56:35 -07:00
Haojian Wu
9eeebedf5f Add pageSize option in printToPDF API. 2015-07-26 11:55:52 +08:00
Paul Betts
5e61974c24 Set NIF_GUID if we have a GUID 2015-07-24 08:05:36 -07:00
Craig Shoemaker
d485cfbca3 Fixed typo 2015-07-24 06:53:55 -07:00
Paul Betts
70feb08f84 Fix linting issues 2015-07-24 03:30:23 -07:00
Paul Betts
75b08f510e Fix up namespaces 2015-07-24 03:27:15 -07:00
Paul Betts
08383a69ce Propagate User App Model ID to Tray Icon
This PR prevents dozens of items showing up in the notification area
preferences when using Squirrel for Windows, by ensuring that
notification tray items are tied to the User App Model ID.
2015-07-24 03:10:03 -07:00
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
Jeffrey Morgan
4de4ef1ccc Remove change to "mapped onto" in accelerator.md
Remove the change to “mapped onto” in `accelerator.md` after feedback
from @OlsonDev.
2015-07-24 07:19:43 +01: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
Craig Shoemaker
959f5d61b7 Windows/Linux compatibility changes
- Updated accelerator to cross platform values
- Added a warning to non-Mac users regarding the selector option
2015-07-23 15:04:43 -07:00
Jeffrey Morgan
d9ee8519e9 Correct error in chrome-command-line-switches.md
Replace “to” with “in” to correct the error identified in
`chrome-command-line-switches.md` by @OlsonDev.
2015-07-23 20:45:08 +01:00
Yifei Teng
8960aa956c Only allow extensions explicitly specified by the user. Fixes #2296 2015-07-23 12:30:07 -07:00
Jeffrey Morgan
8b4815fd95 Improve grammar and punctuation of crash-reporter.md
Improve the grammar, sentence structure, punctuation and formatting of
`crash-reporter.md`.
2015-07-23 18:02:45 +01:00
Jeffrey Morgan
32b84bd3f9 Improve grammar and punctuation of clipboard.md
Improve the grammar, sentence structure, punctuation and formatting of
`clipboard.md`.
2015-07-23 18:01:00 +01:00
Jeffrey Morgan
adab769700 Improve grammar and punctuation of chrome-command-line-switches.md
Improve the grammar, sentence structure, punctuation and formatting of
`chrome-command-line-switches.md`
2015-07-23 17:59:51 +01:00
Jeffrey Morgan
d138c2970c Improve grammar and punctuation of auto-updater.md
Improve the grammar, sentence structure, punctuation and formatting of
`auto-updater.md`.
2015-07-23 17:57:42 +01:00
Jeffrey Morgan
452619990e Improve grammar and punctuation of accelerator.md
Improve the grammar, sentence structure, punctuation and formatting of
`accelerator.md`.
2015-07-23 17:55:57 +01: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
Matias Insaurralde
73790fcef5 preparing README-es 2015-07-19 17:39:59 -04:00
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
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
245 changed files with 9449 additions and 1969 deletions

View File

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

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.1',
'version%': '0.30.4',
},
'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

@@ -17,6 +17,7 @@
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/browser.h"
#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "base/command_line.h"
#include "base/environment.h"
@@ -25,7 +26,6 @@
#include "brightray/browser/brightray_paths.h"
#include "content/public/browser/client_certificate_delegate.h"
#include "content/public/browser/gpu_data_manager.h"
#include "native_mate/callback.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
#include "net/ssl/ssl_cert_request_info.h"

View File

@@ -5,10 +5,11 @@
#include <set>
#include <string>
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "base/bind.h"
#include "base/files/file_util.h"
#include "content/public/browser/tracing_controller.h"
#include "native_mate/callback.h"
#include "native_mate/dictionary.h"
#include "atom/common/node_includes.h"
@@ -46,6 +47,31 @@ struct Converter<base::trace_event::TraceOptions> {
namespace {
using CompletionCallback = base::Callback<void(const base::FilePath&)>;
scoped_refptr<TracingController::TraceDataSink> GetTraceDataSink(
const base::FilePath& path, const CompletionCallback& callback) {
base::FilePath result_file_path = path;
if (result_file_path.empty() && !base::CreateTemporaryFile(&result_file_path))
LOG(ERROR) << "Creating temporary file failed";
return TracingController::CreateFileSink(result_file_path,
base::Bind(callback,
result_file_path));
}
void StopRecording(const base::FilePath& path,
const CompletionCallback& callback) {
TracingController::GetInstance()->DisableRecording(
GetTraceDataSink(path, callback));
}
void CaptureMonitoringSnapshot(const base::FilePath& path,
const CompletionCallback& callback) {
TracingController::GetInstance()->CaptureMonitoringSnapshot(
GetTraceDataSink(path, callback));
}
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Local<v8::Context> context, void* priv) {
auto controller = base::Unretained(TracingController::GetInstance());
@@ -54,14 +80,12 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
&TracingController::GetCategories, controller));
dict.SetMethod("startRecording", base::Bind(
&TracingController::EnableRecording, controller));
dict.SetMethod("stopRecording", base::Bind(
&TracingController::DisableRecording, controller, nullptr));
dict.SetMethod("stopRecording", &StopRecording);
dict.SetMethod("startMonitoring", base::Bind(
&TracingController::EnableMonitoring, controller));
dict.SetMethod("stopMonitoring", base::Bind(
&TracingController::DisableMonitoring, controller));
dict.SetMethod("captureMonitoringSnapshot", base::Bind(
&TracingController::CaptureMonitoringSnapshot, controller, nullptr));
dict.SetMethod("captureMonitoringSnapshot", &CaptureMonitoringSnapshot);
dict.SetMethod("getTraceBufferUsage", base::Bind(
&TracingController::GetTraceBufferUsage, controller));
dict.SetMethod("setWatchEvent", base::Bind(

View File

@@ -4,13 +4,14 @@
#include "atom/browser/api/atom_api_cookies.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/native_mate_converters/value_converter.h"
#include "base/bind.h"
#include "base/time/time.h"
#include "base/values.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "native_mate/callback.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
#include "net/cookies/cookie_monster.h"
@@ -179,8 +180,8 @@ namespace atom {
namespace api {
Cookies::Cookies(content::BrowserContext* browser_context) :
browser_context_(browser_context) {
Cookies::Cookies(content::BrowserContext* browser_context)
: request_context_getter_(browser_context->GetRequestContext()) {
}
Cookies::~Cookies() {
@@ -198,11 +199,9 @@ void Cookies::Get(const base::DictionaryValue& options,
void Cookies::GetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> filter,
const CookiesCallback& callback) {
net::CookieStore* cookie_store = browser_context_->GetRequestContext()
->GetURLRequestContext()->cookie_store();
std::string url;
filter->GetString("url", &url);
if (!GetCookieListFromStore(cookie_store, url,
if (!GetCookieListFromStore(GetCookieStore(), url,
base::Bind(&Cookies::OnGetCookies, base::Unretained(this),
Passed(&filter), callback))) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
@@ -245,9 +244,7 @@ void Cookies::Remove(const mate::Dictionary& details,
void Cookies::RemoveCookiesOnIOThread(const GURL& url, const std::string& name,
const CookiesCallback& callback) {
net::CookieStore* cookie_store = browser_context_->GetRequestContext()
->GetURLRequestContext()->cookie_store();
cookie_store->DeleteCookieAsync(url, name,
GetCookieStore()->DeleteCookieAsync(url, name,
base::Bind(&Cookies::OnRemoveCookies, base::Unretained(this), callback));
}
@@ -286,8 +283,6 @@ void Cookies::SetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> details,
const GURL& url,
const CookiesCallback& callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
net::CookieStore* cookie_store = browser_context_->GetRequestContext()
->GetURLRequestContext()->cookie_store();
std::string name, value, domain, path;
bool secure = false;
@@ -308,7 +303,7 @@ void Cookies::SetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> details,
base::Time::FromDoubleT(expiration_date);
}
cookie_store->GetCookieMonster()->SetCookieWithDetailsAsync(
GetCookieStore()->GetCookieMonster()->SetCookieWithDetailsAsync(
url,
name,
value,
@@ -337,6 +332,10 @@ mate::ObjectTemplateBuilder Cookies::GetObjectTemplateBuilder(
.SetMethod("set", &Cookies::Set);
}
net::CookieStore* Cookies::GetCookieStore() {
return request_context_getter_->GetURLRequestContext()->cookie_store();
}
// static
mate::Handle<Cookies> Cookies::Create(
v8::Isolate* isolate,

View File

@@ -8,17 +8,27 @@
#include <string>
#include "base/callback.h"
#include "base/values.h"
#include "native_mate/wrappable.h"
#include "native_mate/handle.h"
#include "native_mate/dictionary.h"
#include "net/cookies/canonical_cookie.h"
namespace base {
class DictionaryValue;
}
namespace content {
class BrowserContext;
}
namespace mate {
class Dictionary;
}
namespace net {
class CookieStore;
class URLRequestContextGetter;
}
namespace atom {
namespace api {
@@ -60,13 +70,15 @@ class Cookies : public mate::Wrappable {
void OnSetCookies(const CookiesCallback& callback,
bool set_success);
// mate::Wrappable implementations:
// mate::Wrappable:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
private:
content::BrowserContext* browser_context_;
// Must be called on IO thread.
net::CookieStore* GetCookieStore();
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
DISALLOW_COPY_AND_ASSIGN(Cookies);
};

View File

@@ -10,9 +10,9 @@
#include "atom/browser/native_window.h"
#include "atom/browser/ui/file_dialog.h"
#include "atom/browser/ui/message_box.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/image_converter.h"
#include "native_mate/callback.h"
#include "native_mate/dictionary.h"
#include "atom/common/node_includes.h"
@@ -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,8 +7,8 @@
#include <string>
#include "atom/common/native_mate_converters/accelerator_converter.h"
#include "atom/common/native_mate_converters/callback.h"
#include "base/stl_util.h"
#include "native_mate/callback.h"
#include "native_mate/dictionary.h"
#include "atom/common/node_includes.h"

View File

@@ -6,9 +6,9 @@
#include "atom/browser/native_window.h"
#include "atom/common/native_mate_converters/accelerator_converter.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/image_converter.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "native_mate/callback.h"
#include "native_mate/constructor.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
@@ -20,7 +20,7 @@ namespace atom {
namespace api {
Menu::Menu()
: model_(new ui::SimpleMenuModel(this)),
: model_(new AtomMenuModel(this)),
parent_(NULL) {
}

View File

@@ -8,9 +8,9 @@
#include <string>
#include "atom/browser/api/atom_api_window.h"
#include "atom/browser/ui/atom_menu_model.h"
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "ui/base/models/simple_menu_model.h"
#include "native_mate/wrappable.h"
namespace atom {
@@ -18,7 +18,7 @@ namespace atom {
namespace api {
class Menu : public mate::Wrappable,
public ui::SimpleMenuModel::Delegate {
public AtomMenuModel::Delegate {
public:
static mate::Wrappable* Create();
@@ -33,7 +33,7 @@ class Menu : public mate::Wrappable,
static void SendActionToFirstResponder(const std::string& action);
#endif
ui::SimpleMenuModel* model() const { return model_.get(); }
AtomMenuModel* model() const { return model_.get(); }
protected:
Menu();
@@ -42,7 +42,7 @@ class Menu : public mate::Wrappable,
// mate::Wrappable:
void AfterInit(v8::Isolate* isolate) override;
// ui::SimpleMenuModel::Delegate implementations:
// ui::SimpleMenuModel::Delegate:
bool IsCommandIdChecked(int command_id) const override;
bool IsCommandIdEnabled(int command_id) const override;
bool IsCommandIdVisible(int command_id) const override;
@@ -54,7 +54,7 @@ class Menu : public mate::Wrappable,
virtual void Popup(Window* window) = 0;
virtual void PopupAt(Window* window, int x, int y) = 0;
scoped_ptr<ui::SimpleMenuModel> model_;
scoped_ptr<AtomMenuModel> model_;
Menu* parent_;
private:
@@ -102,9 +102,9 @@ class Menu : public mate::Wrappable,
namespace mate {
template<>
struct Converter<ui::SimpleMenuModel*> {
struct Converter<atom::AtomMenuModel*> {
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
ui::SimpleMenuModel** out) {
atom::AtomMenuModel** out) {
// null would be tranfered to NULL.
if (val->IsNull()) {
*out = nullptr;

View File

@@ -7,12 +7,13 @@
#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/callback.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "content/public/browser/browser_thread.h"
#include "native_mate/callback.h"
#include "native_mate/dictionary.h"
#include "net/url_request/url_request_context.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())
@@ -36,7 +37,6 @@ struct Converter<const net::URLRequest*> {
} // namespace mate
namespace atom {
namespace api {
@@ -63,16 +63,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.
@@ -131,9 +128,23 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
dict.Get("method", &method);
dict.Get("referrer", &referrer);
v8::Local<v8::Value> value;
mate::Handle<Session> session;
scoped_refptr<net::URLRequestContextGetter> request_context_getter;
// "session" null -> pass nullptr;
// "session" a Session object -> use passed session.
// "session" undefined -> use current session;
if (dict.Get("session", &session))
request_context_getter =
session->browser_context()->GetRequestContext();
else if (dict.Get("session", &value) && value->IsNull())
request_context_getter = nullptr;
else
request_context_getter = registry_->request_context_getter();
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&AdapterRequestJob::CreateHttpJobAndStart, GetWeakPtr(),
registry_->browser_context(), url, method, referrer));
request_context_getter, url, method, referrer));
return;
}
}
@@ -152,6 +163,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,10 +208,30 @@ 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)
: browser_context_(browser_context),
: request_context_getter_(browser_context->GetRequestContext()),
job_factory_(browser_context->job_factory()) {
CHECK(job_factory_);
}
@@ -202,42 +241,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 +272,131 @@ 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);
// Force the request context to initialize, otherwise we might have nothing
// to intercept.
request_context_getter_->GetURLRequestContext();
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,9 +12,11 @@
#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;
class URLRequestContextGetter;
}
namespace atom {
@@ -26,15 +28,28 @@ 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);
JsProtocolHandler GetProtocolHandler(const std::string& scheme);
AtomBrowserContext* browser_context() const { return browser_context_; }
net::URLRequestContextGetter* request_context_getter() {
return request_context_getter_.get();
}
protected:
explicit Protocol(AtomBrowserContext* browser_context);
@@ -46,37 +61,44 @@ 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);
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);
// Do protocol.emit(event, parameter) under UI thread.
void EmitEventInUI(const std::string& event, const std::string& parameter);
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
AtomBrowserContext* browser_context_;
AtomURLRequestJobFactory* job_factory_;
ProtocolHandlersMap protocol_handlers_;

View File

@@ -5,22 +5,104 @@
#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/callback.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "base/files/file_path.h"
#include "base/prefs/pref_service.h"
#include "base/strings/string_util.h"
#include "base/thread_task_runner_handle.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
#include "native_mate/callback.h"
#include "native_mate/dictionary.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 +162,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(
const scoped_refptr<net::URLRequestContextGetter>& context_getter,
const net::CompletionCallback& callback) {
auto request_context = context_getter->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 +224,43 @@ 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,
make_scoped_refptr(browser_context_->GetRequestContext()),
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));
}
void Session::SetDownloadPath(const base::FilePath& path) {
browser_context_->prefs()->SetFilePath(
prefs::kDownloadDefaultDirectory, path);
}
v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
if (cookies_.IsEmpty()) {
auto handle = atom::api::Cookies::Create(isolate, browser_context_);
@@ -106,6 +273,10 @@ 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)
.SetMethod("setDownloadPath", &Session::SetDownloadPath)
.SetProperty("cookies", &Session::Cookies);
}

View File

@@ -8,11 +8,19 @@
#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 base {
class FilePath;
}
namespace mate {
class Arguments;
}
namespace atom {
class AtomBrowserContext;
@@ -27,6 +35,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 +47,10 @@ 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);
void SetDownloadPath(const base::FilePath& path);
v8::Local<v8::Value> Cookies(v8::Isolate* isolate);
v8::Global<v8::Value> cookies_;

View File

@@ -14,6 +14,7 @@
#include "atom/common/native_mate_converters/string16_converter.h"
#include "native_mate/constructor.h"
#include "native_mate/dictionary.h"
#include "ui/events/event_constants.h"
#include "ui/gfx/image/image.h"
#include "atom/common/node_includes.h"
@@ -40,12 +41,25 @@ mate::Wrappable* Tray::New(v8::Isolate* isolate, const gfx::Image& image) {
return new Tray(image);
}
void Tray::OnClicked(const gfx::Rect& bounds) {
Emit("clicked", bounds);
void Tray::OnClicked(const gfx::Rect& bounds, int modifiers) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
EmitCustomEvent("clicked",
ModifiersToObject(isolate(), modifiers), bounds);
}
void Tray::OnDoubleClicked() {
Emit("double-clicked");
void Tray::OnDoubleClicked(const gfx::Rect& bounds, int modifiers) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
EmitCustomEvent("double-clicked",
ModifiersToObject(isolate(), modifiers), bounds);
}
void Tray::OnRightClicked(const gfx::Rect& bounds, int modifiers) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
EmitCustomEvent("right-clicked",
ModifiersToObject(isolate(), modifiers), bounds);
}
void Tray::OnBalloonShow() {
@@ -60,45 +74,40 @@ void Tray::OnBalloonClosed() {
Emit("balloon-closed");
}
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 +120,38 @@ void Tray::DisplayBalloon(mate::Arguments* args,
tray_icon_->DisplayBalloon(icon, title, content);
}
void Tray::PopUpContextMenu(mate::Arguments* args) {
gfx::Point pos;
args->GetNext(&pos);
tray_icon_->PopUpContextMenu(pos);
}
void Tray::SetContextMenu(mate::Arguments* args, Menu* menu) {
if (!CheckTrayLife(args))
return;
tray_icon_->SetContextMenu(menu->model());
}
bool Tray::CheckTrayLife(mate::Arguments* args) {
if (!tray_icon_) {
args->ThrowError("Tray is already destroyed");
return false;
} else {
return true;
}
v8::Local<v8::Object> Tray::ModifiersToObject(v8::Isolate* isolate,
int modifiers) {
mate::Dictionary obj(isolate, v8::Object::New(isolate));
obj.Set("shiftKey", static_cast<bool>(modifiers & ui::EF_SHIFT_DOWN));
obj.Set("ctrlKey", static_cast<bool>(modifiers & ui::EF_CONTROL_DOWN));
obj.Set("altKey", static_cast<bool>(modifiers & ui::EF_ALT_DOWN));
obj.Set("metaKey", static_cast<bool>(modifiers & ui::EF_COMMAND_DOWN));
return obj.GetHandle();
}
// 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("popUpContextMenu", &Tray::PopUpContextMenu)
.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 OnDoubleClicked() override;
void OnClicked(const gfx::Rect& bounds, int modifiers) override;
void OnDoubleClicked(const gfx::Rect& bounds, int modifiers) override;
void OnRightClicked(const gfx::Rect& bounds, int modifiers) override;
void OnBalloonShow() override;
void OnBalloonClicked() override;
void OnBalloonClosed() 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,10 +60,11 @@ 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 PopUpContextMenu(mate::Arguments* args);
void SetContextMenu(mate::Arguments* args, Menu* menu);
private:
bool CheckTrayLife(mate::Arguments* args);
v8::Local<v8::Object> ModifiersToObject(v8::Isolate* isolate, int modifiers);
scoped_ptr<TrayIcon> tray_icon_;

View File

@@ -13,7 +13,9 @@
#include "atom/browser/native_window.h"
#include "atom/browser/web_view_guest_delegate.h"
#include "atom/common/api/api_messages.h"
#include "atom/common/event_emitter_caller.h"
#include "atom/common/api/event_emitter_caller.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/gfx_converter.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/native_mate_converters/image_converter.h"
@@ -36,10 +38,10 @@
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents.h"
#include "native_mate/callback.h"
#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 +53,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 +150,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 +177,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 +261,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,14 +558,23 @@ 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) {
web_contents()->InsertCSS(css);
}
void WebContents::ExecuteJavaScript(const base::string16& code) {
web_contents()->GetMainFrame()->ExecuteJavaScript(code);
void WebContents::ExecuteJavaScript(const base::string16& code,
bool has_user_gesture) {
Send(new AtomViewMsg_ExecuteJavaScript(routing_id(), code, has_user_gesture));
}
void WebContents::OpenDevTools(mate::Arguments* args) {
@@ -619,9 +639,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_);
@@ -673,6 +691,22 @@ void WebContents::PrintToPDF(const base::DictionaryValue& setting,
PrintToPDF(setting, callback);
}
void WebContents::AddWorkSpace(const base::FilePath& path) {
if (path.empty()) {
node::ThrowError(isolate(), "path cannot be empty");
return;
}
DevToolsAddFileSystem(path);
}
void WebContents::RemoveWorkSpace(const base::FilePath& path) {
if (path.empty()) {
node::ThrowError(isolate(), "path cannot be empty");
return;
}
DevToolsRemoveFileSystem(path);
}
void WebContents::Undo() {
web_contents()->Undo();
}
@@ -717,6 +751,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 +782,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 +797,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 +818,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)
@@ -785,6 +830,8 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
.SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker)
.SetMethod("print", &WebContents::Print)
.SetMethod("_printToPDF", &WebContents::PrintToPDF)
.SetMethod("addWorkSpace", &WebContents::AddWorkSpace)
.SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace)
.SetProperty("session", &WebContents::Session)
.Build());
@@ -792,6 +839,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 {
@@ -36,8 +37,8 @@ class WebContents : public mate::TrackableObject<WebContents>,
public content::WebContentsObserver {
public:
// For node.js callback function type: function(error, buffer)
typedef base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)>
PrintToPDFCallback;
using PrintToPDFCallback =
base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)>;
// Create from an existing WebContents.
static mate::Handle<WebContents> CreateFrom(
@@ -62,8 +63,10 @@ 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 ExecuteJavaScript(const base::string16& code,
bool has_user_gesture);
void OpenDevTools(mate::Arguments* args);
void CloseDevTools();
bool IsDevToolsOpened();
@@ -81,6 +84,10 @@ class WebContents : public mate::TrackableObject<WebContents>,
void PrintToPDF(const base::DictionaryValue& setting,
const PrintToPDFCallback& callback);
// DevTools workspace api.
void AddWorkSpace(const base::FilePath& path);
void RemoveWorkSpace(const base::FilePath& path);
// Editing commands.
void Undo();
void Redo();
@@ -94,6 +101,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 +122,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 +202,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

@@ -8,18 +8,43 @@
#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/browser/browser.h"
#include "atom/browser/native_window.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/gfx_converter.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/native_mate_converters/image_converter.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "content/public/browser/render_process_host.h"
#include "native_mate/callback.h"
#include "native_mate/constructor.h"
#include "native_mate/dictionary.h"
#include "ui/gfx/geometry/rect.h"
#if defined(OS_WIN)
#include "atom/browser/native_window_views.h"
#include "atom/browser/ui/win/taskbar_host.h"
#endif
#include "atom/common/node_includes.h"
#if defined(OS_WIN)
namespace mate {
template<>
struct Converter<atom::TaskbarHost::ThumbarButton> {
static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val,
atom::TaskbarHost::ThumbarButton* out) {
mate::Dictionary dict;
if (!ConvertFromV8(isolate, val, &dict))
return false;
dict.Get("click", &(out->clicked_callback));
dict.Get("tooltip", &(out->tooltip));
dict.Get("flags", &out->flags);
return dict.Get("icon", &(out->icon));
}
};
} // namespace mate
#endif
namespace atom {
namespace api {
@@ -177,6 +202,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);
}
@@ -409,6 +438,21 @@ void Window::SetOverlayIcon(const gfx::Image& overlay,
window_->SetOverlayIcon(overlay, description);
}
bool Window::SetThumbarButtons(mate::Arguments* args) {
#if defined(OS_WIN)
std::vector<TaskbarHost::ThumbarButton> buttons;
if (!args->GetNext(&buttons)) {
args->ThrowError();
return false;
}
auto window = static_cast<NativeWindowViews*>(window_.get());
return window->taskbar_host().SetThumbarButtons(
window->GetAcceleratedWidget(), buttons);
#else
return false;
#endif
}
void Window::SetMenu(v8::Isolate* isolate, v8::Local<v8::Value> value) {
mate::Handle<Menu> menu;
if (value->IsObject() &&
@@ -447,6 +491,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 +527,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 +544,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)
@@ -527,6 +578,7 @@ void Window::BuildPrototype(v8::Isolate* isolate,
.SetMethod("capturePage", &Window::CapturePage)
.SetMethod("setProgressBar", &Window::SetProgressBar)
.SetMethod("setOverlayIcon", &Window::SetOverlayIcon)
.SetMethod("setThumbarButtons", &Window::SetThumbarButtons)
.SetMethod("setMenu", &Window::SetMenu)
.SetMethod("setAutoHideMenuBar", &Window::SetAutoHideMenuBar)
.SetMethod("isMenuBarAutoHide", &Window::IsMenuBarAutoHide)
@@ -540,9 +592,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

@@ -11,6 +11,7 @@
#include "base/memory/scoped_ptr.h"
#include "ui/gfx/image/image.h"
#include "atom/browser/api/trackable_object.h"
#include "atom/browser/native_window.h"
#include "atom/browser/native_window_observer.h"
#include "native_mate/handle.h"
@@ -73,6 +74,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();
@@ -126,11 +130,13 @@ class Window : public mate::TrackableObject<Window>,
void SetProgressBar(double progress);
void SetOverlayIcon(const gfx::Image& overlay,
const std::string& description);
bool SetThumbarButtons(mate::Arguments* args);
void SetMenu(v8::Isolate* isolate, v8::Local<v8::Value> menu);
void SetAutoHideMenuBar(bool auto_hide);
bool IsMenuBarAutoHide();
void SetMenuBarVisibility(bool visible);
bool IsMenuBarVisible();
void SetAspectRatio(double aspect_ratio, mate::Arguments* args);
#if defined(OS_MACOSX)
void ShowDefinitionForSelection();

View File

@@ -37,9 +37,8 @@ v8::Local<v8::Object> CreateEventObject(v8::Isolate* isolate) {
EventEmitter::EventEmitter() {
}
v8::Local<v8::Object> EventEmitter::CreateJSEvent(v8::Isolate* isolate,
content::WebContents* sender,
IPC::Message* message) {
v8::Local<v8::Object> EventEmitter::CreateJSEvent(
v8::Isolate* isolate, content::WebContents* sender, IPC::Message* message) {
v8::Local<v8::Object> event;
bool use_native_event = sender && message;
@@ -54,4 +53,12 @@ v8::Local<v8::Object> EventEmitter::CreateJSEvent(v8::Isolate* isolate,
return event;
}
v8::Local<v8::Object> EventEmitter::CreateCustomEvent(
v8::Isolate* isolate, v8::Local<v8::Object> custom_event) {
v8::Local<v8::Object> event = CreateEventObject(isolate);
event->SetPrototype(custom_event->CreationContext(), custom_event);
mate::Dictionary(isolate, event).Set("sender", GetWrapper(isolate));
return event;
}
} // namespace mate

View File

@@ -7,7 +7,7 @@
#include <vector>
#include "atom/common/event_emitter_caller.h"
#include "atom/common/api/event_emitter_caller.h"
#include "native_mate/wrappable.h"
namespace content {
@@ -25,6 +25,14 @@ class EventEmitter : public Wrappable {
public:
typedef std::vector<v8::Local<v8::Value>> ValueArray;
// this.emit(name, event, args...);
template<typename... Args>
bool EmitCustomEvent(const base::StringPiece& name,
v8::Local<v8::Object> event,
const Args&... args) {
return EmitWithEvent(name, CreateCustomEvent(isolate(), event), args...);
}
// this.emit(name, new Event(), args...);
template<typename... Args>
bool Emit(const base::StringPiece& name, const Args&... args) {
@@ -37,21 +45,31 @@ class EventEmitter : public Wrappable {
content::WebContents* sender,
IPC::Message* message,
const Args&... args) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
v8::Local<v8::Object> event = CreateJSEvent(isolate(), sender, message);
EmitEvent(isolate(), GetWrapper(isolate()), name, event, args...);
return event->Get(
StringToV8(isolate(), "defaultPrevented"))->BooleanValue();
return EmitWithEvent(name, event, args...);
}
protected:
EventEmitter();
private:
// this.emit(name, event, args...);
template<typename... Args>
bool EmitWithEvent(const base::StringPiece& name,
v8::Local<v8::Object> event,
const Args&... args) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
EmitEvent(isolate(), GetWrapper(isolate()), name, event, args...);
return event->Get(
StringToV8(isolate(), "defaultPrevented"))->BooleanValue();
}
v8::Local<v8::Object> CreateJSEvent(v8::Isolate* isolate,
content::WebContents* sender,
IPC::Message* message);
v8::Local<v8::Object> CreateCustomEvent(
v8::Isolate* isolate, v8::Local<v8::Object> event);
DISALLOW_COPY_AND_ASSIGN(EventEmitter);
};

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

@@ -1,7 +1 @@
module.exports = process.atomBinding 'content_tracing'
# Mirrored from content::TracingController::Options
module.exports.DEFAULT_OPTIONS = 0
module.exports.ENABLE_SYSTRACE = 1 << 0
module.exports.ENABLE_SAMPLING = 1 << 1
module.exports.RECORD_CONTINUOUSLY = 1 << 2

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

@@ -3,8 +3,12 @@ bindings = process.atomBinding 'tray'
Tray = bindings.Tray
Tray::__proto__ = EventEmitter.prototype
Tray::setContextMenu = (menu) ->
@_setContextMenu menu
@menu = menu # Keep a strong reference of menu.
# Keep compatibility with old APIs.
Tray::popContextMenu = Tray::popUpContextMenu
module.exports = Tray

View File

@@ -6,6 +6,34 @@ ipc = require 'ipc'
nextId = 0
getNextId = -> ++nextId
PDFPageSize =
A4:
custom_display_name: "A4"
height_microns: 297000
name: "ISO_A4"
is_default: "true"
width_microns: 210000
A3:
custom_display_name: "A3"
height_microns: 420000
name: "ISO_A3"
width_microns: 297000
Legal:
custom_display_name: "Legal"
height_microns: 355600
name: "NA_LEGAL"
width_microns: 215900
Letter:
custom_display_name: "Letter"
height_microns: 279400
name: "NA_LETTER"
width_microns: 215900
Tabloid:
height_microns: 431800
name: "NA_LEDGER"
width_microns: 279400
custom_display_name: "Tabloid"
wrapWebContents = (webContents) ->
# webContents is an EventEmitter.
webContents.__proto__ = EventEmitter.prototype
@@ -18,11 +46,11 @@ wrapWebContents = (webContents) ->
# web contents has been loaded.
webContents.loaded = false
webContents.once 'did-finish-load', -> @loaded = true
webContents.executeJavaScript = (code) ->
webContents.executeJavaScript = (code, hasUserGesture=false) ->
if @loaded
@_executeJavaScript code
@_executeJavaScript code, hasUserGesture
else
webContents.once 'did-finish-load', @_executeJavaScript.bind(this, code)
webContents.once 'did-finish-load', @_executeJavaScript.bind(this, code, hasUserGesture)
# The navigation controller.
controller = new NavigationController(webContents)
@@ -41,32 +69,27 @@ wrapWebContents = (webContents) ->
webContents.printToPDF = (options, callback) ->
printingSetting =
pageRage:[],
mediaSize:
height_microns:297000,
is_default:true,
name:"ISO_A4",
width_microns:210000,
custom_display_name:"A4",
landscape:false,
color:2,
headerFooterEnabled:false,
marginsType:0,
isFirstRequest:false,
requestID: getNextId(),
previewModifiable:true,
printToPDF:true,
printWithCloudPrint:false,
printWithPrivet:false,
printWithExtension:false,
deviceName:"Save as PDF",
generateDraftData:true,
fitToPageEnabled:false,
duplex:0,
copies:1,
collate:true,
shouldPrintBackgrounds:false,
shouldPrintSelectionOnly:false
pageRage: []
mediaSize: {}
landscape: false
color: 2
headerFooterEnabled: false
marginsType: 0
isFirstRequest: false
requestID: getNextId()
previewModifiable: true
printToPDF: true
printWithCloudPrint: false
printWithPrivet: false
printWithExtension: false
deviceName: "Save as PDF"
generateDraftData: true
fitToPageEnabled: false
duplex: 0
copies: 1
collate: true
shouldPrintBackgrounds: false
shouldPrintSelectionOnly: false
if options.landscape
printingSetting.landscape = options.landscape
@@ -77,6 +100,11 @@ wrapWebContents = (webContents) ->
if options.printBackgrounds
printingSetting.shouldPrintBackgrounds = options.printBackground
if options.pageSize and PDFPageSize[options.pageSize]
printingSetting.mediaSize = PDFPageSize[options.pageSize]
else
printingSetting.mediaSize = PDFPageSize['A4']
@_printToPDF printingSetting, callback
binding._setWrapWebContents wrapWebContents

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

@@ -4,6 +4,10 @@
#include "atom/browser/atom_browser_client.h"
#if defined(OS_WIN)
#include <shlobj.h>
#endif
#include "atom/browser/atom_access_token_store.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
@@ -190,10 +194,20 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches(
if (process_type != "renderer")
return;
// The registered standard schemes.
if (!g_custom_schemes.empty())
command_line->AppendSwitchASCII(switches::kRegisterStandardSchemes,
g_custom_schemes);
#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
NativeWindow* window;
WebViewManager::WebViewInfo info;
ProcessOwner owner = GetProcessOwner(process_id, &window, &info);
@@ -215,11 +229,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,25 @@
#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/files/file_path.h"
#include "base/prefs/pref_registry_simple.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 "chrome/common/pref_names.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 +46,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 +63,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) {
@@ -115,4 +149,11 @@ content::BrowserPluginGuestManager* AtomBrowserContext::GetGuestManager() {
return guest_manager_.get();
}
void AtomBrowserContext::RegisterPrefs(PrefRegistrySimple* pref_registry) {
pref_registry->RegisterFilePathPref(prefs::kSelectFileLastDirectory,
base::FilePath());
pref_registry->RegisterFilePathPref(prefs::kDownloadDefaultDirectory,
base::FilePath());
}
} // namespace atom

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;
@@ -29,6 +32,9 @@ class AtomBrowserContext : public brightray::BrowserContext {
content::DownloadManagerDelegate* GetDownloadManagerDelegate() override;
content::BrowserPluginGuestManager* GetGuestManager() override;
// brightray::BrowserContext:
void RegisterPrefs(PrefRegistrySimple* pref_registry) override;
AtomURLRequestJobFactory* job_factory() const { return job_factory_; }
private:

View File

@@ -6,10 +6,13 @@
#include <string>
#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_util.h"
#include "base/prefs/pref_service.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/download_manager.h"
@@ -77,6 +80,11 @@ void AtomDownloadManagerDelegate::OnDownloadPathGenerated(
return;
}
// Remeber the last selected download directory.
AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>(
download_manager_->GetBrowserContext());
browser_context->prefs()->SetFilePath(prefs::kDownloadDefaultDirectory,
path.DirName());
callback.Run(path,
content::DownloadItem::TARGET_DISPOSITION_PROMPT,
content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, path);
@@ -92,9 +100,14 @@ bool AtomDownloadManagerDelegate::DetermineDownloadTarget(
const content::DownloadTargetCallback& callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (default_download_path_.empty()) {
AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>(
download_manager_->GetBrowserContext());
base::FilePath default_download_path = browser_context->prefs()->GetFilePath(
prefs::kDownloadDefaultDirectory);
// If users didn't set download path, use 'Downloads' directory by default.
if (default_download_path.empty()) {
auto path = download_manager_->GetBrowserContext()->GetPath();
default_download_path_ = path.Append(FILE_PATH_LITERAL("Downloads"));
default_download_path = path.Append(FILE_PATH_LITERAL("Downloads"));
}
if (!download->GetForcedFilePath().empty()) {
@@ -118,7 +131,7 @@ bool AtomDownloadManagerDelegate::DetermineDownloadTarget(
download->GetContentDisposition(),
download->GetSuggestedFilename(),
download->GetMimeType(),
default_download_path_,
default_download_path,
download_path_callback));
return true;
}

View File

@@ -47,7 +47,6 @@ class AtomDownloadManagerDelegate : public content::DownloadManagerDelegate {
private:
content::DownloadManager* download_manager_;
base::FilePath default_download_path_;
base::WeakPtrFactory<AtomDownloadManagerDelegate> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(AtomDownloadManagerDelegate);

View File

@@ -274,16 +274,21 @@ void CommonWebContentsDelegate::DevToolsAppendToFile(
base::Unretained(this), url));
}
void CommonWebContentsDelegate::DevToolsAddFileSystem() {
file_dialog::Filters filters;
base::FilePath default_path;
std::vector<base::FilePath> paths;
int flag = file_dialog::FILE_DIALOG_OPEN_DIRECTORY;
if (!file_dialog::ShowOpenDialog(owner_window(), "", default_path,
filters, flag, &paths))
return;
void CommonWebContentsDelegate::DevToolsAddFileSystem(
const base::FilePath& file_system_path) {
base::FilePath path = file_system_path;
if (path.empty()) {
file_dialog::Filters filters;
base::FilePath default_path;
std::vector<base::FilePath> paths;
int flag = file_dialog::FILE_DIALOG_OPEN_DIRECTORY;
if (!file_dialog::ShowOpenDialog(owner_window(), "", default_path,
filters, flag, &paths))
return;
path = paths[0];
}
base::FilePath path = paths[0];
std::string registered_name;
std::string file_system_id = RegisterFileSystem(GetDevToolsWebContents(),
path,
@@ -313,20 +318,20 @@ void CommonWebContentsDelegate::DevToolsAddFileSystem() {
}
void CommonWebContentsDelegate::DevToolsRemoveFileSystem(
const std::string& file_system_path) {
const base::FilePath& file_system_path) {
if (!web_contents_)
return;
base::FilePath path = base::FilePath::FromUTF8Unsafe(file_system_path);
storage::IsolatedContext::GetInstance()->RevokeFileSystemByPath(path);
storage::IsolatedContext::GetInstance()->
RevokeFileSystemByPath(file_system_path);
for (auto it = saved_paths_.begin(); it != saved_paths_.end(); ++it)
if (it->second == path) {
if (it->second == file_system_path) {
saved_paths_.erase(it);
break;
}
base::StringValue file_system_path_value(file_system_path);
base::StringValue file_system_path_value(file_system_path.AsUTF8Unsafe());
web_contents_->CallClientFunction(
"DevToolsAPI.fileSystemRemoved",
&file_system_path_value,

View File

@@ -80,8 +80,9 @@ class CommonWebContentsDelegate
bool save_as) override;
void DevToolsAppendToFile(const std::string& url,
const std::string& content) override;
void DevToolsAddFileSystem() override;
void DevToolsRemoveFileSystem(const std::string& file_system_path) override;
void DevToolsAddFileSystem(const base::FilePath& path) override;
void DevToolsRemoveFileSystem(
const base::FilePath& file_system_path) override;
private:
// Callback for when DevToolsSaveToFile has completed.

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

@@ -3,6 +3,7 @@ webContents = require 'web-contents'
webViewManager = null # Doesn't exist in early initialization.
supportedWebViewEvents = [
'load-commit'
'did-finish-load'
'did-fail-load'
'did-frame-finish-load'

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
@@ -65,3 +64,6 @@ ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPENER_POSTMESSAGE', (event, mess
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', (event, guestId, method, args...) ->
BrowserWindow.fromId(guestId)?.webContents?[method] args...
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_IS_GUEST_WINDOW', (event) ->
event.returnValue = v8Util.getHiddenValue(event.sender, 'embedder') isnt undefined

View File

@@ -38,7 +38,7 @@ process.on 'uncaughtException', (error) ->
# Show error in GUI.
stack = error.stack ? "#{error.name}: #{error.message}"
message = "Uncaught Exception:\n#{stack}"
require('dialog').showErrorBox 'A JavaScript error occured in the browser process', message
require('dialog').showErrorBox 'A JavaScript error occured in the main process', message
# Emit 'exit' event on quit.
app = require 'app'
@@ -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

@@ -10,6 +10,7 @@ valueToMeta = (sender, value) ->
meta.type = 'buffer' if Buffer.isBuffer value
meta.type = 'value' if value is null
meta.type = 'array' if Array.isArray value
meta.type = 'promise' if value? and value.constructor.name is 'Promise'
# Treat the arguments object as array.
meta.type = 'array' if meta.type is 'object' and value.callee? and value.length?
@@ -29,6 +30,8 @@ valueToMeta = (sender, value) ->
meta.members.push {name: prop, type: typeof field} for prop, field of value
else if meta.type is 'buffer'
meta.value = Array::slice.call value, 0
else if meta.type is 'promise'
meta.then = valueToMeta(sender, value.then.bind(value))
else
meta.type = 'value'
meta.value = value
@@ -47,6 +50,7 @@ unwrapArgs = (sender, args) ->
when 'remote-object' then objectsRegistry.get meta.id
when 'array' then unwrapArgs sender, meta.value
when 'buffer' then new Buffer(meta.value)
when 'promise' then Promise.resolve(then: metaToValue(meta.then))
when 'object'
ret = v8Util.createObjectWithName meta.name
for member in meta.members

View File

@@ -10,11 +10,8 @@
#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 +21,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 +32,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,12 +68,20 @@ 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;
// Convert draggable regions in raw format to SkRegion format. Caller is
// responsible for deleting the returned SkRegion instance.
scoped_ptr<SkRegion> DraggableRegionsToSkRegion(
const std::vector<DraggableRegion>& regions) {
scoped_ptr<SkRegion> sk_region(new SkRegion);
for (const DraggableRegion& region : regions) {
sk_region->op(
region.bounds.x(),
region.bounds.y(),
region.bounds.right(),
region.bounds.bottom(),
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
}
return sk_region.Pass();
}
} // namespace
@@ -94,6 +97,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 +134,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 +183,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 +259,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_;
}
@@ -417,8 +427,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 +437,15 @@ 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("allow-displaying-insecure-content", &b))
prefs->allow_displaying_insecure_content = b;
if (web_preferences_.Get("allow-running-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)
@@ -505,6 +522,12 @@ void NativeWindow::NotifyWindowLeaveHtmlFullScreen() {
OnWindowLeaveHtmlFullScreen());
}
void NativeWindow::NotifyWindowExecuteWindowsCommand(
const std::string& command) {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_,
OnExecuteWindowsCommand(command));
}
void NativeWindow::DevToolsFocused() {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnDevToolsFocus());
}
@@ -539,7 +562,7 @@ void NativeWindow::BeforeUnloadDialogCancelled() {
void NativeWindow::TitleWasSet(content::NavigationEntry* entry,
bool explicit_set) {
bool prevent_default = false;
std::string text = base::UTF16ToUTF8(entry->GetTitle());
std::string text = entry ? base::UTF16ToUTF8(entry->GetTitle()) : "";
FOR_EACH_OBSERVER(NativeWindowObserver,
observers_,
OnPageTitleUpdated(&prevent_default, text));
@@ -558,6 +581,14 @@ bool NativeWindow::OnMessageReceived(const IPC::Message& message) {
return handled;
}
void NativeWindow::UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) {
// Draggable region is not supported for non-frameless window.
if (has_frame_)
return;
draggable_region_ = DraggableRegionsToSkRegion(regions);
}
void NativeWindow::ScheduleUnresponsiveEvent(int ms) {
if (!window_unresposive_closure_.IsCancelled())
return;

View File

@@ -23,6 +23,8 @@
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h"
class SkRegion;
namespace base {
class CommandLine;
}
@@ -57,7 +59,7 @@ struct DraggableRegion;
class NativeWindow : public content::WebContentsObserver,
public brightray::InspectableWebContentsViewDelegate {
public:
typedef base::Callback<void(const SkBitmap& bitmap)> CapturePageCallback;
using CapturePageCallback = base::Callback<void(const SkBitmap& bitmap)>;
class DialogScope {
public:
@@ -93,6 +95,7 @@ class NativeWindow : public content::WebContentsObserver,
virtual void Close() = 0;
virtual void CloseImmediately() = 0;
virtual bool IsClosed() const { return is_closed_; }
virtual void Focus(bool focus) = 0;
virtual bool IsFocused() = 0;
virtual void Show() = 0;
@@ -137,14 +140,17 @@ class NativeWindow : public content::WebContentsObserver,
virtual void SetMenu(ui::MenuModel* menu);
virtual bool HasModalDialog();
virtual gfx::NativeWindow GetNativeWindow() = 0;
// Taskbar/Dock APIs.
virtual void SetProgressBar(double progress) = 0;
virtual void SetOverlayIcon(const gfx::Image& overlay,
const std::string& description) = 0;
// Workspace APIs.
virtual void SetVisibleOnAllWorkspaces(bool visible) = 0;
virtual bool IsVisibleOnAllWorkspaces() = 0;
virtual bool IsClosed() const { return is_closed_; }
// Webview APIs.
virtual void FocusOnWebView();
virtual void BlurWebView();
virtual bool IsWebViewFocused();
@@ -163,6 +169,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();
}
@@ -198,11 +209,11 @@ class NativeWindow : public content::WebContentsObserver,
void NotifyWindowLeaveFullScreen();
void NotifyWindowEnterHtmlFullScreen();
void NotifyWindowLeaveHtmlFullScreen();
void NotifyWindowExecuteWindowsCommand(const std::string& command);
void AddObserver(NativeWindowObserver* obs) {
observers_.AddObserver(obs);
}
void RemoveObserver(NativeWindowObserver* obs) {
observers_.RemoveObserver(obs);
}
@@ -212,6 +223,10 @@ class NativeWindow : public content::WebContentsObserver,
}
bool has_frame() const { return has_frame_; }
bool transparent() const { return transparent_; }
SkRegion* draggable_region() const { return draggable_region_.get(); }
bool enable_larger_than_screen() const { return enable_larger_than_screen_; }
gfx::ImageSkia icon() const { return icon_; }
void set_has_dialog_attached(bool has_dialog_attached) {
has_dialog_attached_ = has_dialog_attached;
@@ -221,10 +236,6 @@ class NativeWindow : public content::WebContentsObserver,
NativeWindow(brightray::InspectableWebContents* inspectable_web_contents,
const mate::Dictionary& options);
// Called when the window needs to update its draggable region.
virtual void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) = 0;
// brightray::InspectableWebContentsViewDelegate:
void DevToolsFocused() override;
void DevToolsOpened() override;
@@ -236,22 +247,11 @@ class NativeWindow : public content::WebContentsObserver,
void TitleWasSet(content::NavigationEntry* entry, bool explicit_set) override;
bool OnMessageReceived(const IPC::Message& message) override;
// Whether window has standard frame.
bool has_frame_;
// Whether window is transparent.
bool transparent_;
// Whether window can be resized larger than screen.
bool enable_larger_than_screen_;
// Window icon.
gfx::ImageSkia icon_;
// Observers of this window.
ObserverList<NativeWindowObserver> observers_;
private:
// Called when the window needs to update its draggable region.
void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions);
// Schedule a notification unresponsive event.
void ScheduleUnresponsiveEvent(int ms);
@@ -263,6 +263,22 @@ class NativeWindow : public content::WebContentsObserver,
const SkBitmap& bitmap,
content::ReadbackResponse response);
// Whether window has standard frame.
bool has_frame_;
// Whether window is transparent.
bool transparent_;
// For custom drag, the whole window is non-draggable and the draggable region
// has to been explicitly provided.
scoped_ptr<SkRegion> draggable_region_; // used in custom drag.
// Whether window can be resized larger than screen.
bool enable_larger_than_screen_;
// Window icon.
gfx::ImageSkia icon_;
// The windows has been closed.
bool is_closed_;
@@ -285,9 +301,17 @@ 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_;
// Observers of this window.
ObserverList<NativeWindowObserver> observers_;
base::WeakPtrFactory<NativeWindow> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(NativeWindow);

View File

@@ -11,13 +11,11 @@
#include <vector>
#include "base/mac/scoped_nsobject.h"
#include "base/memory/scoped_ptr.h"
#include "atom/browser/native_window.h"
@class AtomNSWindow;
@class AtomNSWindowDelegate;
@class FullSizeContentView;
class SkRegion;
namespace atom {
@@ -88,9 +86,6 @@ class NativeWindowMac : public NativeWindow {
void ClipWebView();
protected:
void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) override;
// NativeWindow:
void HandleKeyboardEvent(
content::WebContents*,
@@ -117,10 +112,6 @@ class NativeWindowMac : public NativeWindow {
// The presentation options before entering kiosk mode.
NSApplicationPresentationOptions kiosk_options_;
// For custom drag, the whole window is non-draggable and the draggable region
// has to been explicitly provided.
scoped_ptr<SkRegion> draggable_region_; // used in custom drag.
// Mouse location since the last mouse event, in screen coordinates. This is
// used in custom drag to compute the window movement.
NSPoint last_mouse_offset_;

View File

@@ -20,7 +20,26 @@
#include "content/public/browser/render_widget_host_view.h"
#include "native_mate/dictionary.h"
static const CGFloat kAtomWindowCornerRadius = 4.0;
namespace {
// The radius of rounded corner.
const CGFloat kAtomWindowCornerRadius = 4.0;
// Prevents window from resizing during the scope.
class ScopedDisableResize {
public:
ScopedDisableResize() { disable_resize_ = true; }
~ScopedDisableResize() { disable_resize_ = false; }
static bool IsResizeDisabled() { return disable_resize_; }
private:
static bool disable_resize_;
};
bool ScopedDisableResize::disable_resize_ = false;
} // namespace
@interface NSView (PrivateMethods)
- (CGFloat)roundedCornerRadius;
@@ -95,6 +114,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();
@@ -176,8 +233,12 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
enable_larger_than_screen_ = enable;
}
// Enable the window to be larger than screen.
- (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen*)screen {
// Resizing is disabled.
if (ScopedDisableResize::IsResizeDisabled())
return [self frame];
// Enable the window to be larger than screen.
if (enable_larger_than_screen_)
return frameRect;
else
@@ -280,29 +341,6 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
namespace atom {
namespace {
// Convert draggable regions in raw format to SkRegion format. Caller is
// responsible for deleting the returned SkRegion instance.
SkRegion* DraggableRegionsToSkRegion(
const std::vector<DraggableRegion>& regions) {
SkRegion* sk_region = new SkRegion;
for (std::vector<DraggableRegion>::const_iterator iter = regions.begin();
iter != regions.end();
++iter) {
const DraggableRegion& region = *iter;
sk_region->op(
region.bounds.x(),
region.bounds.y(),
region.bounds.right(),
region.bounds.bottom(),
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
}
return sk_region;
}
} // namespace
NativeWindowMac::NativeWindowMac(
brightray::InspectableWebContents* web_contents,
const mate::Dictionary& options)
@@ -325,7 +363,7 @@ NativeWindowMac::NativeWindowMac(
NSUInteger styleMask = NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSResizableWindowMask;
if (!useStandardWindow || transparent_ || !has_frame_) {
if (!useStandardWindow || transparent() || !has_frame()) {
styleMask |= NSTexturedBackgroundWindowMask;
}
@@ -335,12 +373,12 @@ NativeWindowMac::NativeWindowMac(
backing:NSBackingStoreBuffered
defer:YES]);
[window_ setShell:this];
[window_ setEnableLargerThanScreen:enable_larger_than_screen_];
[window_ setEnableLargerThanScreen:enable_larger_than_screen()];
window_delegate_.reset([[AtomNSWindowDelegate alloc] initWithShell:this]);
[window_ setDelegate:window_delegate_];
if (transparent_) {
if (transparent()) {
// Make window has transparent background.
[window_ setOpaque:NO];
[window_ setHasShadow:NO];
@@ -348,7 +386,7 @@ NativeWindowMac::NativeWindowMac(
}
// Remove non-transparent corners, see http://git.io/vfonD.
if (!has_frame_)
if (!has_frame())
[window_ setOpaque:NO];
// We will manage window's lifetime ourselves.
@@ -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);
}
@@ -538,12 +584,15 @@ gfx::Size NativeWindowMac::GetMaximumSize() {
}
void NativeWindowMac::SetResizable(bool resizable) {
// Change styleMask for frameless causes the window to change size, so we have
// to explicitly disables that.
ScopedDisableResize disable_resize;
if (resizable) {
[[window_ standardWindowButton:NSWindowZoomButton] setEnabled:YES];
[window_ setStyleMask:[window_ styleMask] | NSResizableWindowMask];
} else {
[[window_ standardWindowButton:NSWindowZoomButton] setEnabled:NO];
[window_ setStyleMask:[window_ styleMask] ^ NSResizableWindowMask];
[window_ setStyleMask:[window_ styleMask] & (~NSResizableWindowMask)];
}
}
@@ -565,7 +614,7 @@ void NativeWindowMac::Center() {
void NativeWindowMac::SetTitle(const std::string& title) {
// We don't want the title to show in transparent window.
if (transparent_)
if (transparent())
return;
[window_ setTitle:base::SysUTF8ToNSString(title)];
@@ -701,7 +750,7 @@ bool NativeWindowMac::IsVisibleOnAllWorkspaces() {
}
bool NativeWindowMac::IsWithinDraggableRegion(NSPoint point) const {
if (!draggable_region_)
if (!draggable_region())
return false;
if (!web_contents())
return false;
@@ -710,7 +759,7 @@ bool NativeWindowMac::IsWithinDraggableRegion(NSPoint point) const {
// |draggable_region_| is stored in local platform-indepdent coordiate system
// while |point| is in local Cocoa coordinate system. Do the conversion
// to match these two.
return draggable_region_->contains(point.x, webViewHeight - point.y);
return draggable_region()->contains(point.x, webViewHeight - point.y);
}
void NativeWindowMac::HandleMouseEvent(NSEvent* event) {
@@ -730,15 +779,6 @@ void NativeWindowMac::HandleMouseEvent(NSEvent* event) {
}
}
void NativeWindowMac::UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) {
// Draggable region is not supported for non-frameless window.
if (has_frame_)
return;
draggable_region_.reset(DraggableRegionsToSkRegion(regions));
}
void NativeWindowMac::HandleKeyboardEvent(
content::WebContents*,
const content::NativeWebKeyboardEvent& event) {
@@ -765,7 +805,7 @@ void NativeWindowMac::HandleKeyboardEvent(
void NativeWindowMac::InstallView() {
NSView* view = inspectable_web_contents()->GetView()->GetNativeView();
if (has_frame_) {
if (has_frame()) {
// Add layer with white background for the contents view.
base::scoped_nsobject<CALayer> layer([[CALayer alloc] init]);
[layer setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)];

View File

@@ -4,10 +4,6 @@
#include "atom/browser/native_window_views.h"
#if defined(OS_WIN)
#include <shobjidl.h>
#endif
#include <string>
#include <vector>
@@ -20,7 +16,6 @@
#include "brightray/browser/inspectable_web_contents_view.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "native_mate/dictionary.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/hit_test.h"
#include "ui/gfx/image/image.h"
@@ -36,26 +31,20 @@
#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"
#include "base/nix/xdg_util.h"
#include "base/strings/string_util.h"
#include "chrome/browser/ui/libgtk2ui/unity_service.h"
#include "dbus/bus.h"
#include "dbus/object_proxy.h"
#include "dbus/message.h"
#include "ui/base/x/x11_util.h"
#include "ui/gfx/x/x11_types.h"
#include "ui/views/window/native_frame_view.h"
#elif defined(OS_WIN)
#include "atom/browser/ui/views/win_frame_view.h"
#include "base/win/scoped_comptr.h"
#include "base/win/windows_version.h"
#include "atom/browser/ui/win/atom_desktop_window_tree_host_win.h"
#include "ui/base/win/shell.h"
#include "ui/gfx/icon_util.h"
#include "ui/gfx/win/dpi.h"
#include "ui/views/win/hwnd_util.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#endif
namespace atom {
@@ -69,42 +58,6 @@ const int kMenuBarHeight = 20;
const int kMenuBarHeight = 25;
#endif
#if defined(USE_X11)
// Returns true if the bus name "com.canonical.AppMenu.Registrar" is available.
bool ShouldUseGlobalMenuBar() {
dbus::Bus::Options options;
scoped_refptr<dbus::Bus> bus(new dbus::Bus(options));
dbus::ObjectProxy* object_proxy =
bus->GetObjectProxy(DBUS_SERVICE_DBUS, dbus::ObjectPath(DBUS_PATH_DBUS));
dbus::MethodCall method_call(DBUS_INTERFACE_DBUS, "ListNames");
scoped_ptr<dbus::Response> response(object_proxy->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
if (!response) {
bus->ShutdownAndBlock();
return false;
}
dbus::MessageReader reader(response.get());
dbus::MessageReader array_reader(NULL);
if (!reader.PopArray(&array_reader)) {
bus->ShutdownAndBlock();
return false;
}
while (array_reader.HasMoreData()) {
std::string name;
if (array_reader.PopString(&name) &&
name == "com.canonical.AppMenu.Registrar") {
bus->ShutdownAndBlock();
return true;
}
}
bus->ShutdownAndBlock();
return false;
}
#endif
bool IsAltKey(const content::NativeWebKeyboardEvent& event) {
#if defined(USE_X11)
// 164 and 165 represent VK_LALT and VK_RALT.
@@ -183,7 +136,7 @@ const char* AppCommandToString(int command_id) {
case APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE:
return "dictate-or-command-control-toggle";
default:
return "unkown";
return "unknown";
}
}
#endif
@@ -231,7 +184,7 @@ NativeWindowViews::NativeWindowViews(
options.Get(switches::kResizable, &resizable_);
#endif
if (enable_larger_than_screen_)
if (enable_larger_than_screen())
// We need to set a default maximum window size here otherwise Windows
// will not allow us to resize the window larger than scree.
// Setting directly to INT_MAX somehow doesn't work, so we just devide
@@ -251,12 +204,20 @@ NativeWindowViews::NativeWindowViews(
params.bounds = bounds;
params.delegate = this;
params.type = views::Widget::InitParams::TYPE_WINDOW;
params.remove_standard_frame = !has_frame_;
params.remove_standard_frame = !has_frame();
if (transparent_)
if (transparent())
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
#if defined(USE_X11)
#if defined(OS_WIN)
params.native_widget =
new views::DesktopNativeWidgetAura(window_.get());
atom_desktop_window_tree_host_win_ = new AtomDesktopWindowTreeHostWin(
this,
window_.get(),
static_cast<views::DesktopNativeWidgetAura*>(params.native_widget));
params.desktop_window_tree_host = atom_desktop_window_tree_host_win_;
#elif defined(USE_X11)
std::string name = Browser::Get()->GetName();
// Set WM_WINDOW_ROLE.
params.wm_role_name = "browser-window";
@@ -285,14 +246,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))
@@ -304,24 +272,24 @@ NativeWindowViews::NativeWindowViews(
set_background(views::Background::CreateStandardPanelBackground());
AddChildView(web_view_);
if (has_frame_ &&
if (has_frame() &&
options.Get(switches::kUseContentSize, &use_content_size_) &&
use_content_size_)
bounds = ContentBoundsToWindowBounds(bounds);
#if defined(OS_WIN)
if (!has_frame_) {
if (!has_frame()) {
// Set Window style so that we get a minimize and maximize animation when
// frameless.
DWORD frame_style = WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX |
WS_CAPTION;
// We should not show a frame for transparent window.
if (transparent_)
if (transparent())
frame_style &= ~(WS_THICKFRAME | WS_CAPTION);
::SetWindowLong(GetAcceleratedWidget(), GWL_STYLE, frame_style);
}
if (transparent_) {
if (transparent()) {
// Transparent window on Windows has to have WS_EX_COMPOSITED style.
LONG ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE);
ex_style |= WS_EX_COMPOSITED;
@@ -331,14 +299,14 @@ NativeWindowViews::NativeWindowViews(
// TODO(zcbenz): This was used to force using native frame on Windows 2003, we
// should check whether setting it in InitParams can work.
if (has_frame_) {
if (has_frame()) {
window_->set_frame_type(views::Widget::FrameType::FRAME_TYPE_FORCE_NATIVE);
window_->FrameTypeChanged();
}
// The given window is most likely not rectangular since it uses
// transparency and has no standard frame, don't show a shadow for it.
if (transparent_ && !has_frame_)
if (transparent() && !has_frame())
wm::SetShadowType(GetNativeWindow(), wm::SHADOW_TYPE_NONE);
window_->UpdateWindowIcon();
@@ -418,17 +386,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
}
@@ -459,7 +429,7 @@ gfx::Rect NativeWindowViews::GetBounds() {
}
void NativeWindowViews::SetContentSize(const gfx::Size& size) {
if (!has_frame_) {
if (!has_frame()) {
NativeWindow::SetSize(size);
return;
}
@@ -470,7 +440,7 @@ void NativeWindowViews::SetContentSize(const gfx::Size& size) {
}
gfx::Size NativeWindowViews::GetContentSize() {
if (!has_frame_)
if (!has_frame())
return GetSize();
gfx::Size content_size =
@@ -482,14 +452,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 +460,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() {
@@ -634,7 +588,7 @@ void NativeWindowViews::SetMenu(ui::MenuModel* menu_model) {
#endif
// Do not show menu bar in frameless window.
if (!has_frame_)
if (!has_frame())
return;
if (!menu_bar_) {
@@ -659,24 +613,7 @@ gfx::NativeWindow NativeWindowViews::GetNativeWindow() {
void NativeWindowViews::SetProgressBar(double progress) {
#if defined(OS_WIN)
if (base::win::GetVersion() < base::win::VERSION_WIN7)
return;
base::win::ScopedComPtr<ITaskbarList3> taskbar;
if (FAILED(taskbar.CreateInstance(CLSID_TaskbarList, NULL,
CLSCTX_INPROC_SERVER) ||
FAILED(taskbar->HrInit()))) {
return;
}
HWND frame = views::HWNDForNativeWindow(GetNativeWindow());
if (progress > 1.0) {
taskbar->SetProgressState(frame, TBPF_INDETERMINATE);
} else if (progress < 0) {
taskbar->SetProgressState(frame, TBPF_NOPROGRESS);
} else if (progress >= 0) {
taskbar->SetProgressValue(frame,
static_cast<int>(progress * 100),
100);
}
taskbar_host_.SetProgressBar(GetAcceleratedWidget(), progress);
#elif defined(USE_X11)
if (unity::IsRunning()) {
unity::SetProgressFraction(progress);
@@ -687,22 +624,7 @@ void NativeWindowViews::SetProgressBar(double progress) {
void NativeWindowViews::SetOverlayIcon(const gfx::Image& overlay,
const std::string& description) {
#if defined(OS_WIN)
if (base::win::GetVersion() < base::win::VERSION_WIN7)
return;
base::win::ScopedComPtr<ITaskbarList3> taskbar;
if (FAILED(taskbar.CreateInstance(CLSID_TaskbarList, NULL,
CLSCTX_INPROC_SERVER) ||
FAILED(taskbar->HrInit()))) {
return;
}
HWND frame = views::HWNDForNativeWindow(GetNativeWindow());
std::wstring wstr = std::wstring(description.begin(), description.end());
taskbar->SetOverlayIcon(frame,
IconUtil::CreateHICONFromSkBitmap(overlay.AsBitmap()),
wstr.c_str());
taskbar_host_.SetOverlayIcon(GetAcceleratedWidget(), overlay, description);
#endif
}
@@ -759,29 +681,6 @@ gfx::AcceleratedWidget NativeWindowViews::GetAcceleratedWidget() {
return GetNativeWindow()->GetHost()->GetAcceleratedWidget();
}
void NativeWindowViews::UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) {
if (has_frame_)
return;
SkRegion* draggable_region = new SkRegion;
// By default, the whole window is non-draggable. We need to explicitly
// include those draggable regions.
for (std::vector<DraggableRegion>::const_iterator iter = regions.begin();
iter != regions.end(); ++iter) {
const DraggableRegion& region = *iter;
draggable_region->op(
region.bounds.x(),
region.bounds.y(),
region.bounds.right(),
region.bounds.bottom(),
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
}
draggable_region_.reset(draggable_region);
}
void NativeWindowViews::OnWidgetActivationChanged(
views::Widget* widget, bool active) {
if (widget != window_.get())
@@ -841,7 +740,7 @@ bool NativeWindowViews::ShouldHandleSystemCommands() const {
}
gfx::ImageSkia NativeWindowViews::GetWindowAppIcon() {
return icon_;
return icon();
}
gfx::ImageSkia NativeWindowViews::GetWindowIcon() {
@@ -864,12 +763,12 @@ bool NativeWindowViews::ShouldDescendIntoChildForEventHandling(
gfx::NativeView child,
const gfx::Point& location) {
// App window should claim mouse events that fall within the draggable region.
if (draggable_region_ &&
draggable_region_->contains(location.x(), location.y()))
if (draggable_region() &&
draggable_region()->contains(location.x(), location.y()))
return false;
// And the events on border for dragging resizable frameless window.
if (!has_frame_ && CanResize()) {
if (!has_frame() && CanResize()) {
FramelessView* frame = static_cast<FramelessView*>(
window_->non_client_view()->frame_view());
return frame->ResizingBorderHitTest(location) == HTNOWHERE;
@@ -889,8 +788,8 @@ views::NonClientFrameView* NativeWindowViews::CreateNonClientFrameView(
frame_view->Init(this, widget);
return frame_view;
#else
if (has_frame_) {
return new views::NativeFrameView(widget);
if (has_frame()) {
return new NativeFrameView(this, widget);
} else {
FramelessView* frame_view = new FramelessView;
frame_view->Init(this, widget);
@@ -920,10 +819,8 @@ bool NativeWindowViews::ExecuteWindowsCommand(int command_id) {
} else if ((command_id & sc_mask) == SC_MAXIMIZE) {
NotifyWindowMaximize();
} else {
std::string command = AppCommandToString(command_id & sc_mask);
FOR_EACH_OBSERVER(NativeWindowObserver,
observers_,
OnExecuteWindowsCommand(command));
std::string command = AppCommandToString(command_id);
NotifyWindowExecuteWindowsCommand(command);
}
return false;
}
@@ -941,6 +838,17 @@ void NativeWindowViews::GetDevToolsWindowWMClass(
}
#endif
#if defined(OS_WIN)
bool NativeWindowViews::PreHandleMSG(
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) {
// Handle thumbar button click message.
if (message == WM_COMMAND && HIWORD(w_param) == THBN_CLICKED)
return taskbar_host_.HandleThumbarButtonEvent(LOWORD(w_param));
else
return false;
}
#endif
void NativeWindowViews::HandleKeyboardEvent(
content::WebContents*,
const content::NativeWebKeyboardEvent& event) {

View File

@@ -14,6 +14,11 @@
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/widget/widget_observer.h"
#if defined(OS_WIN)
#include "atom/browser/ui/win/message_handler_delegate.h"
#include "atom/browser/ui/win/taskbar_host.h"
#endif
namespace views {
class UnhandledKeyboardEventHandler;
}
@@ -24,7 +29,14 @@ class GlobalMenuBarX11;
class MenuBar;
class WindowStateWatcher;
#if defined(OS_WIN)
class AtomDesktopWindowTreeHostWin;
#endif
class NativeWindowViews : public NativeWindow,
#if defined(OS_WIN)
public MessageHandlerDelegate,
#endif
public views::WidgetDelegateView,
public views::WidgetObserver {
public:
@@ -82,14 +94,13 @@ class NativeWindowViews : public NativeWindow,
gfx::AcceleratedWidget GetAcceleratedWidget();
SkRegion* draggable_region() const { return draggable_region_.get(); }
views::Widget* widget() const { return window_.get(); }
private:
// NativeWindow:
void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) override;
#if defined(OS_WIN)
TaskbarHost& taskbar_host() { return taskbar_host_; }
#endif
private:
// views::WidgetObserver:
void OnWidgetActivationChanged(
views::Widget* widget, bool active) override;
@@ -127,6 +138,12 @@ class NativeWindowViews : public NativeWindow,
std::string* name, std::string* class_name) override;
#endif
#if defined(OS_WIN)
// MessageHandlerDelegate:
bool PreHandleMSG(
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) override;
#endif
// NativeWindow:
void HandleKeyboardEvent(
content::WebContents*,
@@ -159,9 +176,13 @@ class NativeWindowViews : public NativeWindow,
// Handles window state events.
scoped_ptr<WindowStateWatcher> window_state_watcher_;
#elif defined(OS_WIN)
// Weak ref.
AtomDesktopWindowTreeHostWin* atom_desktop_window_tree_host_win_;
// Records window was whether restored from minimized state or maximized
// state.
bool is_minimized_;
// In charge of running taskbar related APIs.
TaskbarHost taskbar_host_;
#endif
// Handles unhandled keyboard messages coming back from the renderer process.
@@ -177,8 +198,6 @@ class NativeWindowViews : public NativeWindow,
gfx::Size maximum_size_;
gfx::Size widget_size_;
scoped_ptr<SkRegion> draggable_region_;
DISALLOW_COPY_AND_ASSIGN(NativeWindowViews);
};

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,
scoped_refptr<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(
scoped_refptr<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,
scoped_refptr<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.get());
else
fetcher_->SetRequestContext(GetRequestContext());
fetcher_->SaveResponseWithWriter(make_scoped_ptr(new ResponsePiper(this)));
// Use |request|'s referrer if |referrer| is not specified.
@@ -101,10 +107,18 @@ URLRequestFetchJob::URLRequestFetchJob(
}
// Use |request|'s headers.
net::HttpRequestHeaders headers;
if (request->GetFullRequestHeaders(&headers)) {
fetcher_->SetExtraRequestHeaders(headers.ToString());
fetcher_->SetExtraRequestHeaders(request->extra_request_headers().ToString());
}
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() {

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(scoped_refptr<net::URLRequestContextGetter> 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.1</string>
<string>0.30.4</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,1,0
PRODUCTVERSION 0,29,1,0
FILEVERSION 0,30,4,0
PRODUCTVERSION 0,30,4,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -68,12 +74,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "GitHub, Inc."
VALUE "FileDescription", "Electron"
VALUE "FileVersion", "0.29.1"
VALUE "FileVersion", "0.30.4"
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.1"
VALUE "ProductVersion", "0.30.4"
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

@@ -0,0 +1,22 @@
// 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/atom_menu_model.h"
namespace atom {
AtomMenuModel::AtomMenuModel(Delegate* delegate)
: ui::SimpleMenuModel(delegate),
delegate_(delegate) {
}
AtomMenuModel::~AtomMenuModel() {
}
void AtomMenuModel::MenuClosed() {
ui::SimpleMenuModel::MenuClosed();
FOR_EACH_OBSERVER(Observer, observers_, MenuClosed());
}
} // namespace atom

View File

@@ -0,0 +1,47 @@
// 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_ATOM_MENU_MODEL_H_
#define ATOM_BROWSER_UI_ATOM_MENU_MODEL_H_
#include "base/observer_list.h"
#include "ui/base/models/simple_menu_model.h"
namespace atom {
class AtomMenuModel : public ui::SimpleMenuModel {
public:
class Delegate : public ui::SimpleMenuModel::Delegate {
public:
virtual ~Delegate() {}
};
class Observer {
public:
virtual ~Observer() {}
// Notifies the menu has been closed.
virtual void MenuClosed() {}
};
explicit AtomMenuModel(Delegate* delegate);
virtual ~AtomMenuModel();
void AddObserver(Observer* obs) { observers_.AddObserver(obs); }
void RemoveObserver(Observer* obs) { observers_.RemoveObserver(obs); }
// ui::SimpleMenuModel:
void MenuClosed() override;
private:
Delegate* delegate_; // weak ref.
ObserverList<Observer> observers_;
DISALLOW_COPY_AND_ASSIGN(AtomMenuModel);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_ATOM_MENU_MODEL_H_

View File

@@ -5,61 +5,15 @@
#import "atom/browser/ui/cocoa/atom_menu_controller.h"
#include "atom/browser/ui/atom_menu_model.h"
#include "base/logging.h"
#include "base/strings/sys_string_conversions.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/accelerators/platform_accelerator_cocoa.h"
#include "ui/base/l10n/l10n_util_mac.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/events/cocoa/cocoa_event_utils.h"
#include "ui/gfx/image/image.h"
namespace {
bool isLeftButtonEvent(NSEvent* event) {
NSEventType type = [event type];
return type == NSLeftMouseDown ||
type == NSLeftMouseDragged ||
type == NSLeftMouseUp;
}
bool isRightButtonEvent(NSEvent* event) {
NSEventType type = [event type];
return type == NSRightMouseDown ||
type == NSRightMouseDragged ||
type == NSRightMouseUp;
}
bool isMiddleButtonEvent(NSEvent* event) {
if ([event buttonNumber] != 2)
return false;
NSEventType type = [event type];
return type == NSOtherMouseDown ||
type == NSOtherMouseDragged ||
type == NSOtherMouseUp;
}
int EventFlagsFromNSEventWithModifiers(NSEvent* event, NSUInteger modifiers) {
int flags = 0;
flags |= (modifiers & NSAlphaShiftKeyMask) ? ui::EF_CAPS_LOCK_DOWN : 0;
flags |= (modifiers & NSShiftKeyMask) ? ui::EF_SHIFT_DOWN : 0;
flags |= (modifiers & NSControlKeyMask) ? ui::EF_CONTROL_DOWN : 0;
flags |= (modifiers & NSAlternateKeyMask) ? ui::EF_ALT_DOWN : 0;
flags |= (modifiers & NSCommandKeyMask) ? ui::EF_COMMAND_DOWN : 0;
flags |= isLeftButtonEvent(event) ? ui::EF_LEFT_MOUSE_BUTTON : 0;
flags |= isRightButtonEvent(event) ? ui::EF_RIGHT_MOUSE_BUTTON : 0;
flags |= isMiddleButtonEvent(event) ? ui::EF_MIDDLE_MOUSE_BUTTON : 0;
return flags;
}
// Retrieves a bitsum of ui::EventFlags from NSEvent.
int EventFlagsFromNSEvent(NSEvent* event) {
NSUInteger modifiers = [event modifierFlags];
return EventFlagsFromNSEventWithModifiers(event, modifiers);
}
} // namespace
@interface AtomMenuController (Private)
- (void)addSeparatorToMenu:(NSMenu*)menu
atIndex:(int)index;
@@ -166,8 +120,7 @@ int EventFlagsFromNSEvent(NSEvent* event) {
[item setTarget:nil];
[item setAction:nil];
ui::MenuModel* submenuModel = model->GetSubmenuModelAt(index);
NSMenu* submenu =
[self menuFromModel:(ui::SimpleMenuModel*)submenuModel];
NSMenu* submenu = [self menuFromModel:submenuModel];
[submenu setTitle:[item title]];
[item setSubmenu:submenu];
@@ -246,8 +199,9 @@ int EventFlagsFromNSEvent(NSEvent* event) {
[[sender representedObject] pointerValue]);
DCHECK(model);
if (model) {
int event_flags = EventFlagsFromNSEvent([NSApp currentEvent]);
model->ActivatedAt(modelIndex, event_flags);
NSEvent* event = [NSApp currentEvent];
model->ActivatedAt(modelIndex,
ui::EventFlagsFromModifiers([event modifierFlags]));
}
}

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,236 @@
// 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/browser.h"
#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;
// TaskDialogIndirect doesn't allow empty name, if we set empty title it
// will show "electron.exe" in title.
base::string16 app_name = base::UTF8ToUTF16(Browser::Get()->GetName());
if (title.empty())
config.pszWindowTitle = app_name.c_str();
else
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,12 +26,16 @@ void TrayIcon::DisplayBalloon(const gfx::Image& icon,
const base::string16& contents) {
}
void TrayIcon::NotifyClicked(const gfx::Rect& bounds) {
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnClicked(bounds));
void TrayIcon::PopUpContextMenu(const gfx::Point& pos) {
}
void TrayIcon::NotifyDoubleClicked() {
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnDoubleClicked());
void TrayIcon::NotifyClicked(const gfx::Rect& bounds, int modifiers) {
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnClicked(bounds, modifiers));
}
void TrayIcon::NotifyDoubleClicked(const gfx::Rect& bounds, int modifiers) {
FOR_EACH_OBSERVER(TrayIconObserver, observers_,
OnDoubleClicked(bounds, modifiers));
}
void TrayIcon::NotifyBalloonShow() {
@@ -46,4 +50,13 @@ void TrayIcon::NotifyBalloonClosed() {
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnBalloonClosed());
}
void TrayIcon::NotifyRightClicked(const gfx::Rect& bounds, int modifiers) {
FOR_EACH_OBSERVER(TrayIconObserver, observers_,
OnRightClicked(bounds, modifiers));
}
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,16 +47,21 @@ class TrayIcon {
const base::string16& title,
const base::string16& contents);
virtual void PopUpContextMenu(const gfx::Point& pos);
// Set the context menu for this icon.
virtual void SetContextMenu(ui::SimpleMenuModel* menu_model) = 0;
void AddObserver(TrayIconObserver* obs) { observers_.AddObserver(obs); }
void RemoveObserver(TrayIconObserver* obs) { observers_.RemoveObserver(obs); }
void NotifyClicked(const gfx::Rect& = gfx::Rect());
void NotifyDoubleClicked();
void NotifyClicked(const gfx::Rect& = gfx::Rect(), int modifiers = 0);
void NotifyDoubleClicked(const gfx::Rect& = gfx::Rect(), int modifiers = 0);
void NotifyBalloonShow();
void NotifyBalloonClicked();
void NotifyBalloonClosed();
void NotifyRightClicked(const gfx::Rect& bounds = gfx::Rect(),
int modifiers = 0);
void NotfiyDropFiles(const std::vector<std::string>& files);
protected:
TrayIcon();

View File

@@ -9,15 +9,17 @@
#include <string>
#include "atom/browser/ui/atom_menu_model.h"
#include "atom/browser/ui/tray_icon.h"
#include "base/mac/scoped_nsobject.h"
@class AtomMenuController;
@class StatusItemController;
@class StatusItemView;
namespace atom {
class TrayIconCocoa : public TrayIcon {
class TrayIconCocoa : public TrayIcon,
public AtomMenuModel::Observer {
public:
TrayIconCocoa();
virtual ~TrayIconCocoa();
@@ -27,16 +29,23 @@ 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 PopUpContextMenu(const gfx::Point& pos) override;
void SetContextMenu(ui::SimpleMenuModel* menu_model) override;
private:
base::scoped_nsobject<NSStatusItem> item_;
protected:
// AtomMenuModel::Observer:
void MenuClosed() override;
base::scoped_nsobject<StatusItemController> controller_;
private:
// 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_;
// Used for unregistering observer.
AtomMenuModel* menu_model_; // weak ref.
DISALLOW_COPY_AND_ASSIGN(TrayIconCocoa);
};

View File

@@ -6,84 +6,333 @@
#include "atom/browser/ui/cocoa/atom_menu_controller.h"
#include "base/strings/sys_string_conversions.h"
#include "ui/events/cocoa/cocoa_event_utils.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/screen.h"
@interface StatusItemController : NSObject {
namespace {
// By default, OS X sets 4px to tray image as left and right padding margin.
const CGFloat kHorizontalMargin = 4;
// OS X tends to make the title 2px lower.
const CGFloat kVerticalTitleMargin = 2;
} // 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<NSImageView> image_view_;
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 {
- (id)initWithImage:(NSImage*)image icon:(atom::TrayIconCocoa*)icon {
image_.reset([image copy]);
trayIcon_ = icon;
isHighlightEnable_ = YES;
// Get the initial size.
NSStatusBar* statusBar = [NSStatusBar systemStatusBar];
NSRect frame = NSMakeRect(0, 0, [self fullWidth], [statusBar thickness]);
if ((self = [super initWithFrame:frame])) {
// Setup the image view.
NSRect iconFrame = frame;
iconFrame.size.width = [self iconWidth];
image_view_.reset([[NSImageView alloc] initWithFrame:iconFrame]);
[image_view_ setImageScaling:NSImageScaleNone];
[image_view_ setImageAlignment:NSImageAlignCenter];
[self addSubview:image_view_];
// Unregister image_view_ as a dragged destination, allows its parent view
// (StatusItemView) handle dragging events.
[image_view_ unregisterDraggedTypes];
NSArray* types = [NSArray arrayWithObjects:NSFilenamesPboardType, nil];
[self registerForDraggedTypes:types];
// Create the status item.
statusItem_.reset([[[NSStatusBar systemStatusBar]
statusItemWithLength:NSWidth(frame)] retain]);
[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 NSStatusItem, layout:
// ----------------
// | icon | title |
/// ----------------
// Draw background.
BOOL highlight = [self shouldHighlight];
CGFloat thickness = [[statusItem_ statusBar] thickness];
NSRect statusItemBounds = NSMakeRect(0, 0, [statusItem_ length], thickness);
[statusItem_ drawStatusBarBackgroundInRect:statusItemBounds
withHighlight:highlight];
// Make use of NSImageView to draw the image, which can correctly draw
// template image under dark menu bar.
if (highlight && alternateImage_ &&
[image_view_ image] != alternateImage_.get()) {
[image_view_ setImage:alternateImage_];
} else if ([image_view_ image] != image_.get()) {
[image_view_ setImage:image_];
}
if (title_) {
// Highlight the text when icon is highlighted or in dark mode.
highlight |= [self isDarkMode];
// Draw title.
NSRect titleDrawRect = NSMakeRect(
[self iconWidth], -kVerticalTitleMargin, [self titleWidth], thickness);
[title_ drawInRect:titleDrawRect
withAttributes:[self titleAttributesWithHighlight:highlight]];
}
}
- (BOOL)isDarkMode {
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
NSString* mode = [defaults stringForKey:@"AppleInterfaceStyle"];
return mode && [mode isEqualToString:@"Dark"];
}
// The width of the full status item.
- (CGFloat)fullWidth {
if (title_)
return [self iconWidth] + [self titleWidth] + kHorizontalMargin;
else
return [self iconWidth];
}
// The width of the icon.
- (CGFloat)iconWidth {
CGFloat thickness = [[NSStatusBar systemStatusBar] thickness];
CGFloat imageHeight = [image_ size].height;
CGFloat imageWidth = [image_ size].width;
CGFloat iconWidth = imageWidth;
if (imageWidth < thickness) {
// Image's width must be larger than menu bar's height.
iconWidth = thickness;
} else {
CGFloat verticalMargin = thickness - imageHeight;
// Image must have same horizontal vertical margin.
if (verticalMargin > 0 && imageWidth != imageHeight)
iconWidth = imageWidth + verticalMargin;
CGFloat horizontalMargin = thickness - imageWidth;
// Image must have at least kHorizontalMargin horizontal margin on each
// side.
if (horizontalMargin < 2 * kHorizontalMargin)
iconWidth = imageWidth + 2 * kHorizontalMargin;
}
return iconWidth;
}
// The width of the title.
- (CGFloat)titleWidth {
if (!title_)
return 0;
base::scoped_nsobject<NSAttributedString> attributes(
[[NSAttributedString alloc] initWithString:title_
attributes:[self titleAttributes]]);
return [attributes size].width;
}
- (NSDictionary*)titleAttributesWithHighlight:(BOOL)highlight {
NSFont* font = [NSFont menuBarFontOfSize:0];
NSColor* foregroundColor = highlight ?
[NSColor whiteColor] :
[NSColor colorWithRed:0.265625 green:0.25390625 blue:0.234375 alpha:1.0];
return [NSDictionary dictionaryWithObjectsAndKeys:
font, NSFontAttributeName,
foregroundColor, NSForegroundColorAttributeName,
nil];
}
- (NSDictionary*)titleAttributes {
return [self titleAttributesWithHighlight:[self isDarkMode]];
}
- (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 {
if (title.length > 0)
title_.reset([title copy]);
else
title_.reset();
[statusItem_ setLength:[self fullWidth]];
[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;
// Show menu when single clicked on the icon.
if (event.clickCount == 1 && menuController_)
[statusItem_ popUpStatusItemMenu:[menuController_ menu]];
// Don't emit click events when menu is showing.
if (menuController_)
return;
// Single click event.
if (event.clickCount == 1)
trayIcon_->NotifyClicked(
[self getBoundsFromEvent:event],
ui::EventFlagsFromModifiers([event modifierFlags]));
// Double click event.
if (event.clickCount == 2)
trayIcon_->NotifyDoubleClicked(
[self getBoundsFromEvent:event],
ui::EventFlagsFromModifiers([event modifierFlags]));
[self setNeedsDisplay:YES];
}
- (void)popUpContextMenu {
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],
ui::EventFlagsFromModifiers([event modifierFlags]));
}
- (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 isMenuOpen = menuController_ && [menuController_ isMenuOpen];
return isHighlightEnable_ && (inMouseEventSequence_ || isMenuOpen);
}
- (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];
TrayIconCocoa::TrayIconCocoa() : menu_model_(nullptr) {
}
TrayIconCocoa::~TrayIconCocoa() {
// Remove the status item from the status bar.
[[NSStatusBar systemStatusBar] removeStatusItem:item_];
[status_item_view_ removeItem];
if (menu_model_)
menu_model_->RemoveObserver(this);
}
void TrayIconCocoa::SetImage(const gfx::Image& image) {
[item_ setImage:image.AsNSImage()];
if (status_item_view_) {
[status_item_view_ setImage:image.AsNSImage()];
} else {
status_item_view_.reset(
[[StatusItemView alloc] initWithImage:image.AsNSImage()
icon:this]);
}
}
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::PopUpContextMenu(const gfx::Point& pos) {
[status_item_view_ popUpContextMenu];
}
void TrayIconCocoa::SetContextMenu(ui::SimpleMenuModel* menu_model) {
// Substribe to MenuClosed event.
if (menu_model_)
menu_model_->RemoveObserver(this);
static_cast<AtomMenuModel*>(menu_model)->AddObserver(this);
// Create native menu.
menu_.reset([[AtomMenuController alloc] initWithModel:menu_model]);
[item_ setMenu:[menu_ menu]];
[status_item_view_ setMenuController:menu_.get()];
}
void TrayIconCocoa::MenuClosed() {
[status_item_view_ setNeedsDisplay:YES];
}
// 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 OnDoubleClicked() {}
virtual void OnClicked(const gfx::Rect& bounds, int modifiers) {}
virtual void OnDoubleClicked(const gfx::Rect& bounds, int modifiers) {}
virtual void OnBalloonShow() {}
virtual void OnBalloonClicked() {}
virtual void OnBalloonClosed() {}
virtual void OnRightClicked(const gfx::Rect& bounds, int modifiers) {}
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

@@ -0,0 +1,28 @@
// 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/win/atom_desktop_window_tree_host_win.h"
#include "atom/browser/ui/win/message_handler_delegate.h"
namespace atom {
AtomDesktopWindowTreeHostWin::AtomDesktopWindowTreeHostWin(
MessageHandlerDelegate* delegate,
views::internal::NativeWidgetDelegate* native_widget_delegate,
views::DesktopNativeWidgetAura* desktop_native_widget_aura)
: views::DesktopWindowTreeHostWin(native_widget_delegate,
desktop_native_widget_aura),
delegate_(delegate) {
}
AtomDesktopWindowTreeHostWin::~AtomDesktopWindowTreeHostWin() {
}
bool AtomDesktopWindowTreeHostWin::PreHandleMSG(
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) {
return delegate_->PreHandleMSG(message, w_param, l_param, result);
}
} // namespace atom

View File

@@ -0,0 +1,39 @@
// 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_WIN_ATOM_DESKTOP_WINDOW_TREE_HOST_WIN_H_
#define ATOM_BROWSER_UI_WIN_ATOM_DESKTOP_WINDOW_TREE_HOST_WIN_H_
#include <windows.h>
#include <vector>
#include "atom/browser/native_window.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h"
namespace atom {
class MessageHandlerDelegate;
class AtomDesktopWindowTreeHostWin : public views::DesktopWindowTreeHostWin {
public:
AtomDesktopWindowTreeHostWin(
MessageHandlerDelegate* delegate,
views::internal::NativeWidgetDelegate* native_widget_delegate,
views::DesktopNativeWidgetAura* desktop_native_widget_aura);
~AtomDesktopWindowTreeHostWin() override;
protected:
bool PreHandleMSG(
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) override;
private:
MessageHandlerDelegate* delegate_; // weak ref
DISALLOW_COPY_AND_ASSIGN(AtomDesktopWindowTreeHostWin);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_WIN_ATOM_DESKTOP_WINDOW_TREE_HOST_WIN_H_

View File

@@ -0,0 +1,14 @@
// 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/win/message_handler_delegate.h"
namespace atom {
bool MessageHandlerDelegate::PreHandleMSG(
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) {
return false;
}
} // namespace atom

View File

@@ -0,0 +1,26 @@
// 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_WIN_MESSAGE_HANDLER_DELEGATE_H_
#define ATOM_BROWSER_UI_WIN_MESSAGE_HANDLER_DELEGATE_H_
#include <windows.h>
namespace atom {
class MessageHandlerDelegate {
public:
// Catch-all message handling and filtering. Called before
// HWNDMessageHandler's built-in handling, which may pre-empt some
// expectations in Views/Aura if messages are consumed. Returns true if the
// message was consumed by the delegate and should not be processed further
// by the HWNDMessageHandler. In this case, |result| is returned. |result| is
// not modified otherwise.
virtual bool PreHandleMSG(
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_WIN_MESSAGE_HANDLER_DELEGATE_H_

View File

@@ -4,7 +4,10 @@
#include "atom/browser/ui/win/notify_icon.h"
#include <shobjidl.h>
#include "atom/browser/ui/win/notify_icon_host.h"
#include "base/md5.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/windows_version.h"
@@ -25,10 +28,24 @@ NotifyIcon::NotifyIcon(NotifyIconHost* host,
icon_id_(id),
window_(window),
message_id_(message),
menu_model_(NULL) {
menu_model_(NULL),
has_tray_app_id_hash_(false) {
// NB: If we have an App Model ID, we should propagate that to the tray.
// Doing this prevents duplicate items from showing up in the notification
// preferences (i.e. "Always Show / Show notifications only / etc")
PWSTR explicit_app_id;
if (SUCCEEDED(GetCurrentProcessExplicitAppUserModelID(&explicit_app_id))) {
// GUIDs and MD5 hashes are the same length. So convenient!
base::MD5Sum(explicit_app_id,
sizeof(wchar_t) * wcslen(explicit_app_id),
reinterpret_cast<base::MD5Digest*>(&tray_app_id_hash_));
has_tray_app_id_hash_ = true;
CoTaskMemFree(explicit_app_id);
}
NOTIFYICONDATA icon_data;
InitIconData(&icon_data);
icon_data.uFlags = NIF_MESSAGE;
icon_data.uFlags |= NIF_MESSAGE;
icon_data.uCallbackMessage = message_id_;
BOOL result = Shell_NotifyIcon(NIM_ADD, &icon_data);
// This can happen if the explorer process isn't running when we try to
@@ -46,39 +63,34 @@ NotifyIcon::~NotifyIcon() {
}
void NotifyIcon::HandleClickEvent(const gfx::Point& cursor_pos,
bool left_mouse_click) {
// Pass to the observer if appropriate.
int modifiers,
bool left_mouse_click,
bool double_button_click) {
NOTIFYICONIDENTIFIER icon_id;
memset(&icon_id, 0, sizeof(NOTIFYICONIDENTIFIER));
icon_id.uID = icon_id_;
icon_id.hWnd = window_;
icon_id.cbSize = sizeof(NOTIFYICONIDENTIFIER);
if (has_tray_app_id_hash_)
memcpy(reinterpret_cast<void*>(&icon_id.guidItem),
&tray_app_id_hash_,
sizeof(GUID));
RECT rect = { 0 };
Shell_NotifyIconGetRect(&icon_id, &rect);
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));
if (double_button_click) // double left click
NotifyDoubleClicked(gfx::Rect(rect), modifiers);
else // single left click
NotifyClicked(gfx::Rect(rect), modifiers);
return;
} else if (!double_button_click) { // single right click
if (menu_model_)
PopUpContextMenu(cursor_pos);
else
NotifyRightClicked(gfx::Rect(rect), modifiers);
}
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));
}
void NotifyIcon::ResetIcon() {
@@ -87,7 +99,7 @@ void NotifyIcon::ResetIcon() {
// Delete any previously existing icon.
Shell_NotifyIcon(NIM_DELETE, &icon_data);
InitIconData(&icon_data);
icon_data.uFlags = NIF_MESSAGE;
icon_data.uFlags |= NIF_MESSAGE;
icon_data.uCallbackMessage = message_id_;
icon_data.hIcon = icon_.Get();
// If we have an image, then set the NIF_ICON flag, which tells
@@ -104,7 +116,7 @@ void NotifyIcon::SetImage(const gfx::Image& image) {
// Create the icon.
NOTIFYICONDATA icon_data;
InitIconData(&icon_data);
icon_data.uFlags = NIF_ICON;
icon_data.uFlags |= NIF_ICON;
icon_.Set(IconUtil::CreateHICONFromSkBitmap(image.AsBitmap()));
icon_data.hIcon = icon_.Get();
BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data);
@@ -121,7 +133,7 @@ void NotifyIcon::SetToolTip(const std::string& tool_tip) {
// Create the icon.
NOTIFYICONDATA icon_data;
InitIconData(&icon_data);
icon_data.uFlags = NIF_TIP;
icon_data.uFlags |= NIF_TIP;
wcscpy_s(icon_data.szTip, base::UTF8ToUTF16(tool_tip).c_str());
BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data);
if (!result)
@@ -133,7 +145,7 @@ void NotifyIcon::DisplayBalloon(const gfx::Image& icon,
const base::string16& contents) {
NOTIFYICONDATA icon_data;
InitIconData(&icon_data);
icon_data.uFlags = NIF_INFO;
icon_data.uFlags |= NIF_INFO;
icon_data.dwInfoFlags = NIIF_INFO;
wcscpy_s(icon_data.szInfoTitle, title.c_str());
wcscpy_s(icon_data.szInfo, contents.c_str());
@@ -151,6 +163,26 @@ void NotifyIcon::DisplayBalloon(const gfx::Image& icon,
LOG(WARNING) << "Unable to create status tray balloon.";
}
void NotifyIcon::PopUpContextMenu(const gfx::Point& pos) {
// Returns if context menu isn't set.
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(pos, gfx::Size()),
views::MENU_ANCHOR_TOPLEFT,
ui::MENU_SOURCE_MOUSE));
}
void NotifyIcon::SetContextMenu(ui::SimpleMenuModel* menu_model) {
menu_model_ = menu_model;
}
@@ -160,6 +192,13 @@ void NotifyIcon::InitIconData(NOTIFYICONDATA* icon_data) {
icon_data->cbSize = sizeof(NOTIFYICONDATA);
icon_data->hWnd = window_;
icon_data->uID = icon_id_;
if (has_tray_app_id_hash_) {
icon_data->uFlags |= NIF_GUID;
memcpy(reinterpret_cast<void*>(&icon_data->guidItem),
&tray_app_id_hash_,
sizeof(GUID));
}
}
} // namespace atom

View File

@@ -33,7 +33,10 @@ class NotifyIcon : public TrayIcon {
// Handles a click event from the user - if |left_button_click| is true and
// there is a registered observer, passes the click event to the observer,
// otherwise displays the context menu if there is one.
void HandleClickEvent(const gfx::Point& cursor_pos, bool left_button_click);
void HandleClickEvent(const gfx::Point& cursor_pos,
int modifiers,
bool left_button_click,
bool double_button_click);
// Re-creates the status tray icon now after the taskbar has been created.
void ResetIcon();
@@ -49,6 +52,7 @@ class NotifyIcon : public TrayIcon {
void DisplayBalloon(const gfx::Image& icon,
const base::string16& title,
const base::string16& contents) override;
void PopUpContextMenu(const gfx::Point& pos) override;
void SetContextMenu(ui::SimpleMenuModel* menu_model) override;
private:
@@ -75,6 +79,10 @@ class NotifyIcon : public TrayIcon {
// The context menu.
ui::SimpleMenuModel* menu_model_;
// A hash of the app model ID
GUID tray_app_id_hash_;
bool has_tray_app_id_hash_;
DISALLOW_COPY_AND_ASSIGN(NotifyIcon);
};

View File

@@ -5,13 +5,16 @@
#include "atom/browser/ui/win/notify_icon_host.h"
#include <commctrl.h>
#include <winuser.h>
#include "atom/browser/ui/win/notify_icon.h"
#include "base/bind.h"
#include "base/stl_util.h"
#include "base/threading/non_thread_safe.h"
#include "base/threading/thread.h"
#include "base/win/win_util.h"
#include "base/win/wrapped_window_proc.h"
#include "ui/events/event_constants.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/win/hwnd_util.h"
@@ -26,6 +29,24 @@ const UINT kBaseIconId = 2;
const wchar_t kNotifyIconHostWindowClass[] = L"Electron_NotifyIconHostWindow";
bool IsWinPressed() {
return ((::GetKeyState(VK_LWIN) & 0x8000) == 0x8000) ||
((::GetKeyState(VK_RWIN) & 0x8000) == 0x8000);
}
int GetKeyboardModifers() {
int modifiers = ui::EF_NONE;
if (base::win::IsShiftPressed())
modifiers |= ui::EF_SHIFT_DOWN;
if (base::win::IsCtrlPressed())
modifiers |= ui::EF_CONTROL_DOWN;
if (base::win::IsAltPressed())
modifiers |= ui::EF_ALT_DOWN;
if (IsWinPressed())
modifiers |= ui::EF_COMMAND_DOWN;
return modifiers;
}
} // namespace
NotifyIconHost::NotifyIconHost()
@@ -146,12 +167,18 @@ LRESULT CALLBACK NotifyIconHost::WndProc(HWND hwnd,
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_LBUTTONDBLCLK:
case WM_RBUTTONDBLCLK:
case WM_CONTEXTMENU:
// Walk our icons, find which one was clicked on, and invoke its
// HandleClickEvent() method.
gfx::Point cursor_pos(
gfx::Screen::GetNativeScreen()->GetCursorScreenPoint());
win_icon->HandleClickEvent(cursor_pos, lparam == WM_LBUTTONDOWN);
win_icon->HandleClickEvent(
cursor_pos,
GetKeyboardModifers(),
(lparam == WM_LBUTTONDOWN || lparam == WM_LBUTTONDBLCLK),
(lparam == WM_LBUTTONDBLCLK || lparam == WM_RBUTTONDBLCLK));
return TRUE;
}
}

View File

@@ -0,0 +1,165 @@
// 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/win/taskbar_host.h"
#include <string>
#include "base/stl_util.h"
#include "base/win/scoped_gdi_object.h"
#include "base/strings/utf_string_conversions.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/icon_util.h"
namespace atom {
namespace {
// From MSDN: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378460(v=vs.85).aspx#thumbbars
// The thumbnail toolbar has a maximum of seven buttons due to the limited room.
const size_t kMaxButtonsCount = 7;
// The base id of Thumbar button.
const int kButtonIdBase = 40001;
bool GetThumbarButtonFlags(const std::vector<std::string>& flags,
THUMBBUTTONFLAGS* out) {
THUMBBUTTONFLAGS result = THBF_ENABLED; // THBF_ENABLED == 0
for (const auto& flag : flags) {
if (flag == "disabled")
result |= THBF_DISABLED;
else if (flag == "dismissonclick")
result |= THBF_DISMISSONCLICK;
else if (flag == "nobackground")
result |= THBF_NOBACKGROUND;
else if (flag == "hidden")
result |= THBF_HIDDEN;
else if (flag == "noninteractive")
result |= THBF_NONINTERACTIVE;
else
return false;
}
*out = result;
return true;
}
} // namespace
TaskbarHost::TaskbarHost() : thumbar_buttons_added_(false) {
}
TaskbarHost::~TaskbarHost() {
}
bool TaskbarHost::SetThumbarButtons(
HWND window, const std::vector<ThumbarButton>& buttons) {
if (buttons.size() > kMaxButtonsCount || !InitailizeTaskbar())
return false;
callback_map_.clear();
// The number of buttons in thumbar can not be changed once it is created,
// so we have to claim kMaxButtonsCount buttons initialy in case users add
// more buttons later.
base::win::ScopedHICON icons[kMaxButtonsCount] = {};
THUMBBUTTON thumb_buttons[kMaxButtonsCount] = {};
for (size_t i = 0; i < kMaxButtonsCount; ++i) {
THUMBBUTTON& thumb_button = thumb_buttons[i];
// Set ID.
thumb_button.iId = kButtonIdBase + i;
thumb_button.dwMask = THB_FLAGS;
if (i >= buttons.size()) {
// This button is used to occupy the place in toolbar, and it does not
// show.
thumb_button.dwFlags = THBF_HIDDEN;
continue;
}
// This button is user's button.
const ThumbarButton& button = buttons[i];
// Generate flags.
thumb_button.dwFlags = THBF_ENABLED;
if (!GetThumbarButtonFlags(button.flags, &thumb_button.dwFlags))
return false;
// Set icon.
if (!button.icon.IsEmpty()) {
thumb_button.dwMask |= THB_ICON;
icons[i] = IconUtil::CreateHICONFromSkBitmap(button.icon.AsBitmap());
thumb_button.hIcon = icons[i].Get();
}
// Set tooltip.
if (!button.tooltip.empty()) {
thumb_button.dwMask |= THB_TOOLTIP;
wcscpy_s(thumb_button.szTip, base::UTF8ToUTF16(button.tooltip).c_str());
}
// Save callback.
callback_map_[thumb_button.iId] = button.clicked_callback;
}
// Finally add them to taskbar.
HRESULT r;
if (thumbar_buttons_added_)
r = taskbar_->ThumbBarUpdateButtons(window, kMaxButtonsCount,
thumb_buttons);
else
r = taskbar_->ThumbBarAddButtons(window, kMaxButtonsCount, thumb_buttons);
thumbar_buttons_added_ = true;
return SUCCEEDED(r);
}
bool TaskbarHost::SetProgressBar(HWND window, double value) {
if (!InitailizeTaskbar())
return false;
HRESULT r;
if (value > 1.0)
r = taskbar_->SetProgressState(window, TBPF_INDETERMINATE);
else if (value < 0)
r = taskbar_->SetProgressState(window, TBPF_NOPROGRESS);
else
r = taskbar_->SetProgressValue(window, static_cast<int>(value * 100), 100);
return SUCCEEDED(r);
}
bool TaskbarHost::SetOverlayIcon(
HWND window, const gfx::Image& overlay, const std::string& text) {
if (!InitailizeTaskbar())
return false;
base::win::ScopedHICON icon(
IconUtil::CreateHICONFromSkBitmap(overlay.AsBitmap()));
return SUCCEEDED(
taskbar_->SetOverlayIcon(window, icon, base::UTF8ToUTF16(text).c_str()));
}
bool TaskbarHost::HandleThumbarButtonEvent(int button_id) {
if (ContainsKey(callback_map_, button_id)) {
auto callback = callback_map_[button_id];
if (!callback.is_null())
callback.Run();
return true;
}
return false;
}
bool TaskbarHost::InitailizeTaskbar() {
if (FAILED(taskbar_.CreateInstance(CLSID_TaskbarList,
nullptr,
CLSCTX_INPROC_SERVER)) ||
FAILED(taskbar_->HrInit())) {
return false;
} else {
return true;
}
}
} // namespace atom

View File

@@ -0,0 +1,64 @@
// 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_WIN_TASKBAR_HOST_H_
#define ATOM_BROWSER_UI_WIN_TASKBAR_HOST_H_
#include <shobjidl.h>
#include <map>
#include <string>
#include <vector>
#include "base/callback.h"
#include "base/win/scoped_comptr.h"
#include "ui/gfx/image/image.h"
namespace atom {
class TaskbarHost {
public:
struct ThumbarButton {
std::string tooltip;
gfx::Image icon;
std::vector<std::string> flags;
base::Closure clicked_callback;
};
TaskbarHost();
virtual ~TaskbarHost();
// Add or update the buttons in thumbar.
bool SetThumbarButtons(
HWND window, const std::vector<ThumbarButton>& buttons);
// Set the progress state in taskbar.
bool SetProgressBar(HWND window, double value);
// Set the overlay icon in taskbar.
bool SetOverlayIcon(
HWND window, const gfx::Image& overlay, const std::string& text);
// Called by the window that there is a button in thumbar clicked.
bool HandleThumbarButtonEvent(int button_id);
private:
// Initailize the taskbar object.
bool InitailizeTaskbar();
using CallbackMap = std::map<int, base::Closure>;
CallbackMap callback_map_;
// The COM object of taskbar.
base::win::ScopedComPtr<ITaskbarList3> taskbar_;
// Whether we have already added the buttons to thumbar.
bool thumbar_buttons_added_;
DISALLOW_COPY_AND_ASSIGN(TaskbarHost);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_WIN_TASKBAR_HOST_H_

View File

@@ -7,6 +7,9 @@
#include <X11/Xatom.h>
#include "base/strings/string_util.h"
#include "dbus/bus.h"
#include "dbus/object_proxy.h"
#include "dbus/message.h"
#include "ui/base/x/x11_util.h"
namespace atom {
@@ -46,4 +49,37 @@ void SetWindowType(::Window xwindow, const std::string& type) {
reinterpret_cast<unsigned char*>(&window_type), 1);
}
bool ShouldUseGlobalMenuBar() {
dbus::Bus::Options options;
scoped_refptr<dbus::Bus> bus(new dbus::Bus(options));
dbus::ObjectProxy* object_proxy =
bus->GetObjectProxy(DBUS_SERVICE_DBUS, dbus::ObjectPath(DBUS_PATH_DBUS));
dbus::MethodCall method_call(DBUS_INTERFACE_DBUS, "ListNames");
scoped_ptr<dbus::Response> response(object_proxy->CallMethodAndBlock(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
if (!response) {
bus->ShutdownAndBlock();
return false;
}
dbus::MessageReader reader(response.get());
dbus::MessageReader array_reader(NULL);
if (!reader.PopArray(&array_reader)) {
bus->ShutdownAndBlock();
return false;
}
while (array_reader.HasMoreData()) {
std::string name;
if (array_reader.PopString(&name) &&
name == "com.canonical.AppMenu.Registrar") {
bus->ShutdownAndBlock();
return true;
}
}
bus->ShutdownAndBlock();
return false;
}
} // namespace atom

View File

@@ -22,6 +22,9 @@ void SetWMSpecState(::Window xwindow, bool enabled, ::Atom state);
// Sets the _NET_WM_WINDOW_TYPE of window.
void SetWindowType(::Window xwindow, const std::string& type);
// Returns true if the bus name "com.canonical.AppMenu.Registrar" is available.
bool ShouldUseGlobalMenuBar();
} // namespace atom
#endif // ATOM_BROWSER_UI_X_X_WINDOW_UTILS_H_

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 "chrome/common/pref_names.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 {
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 {
// For MIME Type, `audio/*, vidio/*, image/*
net::GetExtensionsForMimeType(ascii_type, &extensions);
}
}
// If no valid exntesion is added, return empty filters.
if (extensions.empty())
return filters;
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(
prefs::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(prefs::kSelectFileLastDirectory,
paths[0].DirName());
}
}
}

View File

@@ -5,7 +5,9 @@
#include "atom/browser/web_view_guest_delegate.h"
#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "content/public/browser/guest_host.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
@@ -128,6 +130,12 @@ void WebViewGuestDelegate::RenderViewReady() {
render_view_host_view->SetBackgroundColor(SK_ColorTRANSPARENT);
}
void WebViewGuestDelegate::DidCommitProvisionalLoadForFrame(
content::RenderFrameHost* render_frame_host,
const GURL& url, ui::PageTransition transition_type) {
api_web_contents_->Emit("load-commit", url, !render_frame_host->GetParent());
}
void WebViewGuestDelegate::DidAttach(int guest_proxy_routing_id) {
api_web_contents_->Emit("did-attach");
}

View File

@@ -59,6 +59,9 @@ class WebViewGuestDelegate : public content::BrowserPluginGuestDelegate,
protected:
// content::WebContentsObserver:
void RenderViewReady() override;
void DidCommitProvisionalLoadForFrame(
content::RenderFrameHost* render_frame_host,
const GURL& url, ui::PageTransition transition_type) override;
// content::BrowserPluginGuestDelegate:
void DidAttach(int guest_proxy_routing_id) final;

View File

@@ -34,6 +34,10 @@ IPC_MESSAGE_ROUTED2(AtomViewMsg_Message,
base::string16 /* channel */,
base::ListValue /* arguments */)
IPC_MESSAGE_ROUTED2(AtomViewMsg_ExecuteJavaScript,
base::string16 /* code */,
bool /* has user gesture */)
// Sent by the renderer when the draggable regions are updated.
IPC_MESSAGE_ROUTED1(AtomViewHostMsg_UpdateDraggableRegions,
std::vector<atom::DraggableRegion> /* regions */)

View File

@@ -8,9 +8,9 @@
#include "atom_natives.h" // NOLINT: This file is generated with coffee2c.
#include "atom/common/asar/archive.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "native_mate/arguments.h"
#include "native_mate/callback.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h"
#include "native_mate/wrappable.h"

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

@@ -78,7 +78,7 @@ bool AddImageSkiaRep(gfx::ImageSkia* image,
if (!decoded)
return false;
image->AddRepresentation(gfx::ImageSkiaRep(*decoded.release(), scale_factor));
image->AddRepresentation(gfx::ImageSkiaRep(*decoded, scale_factor));
return true;
}
@@ -113,7 +113,7 @@ bool PopulateImageSkiaRepsFromPath(gfx::ImageSkia* image,
}
#if defined(OS_MACOSX)
bool IsTemplateImage(const base::FilePath& path) {
bool IsTemplateFilename(const base::FilePath& path) {
return (MatchPattern(path.value(), "*Template.*") ||
MatchPattern(path.value(), "*Template@*x.*"));
}
@@ -139,6 +139,7 @@ mate::ObjectTemplateBuilder NativeImage::GetObjectTemplateBuilder(
.SetMethod("isEmpty", &NativeImage::IsEmpty)
.SetMethod("getSize", &NativeImage::GetSize)
.SetMethod("setTemplateImage", &NativeImage::SetTemplateImage)
.SetMethod("isTemplateImage", &NativeImage::IsTemplateImage)
.Build());
return mate::ObjectTemplateBuilder(
@@ -180,6 +181,10 @@ gfx::Size NativeImage::GetSize() {
#if !defined(OS_MACOSX)
void NativeImage::SetTemplateImage(bool setAsTemplate) {
}
bool NativeImage::IsTemplateImage() {
return false;
}
#endif
// static
@@ -217,7 +222,7 @@ mate::Handle<NativeImage> NativeImage::CreateFromPath(
gfx::Image image(image_skia);
mate::Handle<NativeImage> handle = Create(isolate, image);
#if defined(OS_MACOSX)
if (IsTemplateImage(path))
if (IsTemplateFilename(path))
handle->SetTemplateImage(true);
#endif
return handle;

View File

@@ -67,6 +67,8 @@ class NativeImage : public mate::Wrappable {
// Mark the image as template image.
void SetTemplateImage(bool setAsTemplate);
// Determine if the image is a template image.
bool IsTemplateImage();
gfx::Image image_;

View File

@@ -14,6 +14,10 @@ void NativeImage::SetTemplateImage(bool setAsTemplate) {
[image_.AsNSImage() setTemplate:setAsTemplate];
}
bool NativeImage::IsTemplateImage() {
return [image_.AsNSImage() isTemplate];
}
} // namespace api
} // namespace atom

View File

@@ -98,6 +98,10 @@ void AtomBindings::OnCallNextTick(uv_async_t* handle) {
if (tick_info->in_tick())
continue;
if (tick_info->length() == 0) {
env->isolate()->RunMicrotasks();
}
if (tick_info->length() == 0) {
tick_info->set_index(0);
continue;

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