Compare commits

..

85 Commits

Author SHA1 Message Date
Cheng Zhao
68ac6b0cbb Bump v0.16.0. 2014-09-06 20:58:34 +08:00
Cheng Zhao
7fb1cb5b3d Merge pull request #612 from nuivall/master
win: Don't overwrite Chrome high DPI setting.
2014-09-06 20:55:58 +08:00
Cheng Zhao
19b25c0d83 Make dialog API's parameters more flexible. 2014-09-06 18:56:28 +08:00
Cheng Zhao
fd806f81ce linux: Don't set PR_SET_NO_NEW_PRIVS when creating process, fixes #623. 2014-09-05 21:04:27 +08:00
Cheng Zhao
d515404abd Merge pull request #626 from atom/v8-debugger
Implement V8 debugger agent
2014-09-05 13:40:37 +08:00
Cheng Zhao
4509056d5e docs: Add notes on OS X application menu. 2014-09-05 13:39:29 +08:00
Cheng Zhao
f604525b98 mac: Enable setting "Services" menu.
Regarding https://github.com/atom/atom/issues/3204.
2014-09-05 13:07:05 +08:00
Cheng Zhao
3afbb66b92 Send message to client in debugger thread. 2014-09-05 11:51:45 +08:00
Cheng Zhao
fadfd74923 win: Fix compilation error. 2014-09-05 11:44:30 +08:00
Cheng Zhao
222f8e1028 Make --debug-brk work. 2014-09-05 10:59:29 +08:00
Cheng Zhao
e3b6ea62d6 Send connect message if client is connected. 2014-09-05 10:52:47 +08:00
Cheng Zhao
3795cc58b0 Pass debugger messages between V8 debugger. 2014-09-05 10:44:07 +08:00
Cheng Zhao
ed7d430f2b Pass header sent from client. 2014-09-05 09:39:28 +08:00
Cheng Zhao
20f21b707b Start a TCP server in the debugger thread. 2014-09-04 23:02:18 +08:00
Cheng Zhao
a584ca3678 Start a new debugger thread to listen for commands. 2014-09-04 21:06:31 +08:00
Cheng Zhao
ca881c5aaf win: Fix compilation with Chrome 37. 2014-09-03 23:17:00 +08:00
Cheng Zhao
2832708618 Merge pull request #622 from atom/chrome37
Upgrade to Chrome37
2014-09-02 17:03:07 +08:00
Cheng Zhao
b00e56f587 Upgrade to apm@0.93.0 2014-09-02 10:58:42 +08:00
Cheng Zhao
d64f43da65 Merge pull request #624 from Rahazan/patch-1
Small typo fix in fatal JS error message
2014-09-02 09:55:07 +08:00
Guido Zuidhof
3e6d8ddbbd Small typo fix in fatal JS error message
An javascript error -> A javascript error
2014-09-01 21:02:03 +02:00
Cheng Zhao
533548fdc7 Use atom-shell's version for creating node headers tarball. 2014-09-01 22:54:20 +08:00
Cheng Zhao
3b95f49a14 Upgrade node to fix child_process.fork. 2014-09-01 22:32:58 +08:00
Cheng Zhao
d9d1d03d4d linux: Dont' use native style border. 2014-09-01 20:22:38 +08:00
Cheng Zhao
9546120ce4 linux: Fix API changes of Chrome 37. 2014-09-01 20:10:14 +08:00
Cheng Zhao
48a5591508 Upgrade brightray. 2014-09-01 19:18:45 +08:00
Cheng Zhao
a413935e91 Initialize node after WebKit is initialized. 2014-09-01 18:43:43 +08:00
Cheng Zhao
241b07f763 Initailize V8 with gin. 2014-09-01 16:41:26 +08:00
Cheng Zhao
d874ba80db Upgrade libchromiumcontent for gin headers. 2014-09-01 16:08:08 +08:00
Cheng Zhao
3e46363ae1 Fix API changes of Chrome 37. 2014-09-01 15:36:37 +08:00
Cheng Zhao
d4a46fa35f Comment out debugger agent.
V8 has discarded support for debugger agent, we should reimplement it in
atom-shell.
2014-09-01 15:35:56 +08:00
Cheng Zhao
134f8236cc Update printing code to Chrome 37. 2014-09-01 15:35:39 +08:00
Cheng Zhao
55003716aa Upgrade node for Chrome 37. 2014-09-01 15:08:19 +08:00
Cheng Zhao
fe88330e87 Upgrade brightray to Chrome 37. 2014-09-01 13:59:01 +08:00
Cheng Zhao
ed68bd18b8 Upgrade libchromiumcontent to Chrome 37. 2014-09-01 13:33:03 +08:00
Cheng Zhao
45228493eb Merge pull request #610 from atom/devtools-extension
Add support for chrome devtools extension
2014-08-28 23:12:21 +08:00
Cheng Zhao
80fb44b926 docs: Add docs on how to use chrome devtools extension. 2014-08-28 16:33:27 +08:00
Cheng Zhao
aa8f5e54df dev-tools => devtools. 2014-08-28 16:00:29 +08:00
Cheng Zhao
8134585578 Remember loaded extensions. 2014-08-28 15:58:36 +08:00
Cheng Zhao
a59388ecdd Add "dev-tools-opened" and "dev-tools-closed" events. 2014-08-28 14:25:00 +08:00
Cheng Zhao
8051ad8b2a Add support for chrome.extension API in devtools extension. 2014-08-28 12:54:19 +08:00
Cheng Zhao
0a937cd2be Merge pull request #614 from atom/atom-shell-squirrel
Atom.exe should receive Squirrel events
2014-08-28 10:06:24 +08:00
Paul Betts
db11c631f6 Atom.exe should receive Squirrel events
This sets up Atom to be packaged into a Squirrel installer. See
https://github.com/Squirrel/Squirrel.Windows.Next/pull/17 for the details
2014-08-27 17:06:26 -07:00
Marcin Maliszkiewicz
90bfd4bf0f win: Don't overwrite Chrome hight DPI setting.
Also disable high DPI mode by default, Chrome enables it since
https://codereview.chromium.org/294293002
2014-08-27 20:14:41 +02:00
Cheng Zhao
39b98b0e4d Fix cpplint warnings. 2014-08-27 21:16:45 +08:00
Cheng Zhao
b6c2e7ef76 Ignore requests to other hosts. 2014-08-27 21:05:54 +08:00
Cheng Zhao
fe96a9de33 Don't use pure number as host name.
Numbers would be treated as IP addresses.
2014-08-27 20:49:57 +08:00
Cheng Zhao
b80f109524 Make "chrome-extension" a standard scheme.
If we do not do so, urls like "chrome-extension://extension-1" will
never get a hostname.
2014-08-27 20:48:49 +08:00
Cheng Zhao
cd40bdbec8 Add chrome-extension protocol for loading devtools extensions. 2014-08-27 16:01:15 +08:00
Cheng Zhao
1533600720 Upgrade libchromiumcontent to loose iframe sandbox. 2014-08-26 22:27:50 +08:00
Cheng Zhao
263c4b9ab4 Turn off web security for devtools. 2014-08-26 16:05:10 +08:00
Cheng Zhao
f1e72914f5 Update brightray for devtools zooming. 2014-08-26 15:11:26 +08:00
Cheng Zhao
400d5cef3f linux: Fix BrowserWindow.setResizable. 2014-08-26 13:37:37 +08:00
Cheng Zhao
af531d685e linux: Make BrowserWindow.setSkipTaskbar work dynamically. 2014-08-26 12:15:22 +08:00
Cheng Zhao
eb5f1f78bf linux: Set WM_CLASS and WM_WINDOW_ROLE for window, fixes #605. 2014-08-26 10:34:48 +08:00
Cheng Zhao
c81a4bcafc Don't use third party dependency in default_app. 2014-08-26 09:50:45 +08:00
Cheng Zhao
1beeda170c Merge pull request #606 from hokein/master
docs: Correct debugging chapter.
2014-08-25 18:55:09 +08:00
Haojian Wu
9ad81c054d docs: Correct debugging chapter. 2014-08-25 13:08:11 +08:00
Cheng Zhao
5604e75886 Merge pull request #603 from soh1988/patch-corrections
Correction to the API Documentation of the Browser FlashFrame
2014-08-23 19:18:38 +08:00
Cheng Zhao
2e7ef7ea44 Merge pull request #602 from soh1988/patch-minSize
Changing the Logical Or to Bitwise Or to change from Either to Either Or...
2014-08-23 19:17:54 +08:00
Chris Soh
a0867fa7c5 Changing the Logical Or to Bitwise Or to change from Either to Either Or Both values 2014-08-23 13:30:43 +08:00
Chris Soh
31f5855001 Adding the compulsory flag in the API documentation of BrowserWindow.flashFrame 2014-08-23 13:20:47 +08:00
Cheng Zhao
0b24883649 Merge pull request #599 from atom/printing
Add support for printing
2014-08-22 17:48:36 +08:00
Cheng Zhao
4fda81a0b4 Document the BrowserWindow.print(). 2014-08-22 15:14:49 +08:00
Cheng Zhao
17c0888932 Make print settings optional. 2014-08-22 15:05:30 +08:00
Cheng Zhao
d20ec6952a Revert "Move the code of getting printing settings to another class."
This reverts commit 57d06c5241.

Conflicts:
	atom/browser/printing/printing_config_service.cc
2014-08-22 15:03:39 +08:00
Cheng Zhao
e43b3309af Add "silent" and "print_background" option for printing. 2014-08-22 15:01:07 +08:00
Cheng Zhao
d0c1b63064 linux: Fix linking error. 2014-08-22 13:03:27 +08:00
Cheng Zhao
a98e26a307 Fix handling failed print. 2014-08-22 13:01:49 +08:00
Cheng Zhao
57d06c5241 Move the code of getting printing settings to another class. 2014-08-22 12:46:26 +08:00
Cheng Zhao
f28e4574b0 Simplify global-shortcut's code. 2014-08-22 10:53:37 +08:00
Cheng Zhao
c9b284d7f7 Remove more unused printing code. 2014-08-22 10:27:08 +08:00
Cheng Zhao
99a510701d Strip out print preview. 2014-08-21 22:14:27 +08:00
Cheng Zhao
eb3ecab6a8 Setup PrintingMessageFilter for printing. 2014-08-21 21:19:43 +08:00
Cheng Zhao
11b9a06639 Add BrowserWindow.print() method. 2014-08-21 21:00:49 +08:00
Cheng Zhao
87d5b72b76 Initailize PrintViewManagerBasic for browser window. 2014-08-21 20:49:18 +08:00
Cheng Zhao
c95869e515 Fix cpplint warnings. 2014-08-21 20:25:12 +08:00
Cheng Zhao
c2f7920068 Upgrade libchromiumcontent to contain printing headers. 2014-08-21 16:38:25 +08:00
Cheng Zhao
cb7196a9c1 Allow script initialized window.print(). 2014-08-21 16:32:41 +08:00
Cheng Zhao
7de0f71a75 Fix compiling with print messages. 2014-08-21 16:14:22 +08:00
Cheng Zhao
8dcb3726f9 Initialize the fake BrowserProcess object. 2014-08-21 15:45:34 +08:00
Cheng Zhao
d934526bb3 Add printing related source codes from chrome. 2014-08-21 15:43:11 +08:00
Cheng Zhao
cab546cbb7 No more need to flip rect for capturePage, fixes #589. 2014-08-21 12:40:31 +08:00
Cheng Zhao
058d0bbe19 linux: Add "dark-theme" option for BrowserWindow, fixes #352. 2014-08-21 12:25:43 +08:00
Cheng Zhao
a32669ac0d Merge pull request #594 from PeterDaveHello/patch-1
make CI build faster
2014-08-21 10:37:48 +08:00
Peter Dave Hello
cc4b3e9e6f make CI build faster 2014-08-20 22:49:37 +08:00
106 changed files with 6799 additions and 230 deletions

View File

@@ -10,3 +10,6 @@ notifications:
on_failure: change
script: './script/cibuild'
git:
depth: 10

View File

@@ -28,6 +28,7 @@
'atom/browser/api/lib/protocol.coffee',
'atom/browser/api/lib/tray.coffee',
'atom/browser/api/lib/web-contents.coffee',
'atom/browser/lib/chrome-extension.coffee',
'atom/browser/lib/init.coffee',
'atom/browser/lib/objects-registry.coffee',
'atom/browser/lib/rpc-server.coffee',
@@ -38,6 +39,7 @@
'atom/common/api/lib/screen.coffee',
'atom/common/api/lib/shell.coffee',
'atom/common/lib/init.coffee',
'atom/renderer/lib/chrome-api.coffee',
'atom/renderer/lib/init.coffee',
'atom/renderer/lib/inspector.coffee',
'atom/renderer/lib/override.coffee',
@@ -46,6 +48,8 @@
'atom/renderer/api/lib/web-view.coffee',
],
'lib_sources': [
'atom/app/atom_content_client.cc',
'atom/app/atom_content_client.h',
'atom/app/atom_main_delegate.cc',
'atom/app/atom_main_delegate.h',
'atom/app/atom_main_delegate_mac.mm',
@@ -164,10 +168,11 @@
'atom/browser/ui/win/notify_icon_host.h',
'atom/browser/ui/win/notify_icon.cc',
'atom/browser/ui/win/notify_icon.h',
'atom/browser/ui/x/x_window_utils.cc',
'atom/browser/ui/x/x_window_utils.h',
'atom/browser/window_list.cc',
'atom/browser/window_list.h',
'atom/browser/window_list_observer.h',
'atom/common/api/api_messages.cc',
'atom/common/api/api_messages.h',
'atom/common/api/atom_api_clipboard.cc',
'atom/common/api/atom_api_crash_reporter.cc',
@@ -181,6 +186,8 @@
'atom/common/api/atom_bindings.h',
'atom/common/api/object_life_monitor.cc',
'atom/common/api/object_life_monitor.h',
'atom/common/common_message_generator.cc',
'atom/common/common_message_generator.h',
'atom/common/crash_reporter/crash_reporter.cc',
'atom/common/crash_reporter/crash_reporter.h',
'atom/common/crash_reporter/crash_reporter_linux.cc',
@@ -233,6 +240,9 @@
'atom/renderer/atom_render_view_observer.h',
'atom/renderer/atom_renderer_client.cc',
'atom/renderer/atom_renderer_client.h',
'chromium_src/chrome/browser/browser_process.cc',
'chromium_src/chrome/browser/browser_process.h',
'chromium_src/chrome/browser/chrome_notification_types.h',
'chromium_src/chrome/browser/extensions/global_shortcut_listener.cc',
'chromium_src/chrome/browser/extensions/global_shortcut_listener.h',
'chromium_src/chrome/browser/extensions/global_shortcut_listener_mac.mm',
@@ -241,6 +251,24 @@
'chromium_src/chrome/browser/extensions/global_shortcut_listener_x11.h',
'chromium_src/chrome/browser/extensions/global_shortcut_listener_win.cc',
'chromium_src/chrome/browser/extensions/global_shortcut_listener_win.h',
'chromium_src/chrome/browser/printing/print_job.cc',
'chromium_src/chrome/browser/printing/print_job.h',
'chromium_src/chrome/browser/printing/print_job_manager.cc',
'chromium_src/chrome/browser/printing/print_job_manager.h',
'chromium_src/chrome/browser/printing/print_job_worker.cc',
'chromium_src/chrome/browser/printing/print_job_worker.h',
'chromium_src/chrome/browser/printing/print_job_worker_owner.h',
'chromium_src/chrome/browser/printing/print_view_manager_base.cc',
'chromium_src/chrome/browser/printing/print_view_manager_base.h',
'chromium_src/chrome/browser/printing/print_view_manager_basic.cc',
'chromium_src/chrome/browser/printing/print_view_manager_basic.h',
'chromium_src/chrome/browser/printing/print_view_manager_observer.h',
'chromium_src/chrome/browser/printing/printer_query.cc',
'chromium_src/chrome/browser/printing/printer_query.h',
'chromium_src/chrome/browser/printing/printing_message_filter.cc',
'chromium_src/chrome/browser/printing/printing_message_filter.h',
'chromium_src/chrome/browser/printing/printing_ui_web_contents_observer.cc',
'chromium_src/chrome/browser/printing/printing_ui_web_contents_observer.h',
'chromium_src/chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.cc',
'chromium_src/chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.h',
'chromium_src/chrome/browser/ui/libgtk2ui/gtk2_status_icon.cc',
@@ -249,6 +277,13 @@
'chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h',
'chromium_src/chrome/browser/ui/views/status_icons/status_tray_state_changer_win.cc',
'chromium_src/chrome/browser/ui/views/status_icons/status_tray_state_changer_win.h',
'chromium_src/chrome/common/print_messages.cc',
'chromium_src/chrome/common/print_messages.h',
'chromium_src/chrome/renderer/printing/print_web_view_helper.cc',
'chromium_src/chrome/renderer/printing/print_web_view_helper_linux.cc',
'chromium_src/chrome/renderer/printing/print_web_view_helper_mac.mm',
'chromium_src/chrome/renderer/printing/print_web_view_helper_win.cc',
'chromium_src/chrome/renderer/printing/print_web_view_helper.h',
'<@(native_mate_files)',
],
'framework_sources': [
@@ -439,6 +474,10 @@
'vendor/brightray/brightray.gyp:brightray',
'vendor/node/node.gyp:node_lib',
],
'defines': [
# This is defined in skia/skia_common.gypi.
'SK_SUPPORT_LEGACY_GETTOPDEVICE',
],
'sources': [
'<@(lib_sources)',
],

View File

@@ -0,0 +1,24 @@
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/app/atom_content_client.h"
#include <string>
#include <vector>
namespace atom {
AtomContentClient::AtomContentClient() {
}
AtomContentClient::~AtomContentClient() {
}
void AtomContentClient::AddAdditionalSchemes(
std::vector<std::string>* standard_schemes,
std::vector<std::string>* savable_schemes) {
standard_schemes->push_back("chrome-extension");
}
} // namespace atom

View File

@@ -0,0 +1,32 @@
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_APP_ATOM_CONTENT_CLIENT_H_
#define ATOM_APP_ATOM_CONTENT_CLIENT_H_
#include <string>
#include <vector>
#include "brightray/common/content_client.h"
namespace atom {
class AtomContentClient : public brightray::ContentClient {
public:
AtomContentClient();
virtual ~AtomContentClient();
protected:
// content::ContentClient:
virtual void AddAdditionalSchemes(
std::vector<std::string>* standard_schemes,
std::vector<std::string>* savable_schemes) OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(AtomContentClient);
};
} // namespace atom
#endif // ATOM_APP_ATOM_CONTENT_CLIENT_H_

View File

@@ -18,7 +18,6 @@
#include "atom/app/atom_main_delegate.h"
#include "atom/common/crash_reporter/win/crash_service_main.h"
#include "base/environment.h"
#include "base/win/registry.h"
#include "content/public/app/startup_helper_win.h"
#include "sandbox/win/src/sandbox_types.h"
#include "ui/gfx/win/dpi.h"
@@ -36,13 +35,6 @@ int Start(int argc, char *argv[]);
#if defined(OS_WIN)
namespace {
const wchar_t kRegistryProfilePath[] = L"SOFTWARE\\Google\\Chrome\\Profile";
const wchar_t kHighDPISupportW[] = L"high-dpi-support";
} // namespace
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
int argc = 0;
wchar_t** wargv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
@@ -109,10 +101,6 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
atom::AtomMainDelegate delegate;
// Now chrome relies on a regkey to enable high dpi support.
base::win::RegKey high_dpi_key(HKEY_CURRENT_USER);
high_dpi_key.CreateKey(kRegistryProfilePath, KEY_SET_VALUE);
high_dpi_key.WriteValue(kHighDPISupportW, 1);
gfx::EnableHighDPISupport();
content::ContentMainParams params(&delegate);

View File

@@ -6,6 +6,7 @@
#include <string>
#include "atom/app/atom_content_client.h"
#include "atom/browser/atom_browser_client.h"
#include "atom/renderer/atom_renderer_client.h"
#include "base/command_line.h"
@@ -22,18 +23,6 @@ AtomMainDelegate::AtomMainDelegate() {
AtomMainDelegate::~AtomMainDelegate() {
}
void AtomMainDelegate::AddDataPackFromPath(
ui::ResourceBundle* bundle, const base::FilePath& pak_dir) {
#if defined(OS_WIN)
bundle->AddDataPackFromPath(
pak_dir.Append(FILE_PATH_LITERAL("ui_resources_200_percent.pak")),
ui::SCALE_FACTOR_200P);
bundle->AddDataPackFromPath(
pak_dir.Append(FILE_PATH_LITERAL("webkit_resources_200_percent.pak")),
ui::SCALE_FACTOR_200P);
#endif
}
bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
// Disable logging out to debug.log on Windows
#if defined(OS_WIN)
@@ -99,4 +88,20 @@ content::ContentRendererClient*
return renderer_client_.get();
}
scoped_ptr<brightray::ContentClient> AtomMainDelegate::CreateContentClient() {
return scoped_ptr<brightray::ContentClient>(new AtomContentClient).Pass();
}
void AtomMainDelegate::AddDataPackFromPath(
ui::ResourceBundle* bundle, const base::FilePath& pak_dir) {
#if defined(OS_WIN)
bundle->AddDataPackFromPath(
pak_dir.Append(FILE_PATH_LITERAL("ui_resources_200_percent.pak")),
ui::SCALE_FACTOR_200P);
bundle->AddDataPackFromPath(
pak_dir.Append(FILE_PATH_LITERAL("webkit_resources_200_percent.pak")),
ui::SCALE_FACTOR_200P);
#endif
}
} // namespace atom

View File

@@ -16,24 +16,23 @@ class AtomMainDelegate : public brightray::MainDelegate {
~AtomMainDelegate();
protected:
// brightray::MainDelegate:
virtual void AddDataPackFromPath(
ui::ResourceBundle* bundle, const base::FilePath& pak_dir) OVERRIDE;
// content::ContentMainDelegate:
virtual bool BasicStartupComplete(int* exit_code) OVERRIDE;
virtual void PreSandboxStartup() OVERRIDE;
virtual content::ContentBrowserClient* CreateContentBrowserClient() OVERRIDE;
virtual content::ContentRendererClient*
CreateContentRendererClient() OVERRIDE;
// brightray::MainDelegate:
virtual scoped_ptr<brightray::ContentClient> CreateContentClient() OVERRIDE;
virtual void AddDataPackFromPath(
ui::ResourceBundle* bundle, const base::FilePath& pak_dir) OVERRIDE;
#if defined(OS_MACOSX)
virtual void OverrideChildProcessPath() OVERRIDE;
virtual void OverrideFrameworkBundlePath() OVERRIDE;
#endif
private:
virtual content::ContentBrowserClient* CreateContentBrowserClient() OVERRIDE;
virtual content::ContentRendererClient*
CreateContentRendererClient() OVERRIDE;
brightray::ContentClient content_client_;
scoped_ptr<content::ContentBrowserClient> browser_client_;
scoped_ptr<content::ContentRendererClient> renderer_client_;

View File

@@ -66,22 +66,13 @@ void GlobalShortcut::UnregisterAll() {
GlobalShortcutListener::GetInstance()->UnregisterAccelerators(this);
}
// static
mate::ObjectTemplateBuilder GlobalShortcut::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return mate::ObjectTemplateBuilder(isolate)
.SetMethod("register",
base::Bind(&GlobalShortcut::Register,
base::Unretained(this)))
.SetMethod("isRegistered",
base::Bind(&GlobalShortcut::IsRegistered,
base::Unretained(this)))
.SetMethod("unregister",
base::Bind(&GlobalShortcut::Unregister,
base::Unretained(this)))
.SetMethod("unregisterAll",
base::Bind(&GlobalShortcut::UnregisterAll,
base::Unretained(this)));
.SetMethod("register", &GlobalShortcut::Register)
.SetMethod("isRegistered", &GlobalShortcut::IsRegistered)
.SetMethod("unregister", &GlobalShortcut::Unregister)
.SetMethod("unregisterAll", &GlobalShortcut::UnregisterAll);
}
// static

View File

@@ -16,8 +16,30 @@
#include "atom/common/node_includes.h"
namespace {
struct PrintSettings {
bool silent;
bool print_backgournd;
};
} // namespace
namespace mate {
template<>
struct Converter<PrintSettings> {
static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val,
PrintSettings* out) {
mate::Dictionary dict;
if (!ConvertFromV8(isolate, val, &dict))
return false;
dict.Get("silent", &(out->silent));
dict.Get("printBackground", &(out->print_backgournd));
return true;
}
};
template<>
struct Converter<gfx::Rect> {
static bool FromV8(v8::Isolate* isolate,
@@ -303,6 +325,22 @@ bool Window::IsWebViewFocused() {
return window_->IsWebViewFocused();
}
void Window::SetRepresentedFilename(const std::string& filename) {
window_->SetRepresentedFilename(filename);
}
std::string Window::GetRepresentedFilename() {
return window_->GetRepresentedFilename();
}
void Window::SetDocumentEdited(bool edited) {
window_->SetDocumentEdited(edited);
}
bool Window::IsDocumentEdited() {
return window_->IsDocumentEdited();
}
void Window::CapturePage(mate::Arguments* args) {
gfx::Rect rect;
base::Callback<void(v8::Handle<v8::Value>)> callback;
@@ -318,20 +356,14 @@ void Window::CapturePage(mate::Arguments* args) {
rect, base::Bind(&OnCapturePageDone, args->isolate(), callback));
}
void Window::SetRepresentedFilename(const std::string& filename) {
window_->SetRepresentedFilename(filename);
}
void Window::Print(mate::Arguments* args) {
PrintSettings settings = { false, false };;
if (args->Length() == 1 && !args->GetNext(&settings)) {
args->ThrowError();
return;
}
std::string Window::GetRepresentedFilename() {
return window_->GetRepresentedFilename();
}
void Window::SetDocumentEdited(bool edited) {
window_->SetDocumentEdited(edited);
}
bool Window::IsDocumentEdited() {
return window_->IsDocumentEdited();
window_->Print(settings.silent, settings.print_backgournd);
}
mate::Handle<WebContents> Window::GetWebContents(v8::Isolate* isolate) const {
@@ -386,7 +418,7 @@ void Window::BuildPrototype(v8::Isolate* isolate,
.SetMethod("setRepresentedFilename", &Window::SetRepresentedFilename)
.SetMethod("getRepresentedFilename", &Window::GetRepresentedFilename)
.SetMethod("setDocumentEdited", &Window::SetDocumentEdited)
.SetMethod("IsDocumentEdited", &Window::IsDocumentEdited)
.SetMethod("isDocumentEdited", &Window::IsDocumentEdited)
.SetMethod("_openDevTools", &Window::OpenDevTools)
.SetMethod("closeDevTools", &Window::CloseDevTools)
.SetMethod("isDevToolsOpened", &Window::IsDevToolsOpened)
@@ -395,6 +427,7 @@ void Window::BuildPrototype(v8::Isolate* isolate,
.SetMethod("blurWebView", &Window::BlurWebView)
.SetMethod("isWebViewFocused", &Window::IsWebViewFocused)
.SetMethod("capturePage", &Window::CapturePage)
.SetMethod("print", &Window::Print)
.SetMethod("_getWebContents", &Window::GetWebContents)
.SetMethod("_getDevToolsWebContents", &Window::GetDevToolsWebContents);
}

View File

@@ -97,11 +97,12 @@ class Window : public mate::EventEmitter,
void FocusOnWebView();
void BlurWebView();
bool IsWebViewFocused();
void CapturePage(mate::Arguments* args);
void SetRepresentedFilename(const std::string& filename);
std::string GetRepresentedFilename();
void SetDocumentEdited(bool edited);
bool IsDocumentEdited();
void CapturePage(mate::Arguments* args);
void Print(mate::Arguments* args);
// APIs for WebContents.
mate::Handle<WebContents> GetWebContents(v8::Isolate* isolate) const;

View File

@@ -35,6 +35,10 @@ BrowserWindow::openDevTools = ->
@devToolsWebContents = @getDevToolsWebContents()
@devToolsWebContents.once 'destroyed', => @devToolsWebContents = null
# Emit devtools events.
@devToolsWebContents.once 'did-finish-load', => @emit 'devtools-opened'
@devToolsWebContents.once 'destroyed', => @emit 'devtools-closed'
BrowserWindow::toggleDevTools = ->
if @isDevToolsOpened() then @closeDevTools() else @openDevTools()

View File

@@ -10,13 +10,21 @@ fileDialogProperties =
messageBoxTypes = ['none', 'info', 'warning']
parseArgs = (window, options, callback) ->
unless window is null or window?.constructor is BrowserWindow
# Shift.
callback = options
options = window
window = null
if not callback? and typeof options is 'function'
# Shift.
callback = options
options = null
[window, options, callback]
module.exports =
showOpenDialog: (window, options, callback) ->
unless window?.constructor is BrowserWindow
# Shift.
callback = options
options = window
window = null
showOpenDialog: (args...) ->
[window, options, callback] = parseArgs args...
options ?= title: 'Open', properties: ['openFile']
options.properties ?= ['openFile']
@@ -44,11 +52,7 @@ module.exports =
wrappedCallback
showSaveDialog: (window, options, callback) ->
unless window?.constructor is BrowserWindow
# Shift.
callback = options
options = window
window = null
[window, options, callback] = parseArgs args...
options ?= title: 'Save'
options.title ?= ''
@@ -68,11 +72,7 @@ module.exports =
wrappedCallback
showMessageBox: (window, options, callback) ->
unless window?.constructor is BrowserWindow
# Shift.
callback = options
options = window
window = null
[window, options, callback] = parseArgs args...
options ?= type: 'none'
options.type ?= 'none'

View File

@@ -10,6 +10,7 @@
#include "atom/browser/atom_resource_dispatcher_host_delegate.h"
#include "atom/browser/native_window.h"
#include "atom/browser/window_list.h"
#include "chrome/browser/printing/printing_message_filter.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/resource_dispatcher_host.h"
@@ -48,6 +49,11 @@ AtomBrowserClient::AtomBrowserClient()
AtomBrowserClient::~AtomBrowserClient() {
}
void AtomBrowserClient::RenderProcessWillLaunch(
content::RenderProcessHost* host) {
host->AddFilter(new PrintingMessageFilter(host->GetID()));
}
void AtomBrowserClient::ResourceDispatcherHostCreated() {
resource_dispatcher_delegate_.reset(new AtomResourceDispatcherHostDelegate);
content::ResourceDispatcherHost::Get()->SetDelegate(
@@ -79,6 +85,12 @@ void AtomBrowserClient::OverrideWebkitPrefs(
prefs->allow_displaying_insecure_content = true;
prefs->allow_running_insecure_content = true;
// Turn off web security for devtools.
if (url.SchemeIs("chrome-devtools")) {
prefs->web_security_enabled = false;
return;
}
NativeWindow* window = NativeWindow::FromRenderView(
render_view_host->GetProcess()->GetID(),
render_view_host->GetRoutingID());

View File

@@ -20,6 +20,8 @@ class AtomBrowserClient : public brightray::BrowserClient {
protected:
// content::ContentBrowserClient:
virtual void RenderProcessWillLaunch(
content::RenderProcessHost* host) OVERRIDE;
virtual void ResourceDispatcherHostCreated() OVERRIDE;
virtual content::AccessTokenStore* CreateAccessTokenStore() OVERRIDE;
virtual void OverrideWebkitPrefs(content::RenderViewHost* render_view_host,

View File

@@ -8,18 +8,21 @@
#include "atom/browser/net/atom_url_request_job_factory.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/worker_pool.h"
#include "chrome/browser/browser_process.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/url_constants.h"
#include "net/url_request/data_protocol_handler.h"
#include "net/url_request/file_protocol_handler.h"
#include "net/url_request/protocol_intercept_job_factory.h"
#include "net/url_request/url_request_intercepting_job_factory.h"
#include "url/url_constants.h"
using content::BrowserThread;
namespace atom {
AtomBrowserContext::AtomBrowserContext()
: job_factory_(new AtomURLRequestJobFactory) {
: fake_browser_process_(new BrowserProcess),
job_factory_(new AtomURLRequestJobFactory) {
}
AtomBrowserContext::~AtomBrowserContext() {
@@ -27,7 +30,7 @@ AtomBrowserContext::~AtomBrowserContext() {
net::URLRequestJobFactory* AtomBrowserContext::CreateURLRequestJobFactory(
content::ProtocolHandlerMap* handlers,
content::ProtocolHandlerScopedVector* interceptors) {
content::URLRequestInterceptorScopedVector* interceptors) {
scoped_ptr<AtomURLRequestJobFactory> job_factory(job_factory_);
for (content::ProtocolHandlerMap::iterator it = handlers->begin();
@@ -36,18 +39,18 @@ net::URLRequestJobFactory* AtomBrowserContext::CreateURLRequestJobFactory(
handlers->clear();
job_factory->SetProtocolHandler(
content::kDataScheme, new net::DataProtocolHandler);
url::kDataScheme, new net::DataProtocolHandler);
job_factory->SetProtocolHandler(
content::kFileScheme, new net::FileProtocolHandler(
url::kFileScheme, new net::FileProtocolHandler(
BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)));
// Set up interceptors in the reverse order.
scoped_ptr<net::URLRequestJobFactory> top_job_factory =
job_factory.PassAs<net::URLRequestJobFactory>();
content::ProtocolHandlerScopedVector::reverse_iterator it;
content::URLRequestInterceptorScopedVector::reverse_iterator it;
for (it = interceptors->rbegin(); it != interceptors->rend(); ++it)
top_job_factory.reset(new net::ProtocolInterceptJobFactory(
top_job_factory.reset(new net::URLRequestInterceptingJobFactory(
top_job_factory.Pass(), make_scoped_ptr(*it)));
interceptors->weak_clear();

View File

@@ -7,6 +7,8 @@
#include "brightray/browser/browser_context.h"
class BrowserProcess;
namespace atom {
class AtomURLRequestJobFactory;
@@ -25,9 +27,12 @@ class AtomBrowserContext : public brightray::BrowserContext {
// brightray::URLRequestContextGetter::Delegate:
virtual net::URLRequestJobFactory* CreateURLRequestJobFactory(
content::ProtocolHandlerMap* handlers,
content::ProtocolHandlerScopedVector* interceptors) OVERRIDE;
content::URLRequestInterceptorScopedVector* interceptors) OVERRIDE;
private:
// A fake BrowserProcess object that used to feed the source code from chrome.
scoped_ptr<BrowserProcess> fake_browser_process_;
AtomURLRequestJobFactory* job_factory_; // Weak reference.
DISALLOW_COPY_AND_ASSIGN(AtomBrowserContext);

View File

@@ -12,6 +12,7 @@
#include "atom/common/api/atom_bindings.h"
#include "atom/common/node_bindings.h"
#include "base/command_line.h"
#include "v8/include/v8-debug.h"
#if defined(USE_X11)
#include "chrome/browser/ui/libgtk2ui/gtk2_util.h"
@@ -55,11 +56,15 @@ void AtomBrowserMainParts::PostEarlyInitialization() {
node_bindings_->Initialize();
// Support the "--debug" switch.
node_debugger_.reset(new NodeDebugger);
node_debugger_.reset(new NodeDebugger(js_env_->isolate()));
// Create the global environment.
global_env = node_bindings_->CreateEnvironment(js_env_->context());
// Make sure node can get correct environment when debugging.
if (node_debugger_->IsRunning())
global_env->AssignToContext(v8::Debug::GetDebugContext());
// Add atom-shell extended APIs.
atom_bindings_->BindTo(js_env_->isolate(), global_env->process_object());
}

View File

@@ -34,6 +34,13 @@ app.on('ready', function() {
{
type: 'separator'
},
{
label: 'Services',
submenu: []
},
{
type: 'separator'
},
{
label: 'Hide Atom Shell',
accelerator: 'Command+H',

View File

@@ -2,7 +2,6 @@ var app = require('app');
var dialog = require('dialog');
var fs = require('fs');
var path = require('path');
var optimist = require('optimist');
// Quit when all windows are closed and no other one is listening to this.
app.on('window-all-closed', function() {
@@ -10,14 +9,27 @@ app.on('window-all-closed', function() {
app.quit();
});
var argv = optimist(process.argv.slice(1)).boolean('ci').argv;
// Parse command line options.
var argv = process.argv.slice(1);
var option = { file: null, version: null };
for (var i in argv) {
if (argv[i] == '--version' || argv[i] == '-v') {
option.version = true;
break;
} else if (argv[i][0] == '-') {
continue;
} else {
option.file = argv[i];
break;
}
}
// Start the specified app if there is one specified in command line, otherwise
// start the default app.
if (argv._.length > 0) {
if (option.file) {
try {
// Override app name and version.
var packagePath = path.resolve(argv._[0]);
var packagePath = path.resolve(option.file);
var packageJsonPath = path.join(packagePath, 'package.json');
if (fs.existsSync(packageJsonPath)) {
var packageJson = JSON.parse(fs.readFileSync(packageJsonPath));
@@ -48,7 +60,7 @@ if (argv._.length > 0) {
throw e;
}
}
} else if (argv.version) {
} else if (option.version) {
console.log('v' + process.versions['atom-shell']);
process.exit(0);
} else {

View File

@@ -2,8 +2,5 @@
"name": "atom-shell-default-app",
"productName": "Atom Shell Default App",
"version": "0.1.0",
"main": "main.js",
"dependencies": {
"optimist": "*"
}
"main": "main.js"
}

View File

@@ -7,7 +7,9 @@
namespace atom {
JavascriptEnvironment::JavascriptEnvironment()
: isolate_(v8::Isolate::GetCurrent()),
: isolate_holder_(gin::IsolateHolder::kNonStrictMode),
isolate_(isolate_holder_.isolate()),
isolate_scope_(isolate_),
locker_(isolate_),
handle_scope_(isolate_),
context_(isolate_, v8::Context::New(isolate_)),

View File

@@ -6,7 +6,7 @@
#define ATOM_BROWSER_JAVASCRIPT_ENVIRONMENT_H_
#include "base/basictypes.h"
#include "v8/include/v8.h"
#include "gin/public/isolate_holder.h"
namespace atom {
@@ -20,7 +20,9 @@ class JavascriptEnvironment {
}
private:
gin::IsolateHolder isolate_holder_;
v8::Isolate* isolate_;
v8::Isolate::Scope isolate_scope_;
v8::Locker locker_;
v8::HandleScope handle_scope_;
v8::UniquePersistent<v8::Context> context_;

View File

@@ -0,0 +1,88 @@
app = require 'app'
fs = require 'fs'
path = require 'path'
url = require 'url'
# Mapping between hostname and file path.
hostPathMap = {}
hostPathMapNextKey = 0
getHostForPath = (path) ->
key = "extension-#{++hostPathMapNextKey}"
hostPathMap[key] = path
key
getPathForHost = (host) ->
hostPathMap[host]
# Cache extensionInfo.
extensionInfoMap = {}
getExtensionInfoFromPath = (srcDirectory) ->
manifest = JSON.parse fs.readFileSync(path.join(srcDirectory, 'manifest.json'))
unless extensionInfoMap[manifest.name]?
# We can not use 'file://' directly because all resources in the extension
# will be treated as relative to the root in Chrome.
page = url.format
protocol: 'chrome-extension'
slashes: true
hostname: getHostForPath srcDirectory
pathname: manifest.devtools_page
extensionInfoMap[manifest.name] =
startPage: page
name: manifest.name
srcDirectory: srcDirectory
extensionInfoMap[manifest.name]
# Load persistented extensions.
loadedExtensionsPath = path.join app.getDataPath(), 'DevTools Extensions'
try
loadedExtensions = JSON.parse fs.readFileSync(loadedExtensionsPath)
loadedExtensions = [] unless Array.isArray loadedExtensions
# Preheat the extensionInfo cache.
getExtensionInfoFromPath srcDirectory for srcDirectory in loadedExtensions
catch e
# Persistent loaded extensions.
app.on 'will-quit', ->
try
loadedExtensions = Object.keys(extensionInfoMap).map (key) -> extensionInfoMap[key].srcDirectory
try
fs.mkdirSync path.dirname(loadedExtensionsPath)
catch e
fs.writeFileSync loadedExtensionsPath, JSON.stringify(loadedExtensions)
catch e
# We can not use protocol or BrowserWindow until app is ready.
app.once 'ready', ->
protocol = require 'protocol'
BrowserWindow = require 'browser-window'
# The chrome-extension: can map a extension URL request to real file path.
protocol.registerProtocol 'chrome-extension', (request) ->
parsed = url.parse request.url
return unless parsed.hostname and parsed.path?
return unless /extension-\d+/.test parsed.hostname
directory = getPathForHost parsed.hostname
return unless directory?
return new protocol.RequestFileJob(path.join(directory, parsed.path))
BrowserWindow::_loadDevToolsExtensions = (extensionInfoArray) ->
@devToolsWebContents?.executeJavaScript "WebInspector.addExtensions(#{JSON.stringify(extensionInfoArray)});"
BrowserWindow.addDevToolsExtension = (srcDirectory) ->
extensionInfo = getExtensionInfoFromPath srcDirectory
window._loadDevToolsExtensions [extensionInfo] for window in BrowserWindow.getAllWindows()
extensionInfo.name
BrowserWindow.removeDevToolsExtension = (name) ->
delete extensionInfoMap[name]
# Load persistented extensions when devtools is opened.
init = BrowserWindow::_init
BrowserWindow::_init = ->
init.call this
@on 'devtools-opened', ->
@_loadDevToolsExtensions Object.keys(extensionInfoMap).map (key) -> extensionInfoMap[key]

View File

@@ -47,7 +47,7 @@ setImmediate ->
message = error.stack ? "#{error.name}: #{error.message}"
require('dialog').showMessageBox
type: 'warning'
title: 'An javascript error occured in the browser'
title: 'A javascript error occured in the browser'
message: 'uncaughtException'
detail: message
buttons: ['OK']
@@ -77,5 +77,8 @@ setImmediate ->
else if packageJson.name?
app.setName packageJson.name
# Load the chrome extension support.
require './chrome-extension.js'
# Finally load app's main.js and transfer control to C++.
module._load path.join(packagePath, packageJson.main), module, true

View File

@@ -29,6 +29,7 @@
#include "base/strings/utf_string_conversions.h"
#include "brightray/browser/inspectable_web_contents.h"
#include "brightray/browser/inspectable_web_contents_view.h"
#include "chrome/browser/printing/print_view_manager_basic.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/invalidate_type.h"
#include "content/public/browser/navigation_entry.h"
@@ -66,6 +67,8 @@ NativeWindow::NativeWindow(content::WebContents* web_contents,
weak_factory_(this),
inspectable_web_contents_(
brightray::InspectableWebContents::Create(web_contents)) {
printing::PrintViewManagerBasic::CreateForWebContents(web_contents);
options.Get(switches::kFrame, &has_frame_);
options.Get(switches::kEnableLargerThanScreen, &enable_larger_than_screen_);
@@ -142,7 +145,7 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) {
Center();
}
int min_height = 0, min_width = 0;
if (options.Get(switches::kMinHeight, &min_height) ||
if (options.Get(switches::kMinHeight, &min_height) |
options.Get(switches::kMinWidth, &min_width)) {
SetMinimumSize(gfx::Size(min_width, min_height));
}
@@ -192,11 +195,16 @@ std::string NativeWindow::GetRepresentedFilename() {
void NativeWindow::SetDocumentEdited(bool edited) {
}
bool NativeWindow::IsDocumentEdited() {
return false;
}
void NativeWindow::SetMenu(ui::MenuModel* menu) {
}
bool NativeWindow::IsDocumentEdited() {
return false;
void NativeWindow::Print(bool silent, bool print_background) {
printing::PrintViewManagerBasic::FromWebContents(GetWebContents())->
PrintNow(silent, print_background);
}
bool NativeWindow::HasModalDialog() {
@@ -249,18 +257,10 @@ void NativeWindow::CapturePage(const gfx::Rect& rect,
return;
}
gfx::Rect flipped_y_rect = rect;
flipped_y_rect.set_y(-rect.y());
gfx::Size size;
if (flipped_y_rect.IsEmpty())
size = render_widget_host_view->GetViewBounds().size();
else
size = flipped_y_rect.size();
GetWebContents()->GetRenderViewHost()->CopyFromBackingStore(
flipped_y_rect,
size,
rect,
rect.IsEmpty() ? render_widget_host_view->GetViewBounds().size() :
rect.size(),
base::Bind(&NativeWindow::OnCapturePageDone,
weak_factory_.GetWeakPtr(),
callback),

View File

@@ -136,8 +136,8 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
virtual void SetRepresentedFilename(const std::string& filename);
virtual std::string GetRepresentedFilename();
virtual void SetDocumentEdited(bool edited);
virtual void SetMenu(ui::MenuModel* menu);
virtual bool IsDocumentEdited();
virtual void SetMenu(ui::MenuModel* menu);
virtual bool HasModalDialog();
virtual gfx::NativeWindow GetNativeWindow() = 0;
@@ -156,6 +156,9 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
virtual void CapturePage(const gfx::Rect& rect,
const CapturePageCallback& callback);
// Print current page.
virtual void Print(bool silent, bool print_background);
// The same with closing a tab in a real browser.
//
// Should be called by platform code when user want to close the window.

View File

@@ -8,12 +8,6 @@
#include <shobjidl.h>
#endif
#if defined(USE_X11)
#include <X11/extensions/XInput2.h>
#include <X11/extensions/Xrandr.h>
#include <X11/Xlib.h>
#endif
#include <string>
#include <vector>
@@ -35,11 +29,15 @@
#include "ui/views/widget/widget.h"
#if defined(USE_X11)
#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/x/x_window_utils.h"
#include "base/environment.h"
#include "base/nix/xdg_util.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/ui/libgtk2ui/unity_service.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)
@@ -60,6 +58,10 @@ const int kMenuBarHeight = 25;
#endif
#if defined(USE_X11)
// Counts how many window has already been created, it will be used to set the
// window role for X11.
int kWindowsCreated = 0;
bool ShouldUseGlobalMenuBar() {
// Some DE would pretend to be Unity but don't have global application menu,
// so we can not trust unity::IsRunning().
@@ -115,10 +117,15 @@ NativeWindowViews::NativeWindowViews(content::WebContents* web_contents,
keyboard_event_handler_(new views::UnhandledKeyboardEventHandler),
use_content_size_(false),
resizable_(true) {
options.Get(switches::kResizable, &resizable_);
options.Get(switches::kTitle, &title_);
options.Get(switches::kAutoHideMenuBar, &menu_bar_autohide_);
#if defined(OS_WIN)
// On Windows we rely on the CanResize() to indicate whether window can be
// resized, and it should be set before window is created.
options.Get(switches::kResizable, &resizable_);
#endif
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.
@@ -138,18 +145,44 @@ NativeWindowViews::NativeWindowViews(content::WebContents* web_contents,
params.bounds = bounds;
params.delegate = this;
params.type = views::Widget::InitParams::TYPE_WINDOW;
params.top_level = true;
params.remove_standard_frame = !has_frame_;
#if defined(USE_X11)
// FIXME Find out how to do this dynamically on Linux.
bool skip_taskbar = false;
if (options.Get(switches::kSkipTaskbar, &skip_taskbar) && skip_taskbar)
params.type = views::Widget::InitParams::TYPE_BUBBLE;
// Set WM_WINDOW_ROLE.
params.wm_role_name = base::StringPrintf(
"%s/%s/%d", "Atom Shell", Browser::Get()->GetName().c_str(),
++kWindowsCreated);
// Set WM_CLASS.
params.wm_class_name = "atom-shell";
params.wm_class_class = "Atom Shell";
#endif
window_->Init(params);
#if defined(USE_X11)
// Set _GTK_THEME_VARIANT to dark if we have "dark-theme" option set.
bool use_dark_theme = false;
if (options.Get(switches::kDarkTheme, &use_dark_theme) && use_dark_theme) {
XDisplay* xdisplay = gfx::GetXDisplay();
XChangeProperty(xdisplay, GetAcceleratedWidget(),
XInternAtom(xdisplay, "_GTK_THEME_VARIANT", False),
XInternAtom(xdisplay, "UTF8_STRING", False),
8, PropModeReplace,
reinterpret_cast<const unsigned char*>("dark"),
4);
}
// Before the window is mapped the SetWMSpecState can not work, so we have
// to manually set the _NET_WM_STATE.
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);
}
#endif
// Add web view.
SetLayoutManager(new MenuLayout(kMenuBarHeight));
set_background(views::Background::CreateStandardPanelBackground());
@@ -237,6 +270,15 @@ bool NativeWindowViews::IsFullscreen() {
}
void NativeWindowViews::SetSize(const gfx::Size& size) {
#if defined(USE_X11)
// On Linux the minimum and maximum size should be updated with window size
// when window is not resizable.
if (!resizable_) {
SetMaximumSize(size);
SetMinimumSize(size);
}
#endif
window_->SetSize(size);
}
@@ -256,8 +298,7 @@ void NativeWindowViews::SetContentSize(const gfx::Size& size) {
}
gfx::Rect bounds = window_->GetWindowBoundsInScreen();
bounds.set_size(size);
window_->SetBounds(ContentBoundsToWindowBounds(bounds));
SetSize(ContentBoundsToWindowBounds(gfx::Rect(bounds.origin(), size)).size());
}
gfx::Size NativeWindowViews::GetContentSize() {
@@ -304,8 +345,6 @@ gfx::Size NativeWindowViews::GetMaximumSize() {
}
void NativeWindowViews::SetResizable(bool resizable) {
resizable_ = resizable;
#if defined(OS_WIN)
if (has_frame_) {
// WS_MAXIMIZEBOX => Maximize button
@@ -318,9 +357,21 @@ void NativeWindowViews::SetResizable(bool resizable) {
style = (style & ~(WS_MAXIMIZEBOX | WS_THICKFRAME)) | WS_MINIMIZEBOX;
::SetWindowLong(GetAcceleratedWidget(), GWL_STYLE, style);
}
#elif defined(USE_X11)
if (resizable != resizable_) {
// On Linux there is no "resizable" property of a window, we have to set
// both the minimum and maximum size to the window size to achieve it.
if (resizable) {
SetMaximumSize(gfx::Size());
SetMinimumSize(gfx::Size());
} else {
SetMaximumSize(GetSize());
SetMinimumSize(GetSize());
}
}
#endif
// FIXME Implement me for X11.
resizable_ = resizable;
}
bool NativeWindowViews::IsResizable() {
@@ -376,6 +427,9 @@ void NativeWindowViews::SetSkipTaskbar(bool skip) {
taskbar->DeleteTab(GetAcceleratedWidget());
else
taskbar->AddTab(GetAcceleratedWidget());
#elif defined(USE_X11)
SetWMSpecState(GetAcceleratedWidget(), skip,
GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
#endif
}

View File

@@ -6,25 +6,33 @@
#include <string>
#include "atom/common/atom_version.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/strings/string_number_conversions.h"
#include "v8/include/v8.h"
#include "v8/include/v8-debug.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/browser_thread.h"
#include "net/socket/tcp_listen_socket.h"
#include "atom/common/node_includes.h"
namespace atom {
// static
uv_async_t NodeDebugger::dispatch_debug_messages_async_;
namespace {
NodeDebugger::NodeDebugger() {
uv_async_init(uv_default_loop(),
&dispatch_debug_messages_async_,
DispatchDebugMessagesInMainThread);
uv_unref(reinterpret_cast<uv_handle_t*>(&dispatch_debug_messages_async_));
// NodeDebugger is stored in Isolate's data, slots 0, 1, 3 have already been
// taken by gin, blink and node, using 2 is a safe option for now.
const int kIsolateSlot = 2;
const char* kContentLength = "Content-Length";
} // namespace
NodeDebugger::NodeDebugger(v8::Isolate* isolate)
: isolate_(isolate),
thread_("NodeDebugger"),
content_length_(-1),
weak_factory_(this) {
bool use_debug_agent = false;
int port = 5858;
bool wait_for_connection = false;
@@ -44,24 +52,151 @@ NodeDebugger::NodeDebugger() {
if (use_debug_agent) {
if (!port_str.empty())
base::StringToInt(port_str, &port);
v8::Debug::EnableAgent("atom-shell " ATOM_VERSION, port,
wait_for_connection);
v8::Debug::SetDebugMessageDispatchHandler(DispatchDebugMessagesInMsgThread,
false);
isolate_->SetData(kIsolateSlot, this);
v8::Debug::SetMessageHandler(DebugMessageHandler);
if (wait_for_connection)
v8::Debug::DebugBreak(isolate_);
// Start a new IO thread.
base::Thread::Options options;
options.message_loop_type = base::MessageLoop::TYPE_IO;
if (!thread_.StartWithOptions(options)) {
LOG(ERROR) << "Unable to start debugger thread";
return;
}
// Start the server in new IO thread.
thread_.message_loop()->PostTask(
FROM_HERE,
base::Bind(&NodeDebugger::StartServer, weak_factory_.GetWeakPtr(),
port));
}
}
NodeDebugger::~NodeDebugger() {
thread_.Stop();
}
bool NodeDebugger::IsRunning() const {
return thread_.IsRunning();
}
void NodeDebugger::StartServer(int port) {
server_ = net::TCPListenSocket::CreateAndListen("127.0.0.1", port, this);
if (!server_) {
LOG(ERROR) << "Cannot start debugger server";
return;
}
}
void NodeDebugger::CloseSession() {
accepted_socket_.reset();
}
void NodeDebugger::OnMessage(const std::string& message) {
if (message.find("\"type\":\"request\",\"command\":\"disconnect\"}") !=
std::string::npos)
CloseSession();
base::string16 message16 = base::UTF8ToUTF16(message);
v8::Debug::SendCommand(
isolate_,
reinterpret_cast<const uint16_t*>(message16.data()), message16.size());
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
base::Bind(&v8::Debug::ProcessDebugMessages));
}
void NodeDebugger::SendMessage(const std::string& message) {
if (accepted_socket_) {
std::string header = base::StringPrintf(
"%s: %d\r\n\r\n", kContentLength, static_cast<int>(message.size()));
accepted_socket_->Send(header);
accepted_socket_->Send(message);
}
}
void NodeDebugger::SendConnectMessage() {
accepted_socket_->Send(base::StringPrintf(
"Type: connect\r\n"
"V8-Version: %s\r\n"
"Protocol-Version: 1\r\n"
"Embedding-Host: %s\r\n"
"%s: 0\r\n",
v8::V8::GetVersion(), "Atom-Shell", kContentLength), true);
}
// static
void NodeDebugger::DispatchDebugMessagesInMainThread(uv_async_t* handle) {
v8::Debug::ProcessDebugMessages();
void NodeDebugger::DebugMessageHandler(const v8::Debug::Message& message) {
NodeDebugger* self = static_cast<NodeDebugger*>(
message.GetIsolate()->GetData(kIsolateSlot));
if (self) {
std::string message8(*v8::String::Utf8Value(message.GetJSON()));
self->thread_.message_loop()->PostTask(
FROM_HERE,
base::Bind(&NodeDebugger::SendMessage, self->weak_factory_.GetWeakPtr(),
message8));
}
}
// static
void NodeDebugger::DispatchDebugMessagesInMsgThread() {
uv_async_send(&dispatch_debug_messages_async_);
void NodeDebugger::DidAccept(net::StreamListenSocket* server,
scoped_ptr<net::StreamListenSocket> socket) {
// Only accept one session.
if (accepted_socket_) {
socket->Send(std::string("Remote debugging session already active"), true);
return;
}
accepted_socket_ = socket.Pass();
SendConnectMessage();
}
void NodeDebugger::DidRead(net::StreamListenSocket* socket,
const char* data,
int len) {
buffer_.append(data, len);
do {
if (buffer_.size() == 0)
return;
// Read the "Content-Length" header.
if (content_length_ < 0) {
size_t pos = buffer_.find("\r\n\r\n");
if (pos == std::string::npos)
return;
// We can be sure that the header is "Content-Length: xxx\r\n".
std::string content_length = buffer_.substr(16, pos - 16);
if (!base::StringToInt(content_length, &content_length_)) {
DidClose(accepted_socket_.get());
return;
}
// Strip header from buffer.
buffer_ = buffer_.substr(pos + 4);
}
// Read the message.
if (buffer_.size() >= static_cast<size_t>(content_length_)) {
std::string message = buffer_.substr(0, content_length_);
buffer_ = buffer_.substr(content_length_);
OnMessage(message);
// Get ready for next message.
content_length_ = -1;
}
} while (true);
}
void NodeDebugger::DidClose(net::StreamListenSocket* socket) {
// If we lost the connection, then simulate a disconnect msg:
OnMessage("{\"seq\":1,\"type\":\"request\",\"command\":\"disconnect\"}");
}
} // namespace atom

View File

@@ -5,22 +5,51 @@
#ifndef ATOM_BROWSER_NODE_DEBUGGER_H_
#define ATOM_BROWSER_NODE_DEBUGGER_H_
#include "base/basictypes.h"
#include "vendor/node/deps/uv/include/uv.h"
#include <string>
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread.h"
#include "net/socket/stream_listen_socket.h"
#include "v8/include/v8-debug.h"
namespace atom {
// Add support for node's "--debug" switch.
class NodeDebugger {
class NodeDebugger : public net::StreamListenSocket::Delegate {
public:
NodeDebugger();
explicit NodeDebugger(v8::Isolate* isolate);
virtual ~NodeDebugger();
private:
static void DispatchDebugMessagesInMainThread(uv_async_t* handle);
static void DispatchDebugMessagesInMsgThread();
bool IsRunning() const;
static uv_async_t dispatch_debug_messages_async_;
private:
void StartServer(int port);
void CloseSession();
void OnMessage(const std::string& message);
void SendMessage(const std::string& message);
void SendConnectMessage();
static void DebugMessageHandler(const v8::Debug::Message& message);
// net::StreamListenSocket::Delegate:
virtual void DidAccept(net::StreamListenSocket* server,
scoped_ptr<net::StreamListenSocket> socket) OVERRIDE;
virtual void DidRead(net::StreamListenSocket* socket,
const char* data,
int len) OVERRIDE;
virtual void DidClose(net::StreamListenSocket* socket) OVERRIDE;
v8::Isolate* isolate_;
base::Thread thread_;
scoped_ptr<net::StreamListenSocket> server_;
scoped_ptr<net::StreamListenSocket> accepted_socket_;
std::string buffer_;
int content_length_;
base::WeakPtrFactory<NodeDebugger> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(NodeDebugger);
};

View File

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

View File

@@ -50,8 +50,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,15,9,0
PRODUCTVERSION 0,15,9,0
FILEVERSION 0,16,0,0
PRODUCTVERSION 0,16,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -68,12 +68,13 @@ BEGIN
BEGIN
VALUE "CompanyName", "GitHub, Inc."
VALUE "FileDescription", "Atom-Shell"
VALUE "FileVersion", "0.15.9"
VALUE "FileVersion", "0.16.0"
VALUE "InternalName", "atom.exe"
VALUE "LegalCopyright", "Copyright (C) 2013 GitHub, Inc. All rights reserved."
VALUE "OriginalFilename", "atom.exe"
VALUE "ProductName", "Atom-Shell"
VALUE "ProductVersion", "0.15.9"
VALUE "ProductVersion", "0.16.0"
VALUE "SquirrelAwareVersion", "1"
END
END
BLOCK "VarFileInfo"

View File

@@ -159,6 +159,9 @@ int EventFlagsFromNSEvent(NSEvent* event) {
[NSApp setWindowsMenu:submenu];
else if ([[item title] isEqualToString:@"Help"])
[NSApp setHelpMenu:submenu];
if ([[item title] isEqualToString:@"Services"] &&
[submenu numberOfItems] == 0)
[NSApp setServicesMenu:submenu];
} else {
// The MenuModel works on indexes so we can't just set the command id as the
// tag like we do in other menus. Also set the represented object to be

View File

@@ -71,7 +71,7 @@ class MessageDialog : public views::WidgetDelegate,
virtual views::ClientView* CreateClientView(views::Widget* widget) OVERRIDE;
// Overridden from views::View:
virtual gfx::Size GetPreferredSize() OVERRIDE;
virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual void Layout() OVERRIDE;
virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
@@ -160,7 +160,6 @@ MessageDialog::MessageDialog(NativeWindow* parent_window,
views::Widget::InitParams params;
params.delegate = this;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.top_level = true;
if (parent_) {
params.parent = parent_->GetNativeWindow();
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
@@ -264,7 +263,7 @@ views::ClientView* MessageDialog::CreateClientView(views::Widget* widget) {
return new MessageDialogClientView(this, widget);
}
gfx::Size MessageDialog::GetPreferredSize() {
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);

View File

@@ -95,16 +95,16 @@ void FramelessView::UpdateWindowIcon() {
void FramelessView::UpdateWindowTitle() {
}
gfx::Size FramelessView::GetPreferredSize() {
gfx::Size FramelessView::GetPreferredSize() const {
return frame_->non_client_view()->GetWindowBoundsForClientBounds(
gfx::Rect(frame_->client_view()->GetPreferredSize())).size();
}
gfx::Size FramelessView::GetMinimumSize() {
gfx::Size FramelessView::GetMinimumSize() const {
return window_->GetMinimumSize();
}
gfx::Size FramelessView::GetMaximumSize() {
gfx::Size FramelessView::GetMaximumSize() const {
return window_->GetMaximumSize();
}

View File

@@ -38,9 +38,9 @@ class FramelessView : public views::NonClientFrameView {
virtual void UpdateWindowTitle() OVERRIDE;
// Overridden from View:
virtual gfx::Size GetPreferredSize() OVERRIDE;
virtual gfx::Size GetMinimumSize() OVERRIDE;
virtual gfx::Size GetMaximumSize() OVERRIDE;
virtual gfx::Size GetPreferredSize() const OVERRIDE;
virtual gfx::Size GetMinimumSize() const OVERRIDE;
virtual gfx::Size GetMaximumSize() const OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
// Not owned.

View File

@@ -74,10 +74,10 @@ void MenuBar::SetMenu(ui::MenuModel* model) {
button->set_tag(i);
#if defined(USE_X11)
button->SetEnabledColor(enabled_color_);
button->SetDisabledColor(disabled_color_);
button->SetHighlightColor(highlight_color_);
button->SetHoverColor(hover_color_);
button->SetTextColor(views::Button::STATE_NORMAL, enabled_color_);
button->SetTextColor(views::Button::STATE_DISABLED, disabled_color_);
button->SetTextColor(views::Button::STATE_PRESSED, highlight_color_);
button->SetTextColor(views::Button::STATE_HOVERED, hover_color_);
button->SetUnderlineColor(enabled_color_);
#elif defined(OS_WIN)
button->SetUnderlineColor(color_utils::GetSysSkColor(COLOR_GRAYTEXT));

View File

@@ -73,7 +73,7 @@ bool MenuDelegate::IsTriggerableEvent(views::MenuItemView* source,
return delegate()->IsTriggerableEvent(source, e);
}
bool MenuDelegate::GetAccelerator(int id, ui::Accelerator* accelerator) {
bool MenuDelegate::GetAccelerator(int id, ui::Accelerator* accelerator) const {
return delegate()->GetAccelerator(id, accelerator);
}

View File

@@ -35,7 +35,7 @@ class MenuDelegate : public views::MenuDelegate {
virtual bool IsTriggerableEvent(views::MenuItemView* source,
const ui::Event& e) OVERRIDE;
virtual bool GetAccelerator(int id,
ui::Accelerator* accelerator) OVERRIDE;
ui::Accelerator* accelerator) const OVERRIDE;
virtual base::string16 GetLabel(int id) const OVERRIDE;
virtual const gfx::FontList* GetLabelFontList(int id) const OVERRIDE;
virtual bool IsCommandEnabled(int id) const OVERRIDE;

View File

@@ -30,7 +30,7 @@ void MenuLayout::Layout(views::View* host) {
menu_bar->SetBoundsRect(menu_Bar_bounds);
}
gfx::Size MenuLayout::GetPreferredSize(views::View* host) {
gfx::Size MenuLayout::GetPreferredSize(const views::View* host) const {
gfx::Size size = views::FillLayout::GetPreferredSize(host);
if (!HasMenu(host))
return size;
@@ -39,7 +39,8 @@ gfx::Size MenuLayout::GetPreferredSize(views::View* host) {
return size;
}
int MenuLayout::GetPreferredHeightForWidth(views::View* host, int width) {
int MenuLayout::GetPreferredHeightForWidth(
const views::View* host, int width) const {
int height = views::FillLayout::GetPreferredHeightForWidth(host, width);
if (!HasMenu(host))
return height;

View File

@@ -16,8 +16,9 @@ class MenuLayout : public views::FillLayout {
// views::LayoutManager:
virtual void Layout(views::View* host) OVERRIDE;
virtual gfx::Size GetPreferredSize(views::View* host) OVERRIDE;
virtual int GetPreferredHeightForWidth(views::View* host, int width) OVERRIDE;
virtual gfx::Size GetPreferredSize(const views::View* host) const OVERRIDE;
virtual int GetPreferredHeightForWidth(
const views::View* host, int width) const OVERRIDE;
private:
bool HasMenu(const views::View* host) const;

View File

@@ -8,6 +8,7 @@
#include "base/strings/utf_string_conversions.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/text_utils.h"
#include "ui/views/controls/button/label_button_border.h"
namespace atom {
@@ -34,9 +35,14 @@ SubmenuButton::SubmenuButton(views::ButtonListener* listener,
text_width_(0),
text_height_(0),
underline_color_(SK_ColorBLACK) {
#if defined(OS_LINUX)
// Dont' use native style border.
SetBorder(CreateDefaultBorder().PassAs<views::Border>());
#endif
if (GetUnderlinePosition(title, &accelerator_, &underline_start_,
&underline_end_))
gfx::Canvas::SizeStringInt(text(), font_list(), &text_width_,
gfx::Canvas::SizeStringInt(GetText(), GetFontList(), &text_width_,
&text_height_, 0, 0);
}
@@ -85,7 +91,7 @@ bool SubmenuButton::GetUnderlinePosition(const base::string16& text,
void SubmenuButton::GetCharacterPosition(
const base::string16& text, int index, int* pos) {
int height;
gfx::Canvas::SizeStringInt(text.substr(0, index), font_list(), pos, &height,
gfx::Canvas::SizeStringInt(text.substr(0, index), GetFontList(), pos, &height,
0, 0);
}

View File

@@ -20,6 +20,9 @@ class SubmenuButton : public views::MenuButton {
void SetAcceleratorVisibility(bool visible);
void SetUnderlineColor(SkColor color);
void SetEnabledColor(SkColor color);
void SetBackgroundColor(SkColor color);
base::char16 accelerator() const { return accelerator_; }
// views::MenuButton:

View File

@@ -39,12 +39,12 @@ int WinFrameView::NonClientHitTest(const gfx::Point& point) {
return FramelessView::NonClientHitTest(point);
}
gfx::Size WinFrameView::GetMinimumSize() {
gfx::Size WinFrameView::GetMinimumSize() const {
gfx::Size size = FramelessView::GetMinimumSize();
return gfx::win::DIPToScreenSize(size);
}
gfx::Size WinFrameView::GetMaximumSize() {
gfx::Size WinFrameView::GetMaximumSize() const {
gfx::Size size = FramelessView::GetMaximumSize();
return gfx::win::DIPToScreenSize(size);
}

View File

@@ -20,8 +20,8 @@ class WinFrameView : public FramelessView {
virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE;
// views::View:
virtual gfx::Size GetMinimumSize() OVERRIDE;
virtual gfx::Size GetMaximumSize() OVERRIDE;
virtual gfx::Size GetMinimumSize() const OVERRIDE;
virtual gfx::Size GetMaximumSize() const OVERRIDE;
virtual const char* GetClassName() const OVERRIDE;
private:

View File

@@ -0,0 +1,34 @@
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/ui/x/x_window_utils.h"
#include "ui/base/x/x11_util.h"
namespace atom {
::Atom GetAtom(const char* name) {
return XInternAtom(gfx::GetXDisplay(), name, false);
}
void SetWMSpecState(::Window xwindow, bool enabled, ::Atom state) {
XEvent xclient;
memset(&xclient, 0, sizeof(xclient));
xclient.type = ClientMessage;
xclient.xclient.window = xwindow;
xclient.xclient.message_type = GetAtom("_NET_WM_STATE");
xclient.xclient.format = 32;
xclient.xclient.data.l[0] = enabled ? 1 : 0;
xclient.xclient.data.l[1] = state;
xclient.xclient.data.l[2] = None;
xclient.xclient.data.l[3] = 1;
xclient.xclient.data.l[4] = 0;
XDisplay* xdisplay = gfx::GetXDisplay();
XSendEvent(xdisplay, DefaultRootWindow(xdisplay), False,
SubstructureRedirectMask | SubstructureNotifyMask,
&xclient);
}
} // namespace atom

View File

@@ -0,0 +1,22 @@
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_UI_X_X_WINDOW_UTILS_H_
#define ATOM_BROWSER_UI_X_X_WINDOW_UTILS_H_
#include <X11/extensions/XInput2.h>
#include <X11/extensions/Xrandr.h>
#include <X11/Xlib.h>
namespace atom {
::Atom GetAtom(const char* name);
// Sends a message to the x11 window manager, enabling or disabling the |state|
// for _NET_WM_STATE.
void SetWMSpecState(::Window xwindow, bool enabled, ::Atom state);
} // namespace atom
#endif // ATOM_BROWSER_UI_X_X_WINDOW_UTILS_H_

View File

@@ -61,7 +61,6 @@ AtomBindings::AtomBindings() {
call_next_tick_async_.data = this;
uv_async_init(uv_default_loop(), &g_callback_uv_handle, UvOnCallback);
v8::V8::SetFatalErrorHandler(FatalErrorCallback);
}
AtomBindings::~AtomBindings() {
@@ -69,6 +68,8 @@ AtomBindings::~AtomBindings() {
void AtomBindings::BindTo(v8::Isolate* isolate,
v8::Handle<v8::Object> process) {
v8::V8::SetFatalErrorHandler(FatalErrorCallback);
mate::Dictionary dict(isolate, process);
dict.SetMethod("crash", &Crash);
dict.SetMethod("log", &Log);

View File

@@ -6,8 +6,8 @@
#define ATOM_VERSION_H
#define ATOM_MAJOR_VERSION 0
#define ATOM_MINOR_VERSION 15
#define ATOM_PATCH_VERSION 9
#define ATOM_MINOR_VERSION 16
#define ATOM_PATCH_VERSION 0
#define ATOM_VERSION_IS_RELEASE 1

View File

@@ -8,7 +8,7 @@
#ifndef ATOM_COMMON_CHROME_VERSION_H_
#define ATOM_COMMON_CHROME_VERSION_H_
#define CHROME_VERSION_STRING "36.0.1985.125"
#define CHROME_VERSION_STRING "37.0.2062.102"
#define CHROME_VERSION "v" CHROME_VERSION_STRING
#endif // ATOM_COMMON_CHROME_VERSION_H_

View File

@@ -1,33 +1,34 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
// Get basic type definitions.
#define IPC_MESSAGE_IMPL
#include "atom/common/api/api_messages.h"
#include "atom/common/common_message_generator.h"
// Generate constructors.
#include "ipc/struct_constructor_macros.h"
#include "atom/common/api/api_messages.h"
#include "atom/common/common_message_generator.h"
// Generate destructors.
#include "ipc/struct_destructor_macros.h"
#include "atom/common/api/api_messages.h"
#include "atom/common/common_message_generator.h"
// Generate param traits write methods.
#include "ipc/param_traits_write_macros.h"
namespace IPC {
#include "atom/common/api/api_messages.h"
#include "atom/common/common_message_generator.h"
} // namespace IPC
// Generate param traits read methods.
#include "ipc/param_traits_read_macros.h"
namespace IPC {
#include "atom/common/api/api_messages.h"
#include "atom/common/common_message_generator.h"
} // namespace IPC
// Generate param traits log methods.
#include "ipc/param_traits_log_macros.h"
namespace IPC {
#include "atom/common/api/api_messages.h"
#include "atom/common/common_message_generator.h"
} // namespace IPC

View File

@@ -0,0 +1,8 @@
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
// Multiply-included file, no traditional include guard.
#include "atom/common/api/api_messages.h"
#include "chrome/common/print_messages.h"

View File

@@ -54,6 +54,9 @@ const char kAutoHideMenuBar[] = "auto-hide-menu-bar";
// Enable window to be resized larger than screen.
const char kEnableLargerThanScreen[] = "enable-larger-than-screen";
// Forces to use dark theme on Linux.
const char kDarkTheme[] = "dark-theme";
} // namespace switches
} // namespace atom

View File

@@ -34,6 +34,7 @@ extern const char kWebPreferences[];
extern const char kZoomFactor[];
extern const char kAutoHideMenuBar[];
extern const char kEnableLargerThanScreen[];
extern const char kDarkTheme[];
} // namespace switches

View File

@@ -19,6 +19,7 @@ void XDGUtil(const std::string& util, const std::string& arg) {
argv.push_back(arg);
base::LaunchOptions options;
options.allow_new_privs = true;
// xdg-open can fall back on mailcap which eventually might plumb through
// to a command that needs a terminal. Set the environment variable telling
// it that we definitely don't have a terminal available and that it should

View File

@@ -5,6 +5,7 @@
#ifndef ATOM_RENDERER_ATOM_RENDER_VIEW_OBSERVER_H_
#define ATOM_RENDERER_ATOM_RENDER_VIEW_OBSERVER_H_
#include "base/strings/string16.h"
#include "content/public/renderer/render_view_observer.h"
namespace base {

View File

@@ -11,12 +11,15 @@
#include "atom/common/options_switches.h"
#include "atom/renderer/api/atom_renderer_bindings.h"
#include "atom/renderer/atom_render_view_observer.h"
#include "chrome/renderer/printing/print_web_view_helper.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_frame_observer.h"
#include "content/public/renderer/render_thread.h"
#include "base/command_line.h"
#include "native_mate/converter.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebKit.h"
#include "atom/common/node_includes.h"
@@ -82,7 +85,7 @@ AtomRendererClient::AtomRendererClient()
AtomRendererClient::~AtomRendererClient() {
}
void AtomRendererClient::RenderThreadStarted() {
void AtomRendererClient::WebKitInitialized() {
if (!IsNodeBindingEnabled())
return;
@@ -93,18 +96,23 @@ void AtomRendererClient::RenderThreadStarted() {
// Create a default empty environment which would be used when we need to
// run V8 code out of a window context (like running a uv callback).
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Isolate* isolate = blink::mainThreadIsolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
global_env = node::Environment::New(context);
}
void AtomRendererClient::RenderThreadStarted() {
content::RenderThread::Get()->AddObserver(this);
}
void AtomRendererClient::RenderFrameCreated(
content::RenderFrame* render_frame) {
new AtomRenderFrameObserver(render_frame, this);
}
void AtomRendererClient::RenderViewCreated(content::RenderView* render_view) {
new printing::PrintWebViewHelper(render_view);
new AtomRenderViewObserver(render_view, this);
}
@@ -197,6 +205,10 @@ bool AtomRendererClient::IsNodeBindingEnabled(blink::WebFrame* frame) {
// Node integration is enabled in main frame unless explictly disabled.
else if (frame == main_frame_)
return true;
// Enable node integration in chrome extensions.
else if (frame != NULL &&
GURL(frame->document().url()).SchemeIs("chrome-extension"))
return true;
else if (node_integration_ == MANUAL_ENABLE_IFRAME &&
frame != NULL &&
frame->uniqueName().utf8().find(kSecurityEnableNodeIntegration)

View File

@@ -9,6 +9,7 @@
#include <vector>
#include "content/public/renderer/content_renderer_client.h"
#include "content/public/renderer/render_process_observer.h"
namespace node {
class Environment;
@@ -19,7 +20,8 @@ namespace atom {
class AtomRendererBindings;
class NodeBindings;
class AtomRendererClient : public content::ContentRendererClient {
class AtomRendererClient : public content::ContentRendererClient,
public content::RenderProcessObserver {
public:
AtomRendererClient();
virtual ~AtomRendererClient();
@@ -41,6 +43,9 @@ class AtomRendererClient : public content::ContentRendererClient {
DISABLE,
};
// content::RenderProcessObserver:
virtual void WebKitInitialized() OVERRIDE;
// content::ContentRendererClient:
virtual void RenderThreadStarted() OVERRIDE;
virtual void RenderFrameCreated(content::RenderFrame* render_frame) OVERRIDE;

View File

@@ -0,0 +1,10 @@
url = require 'url'
chrome = window.chrome = window.chrome || {}
chrome.extension =
getURL: (path) ->
url.format
protocol: location.protocol
slashes: true
hostname: location.hostname
pathname: path

View File

@@ -46,6 +46,9 @@ else
if location.protocol is 'chrome-devtools:'
# Override some inspector APIs.
require path.join(__dirname, 'inspector')
else if location.protocol is 'chrome-extension:'
# Add implementations of chrome API.
require path.join(__dirname, 'chrome-api')
else
# Override default web functions.
require path.join(__dirname, 'override')

View File

@@ -0,0 +1,28 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/browser_process.h"
#include "chrome/browser/printing/print_job_manager.h"
#include "ui/base/l10n/l10n_util.h"
BrowserProcess* g_browser_process = NULL;
BrowserProcess::BrowserProcess() {
g_browser_process = this;
print_job_manager_.reset(new printing::PrintJobManager);
}
BrowserProcess::~BrowserProcess() {
g_browser_process = NULL;
}
std::string BrowserProcess::GetApplicationLocale() {
return l10n_util::GetApplicationLocale("");
}
printing::PrintJobManager* BrowserProcess::print_job_manager() {
return print_job_manager_.get();
}

View File

@@ -0,0 +1,41 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This interface is for managing the global services of the application. Each
// service is lazily created when requested the first time. The service getters
// will return NULL if the service is not available, so callers must check for
// this condition.
#ifndef CHROME_BROWSER_BROWSER_PROCESS_H_
#define CHROME_BROWSER_BROWSER_PROCESS_H_
#include <string>
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
namespace printing {
class PrintJobManager;
}
// NOT THREAD SAFE, call only from the main thread.
// These functions shouldn't return NULL unless otherwise noted.
class BrowserProcess {
public:
BrowserProcess();
~BrowserProcess();
std::string GetApplicationLocale();
printing::PrintJobManager* print_job_manager();
private:
scoped_ptr<printing::PrintJobManager> print_job_manager_;
DISALLOW_COPY_AND_ASSIGN(BrowserProcess);
};
extern BrowserProcess* g_browser_process;
#endif // CHROME_BROWSER_BROWSER_PROCESS_H_

View File

@@ -0,0 +1,949 @@
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_CHROME_NOTIFICATION_TYPES_H_
#define CHROME_BROWSER_CHROME_NOTIFICATION_TYPES_H_
#include "build/build_config.h"
#include "content/public/browser/notification_types.h"
namespace chrome {
enum NotificationType {
NOTIFICATION_CHROME_START = content::NOTIFICATION_CONTENT_END,
// Browser-window ----------------------------------------------------------
// This message is sent after a window has been opened. The source is a
// Source<Browser> containing the affected Browser. No details are
// expected.
NOTIFICATION_BROWSER_OPENED = NOTIFICATION_CHROME_START,
// This message is sent soon after BROWSER_OPENED, and indicates that
// the Browser's |window_| is now non-NULL. The source is a Source<Browser>
// containing the affected Browser. No details are expected.
NOTIFICATION_BROWSER_WINDOW_READY,
// This message is sent when a browser is closing. The source is a
// Source<Browser> containing the affected Browser. No details are expected.
// This is sent prior to BROWSER_CLOSED, and may be sent more than once for a
// particular browser.
NOTIFICATION_BROWSER_CLOSING,
// This message is sent after a window has been closed. The source is a
// Source<Browser> containing the affected Browser. No details are exptected.
NOTIFICATION_BROWSER_CLOSED,
// This message is sent when closing a browser has been cancelled, either by
// the user cancelling a beforeunload dialog, or IsClosingPermitted()
// disallowing closing. This notification implies that no BROWSER_CLOSING or
// BROWSER_CLOSED notification will be sent.
// The source is a Source<Browser> containing the affected browser. No details
// are expected.
NOTIFICATION_BROWSER_CLOSE_CANCELLED,
// Indicates that a top window has been closed. The source is the HWND
// that was closed, no details are expected.
NOTIFICATION_WINDOW_CLOSED,
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
// On Linux maximize can be an asynchronous operation. This notification
// indicates that the window has been maximized. The source is
// a Source<BrowserWindow> containing the BrowserWindow that was maximized.
// No details are expected.
NOTIFICATION_BROWSER_WINDOW_MAXIMIZED,
#endif
// Sent when the language (English, French...) for a page has been detected.
// The details Details<std::string> contain the ISO 639-1 language code and
// the source is Source<WebContents>.
NOTIFICATION_TAB_LANGUAGE_DETERMINED,
// Sent when a page has been translated. The source is the tab for that page
// (Source<WebContents>) and the details are the language the page was
// originally in and the language it was translated to
// (std::pair<std::string, std::string>).
NOTIFICATION_PAGE_TRANSLATED,
// The user has changed the browser theme. The source is a
// Source<ThemeService>. There are no details.
NOTIFICATION_BROWSER_THEME_CHANGED,
#if defined(USE_AURA)
// The user has changed the fling curve configuration.
// Source<GesturePrefsObserver>. There are no details.
NOTIFICATION_BROWSER_FLING_CURVE_PARAMETERS_CHANGED,
#endif // defined(USE_AURA)
// Sent when the renderer returns focus to the browser, as part of focus
// traversal. The source is the browser, there are no details.
NOTIFICATION_FOCUS_RETURNED_TO_BROWSER,
// A new tab is created from an existing tab to serve as a target of a
// navigation that is about to happen. The source will be a Source<Profile>
// corresponding to the profile in which the new tab will live. Details in
// the form of a RetargetingDetails object are provided.
NOTIFICATION_RETARGETING,
// Application-wide ----------------------------------------------------------
// This message is sent when the application is terminating (the last
// browser window has shutdown as part of an explicit user-initiated exit,
// or the user closed the last browser window on Windows/Linux and there are
// no BackgroundContents keeping the browser running). No source or details
// are passed.
NOTIFICATION_APP_TERMINATING,
#if defined(OS_MACOSX)
// This notification is sent when the app has no key window, such as when
// all windows are closed but the app is still active. No source or details
// are provided.
NOTIFICATION_NO_KEY_WINDOW,
#endif
// This is sent when the user has chosen to exit the app, but before any
// browsers have closed. This is sent if the user chooses to exit (via exit
// menu item or keyboard shortcut) or to restart the process (such as in flags
// page), not if Chrome exits by some other means (such as the user closing
// the last window). No source or details are passed.
//
// Note that receiving this notification does not necessarily mean the process
// will exit because the shutdown process can be cancelled by an unload
// handler. Use APP_TERMINATING for such needs.
NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST,
// Application-modal dialogs -----------------------------------------------
// Sent after an application-modal dialog has been shown. The source
// is the dialog.
NOTIFICATION_APP_MODAL_DIALOG_SHOWN,
// This message is sent when a new InfoBar has been added to an
// InfoBarService. The source is a Source<InfoBarService> with a pointer to
// the InfoBarService the InfoBar was added to. The details is a
// Details<InfoBar::AddedDetails>.
NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED,
// This message is sent when an InfoBar is about to be removed from an
// InfoBarService. The source is a Source<InfoBarService> with a pointer to
// the InfoBarService the InfoBar was removed from. The details is a
// Details<InfoBar::RemovedDetails>.
NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
// This message is sent when an InfoBar is replacing another infobar in an
// InfoBarService. The source is a Source<InfoBarService> with a pointer to
// the InfoBarService the InfoBar was removed from. The details is a
// Details<InfoBar::ReplacedDetails>.
NOTIFICATION_TAB_CONTENTS_INFOBAR_REPLACED,
// Used to fire notifications about how long various events took to
// complete. E.g., this is used to get more fine grained timings from the
// new tab page. The source is a WebContents and the details is a
// MetricEventDurationDetails.
NOTIFICATION_METRIC_EVENT_DURATION,
// This notification is sent when extensions::TabHelper::SetExtensionApp is
// invoked. The source is the extensions::TabHelper SetExtensionApp was
// invoked on.
NOTIFICATION_TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED,
// Tabs --------------------------------------------------------------------
// Sent when a tab is added to a WebContentsDelegate. The source is the
// WebContentsDelegate and the details is the added WebContents.
NOTIFICATION_TAB_ADDED,
// This notification is sent after a tab has been appended to the tab_strip.
// The source is a Source<WebContents> of the tab being added. There
// are no details.
NOTIFICATION_TAB_PARENTED,
// This message is sent before a tab has been closed. The source is a
// Source<NavigationController> with a pointer to the controller for the
// closed tab. No details are expected.
//
// See also content::NOTIFICATION_WEB_CONTENTS_DESTROYED, which is sent when
// the WebContents containing the NavigationController is destroyed.
NOTIFICATION_TAB_CLOSING,
// Stuff inside the tabs ---------------------------------------------------
// This notification is sent when the result of a find-in-page search is
// available with the browser process. The source is a Source<WebContents>.
// Details encompass a FindNotificationDetail object that tells whether the
// match was found or not found.
NOTIFICATION_FIND_RESULT_AVAILABLE,
// BackgroundContents ------------------------------------------------------
// A new background contents was opened by script. The source is the parent
// profile and the details are BackgroundContentsOpenedDetails.
NOTIFICATION_BACKGROUND_CONTENTS_OPENED,
// The background contents navigated to a new location. The source is the
// parent Profile, and the details are the BackgroundContents that was
// navigated.
NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED,
// The background contents were closed by someone invoking window.close()
// or the parent application was uninstalled.
// The source is the parent profile, and the details are the
// BackgroundContents.
NOTIFICATION_BACKGROUND_CONTENTS_CLOSED,
// The background contents is being deleted. The source is the
// parent Profile, and the details are the BackgroundContents being deleted.
NOTIFICATION_BACKGROUND_CONTENTS_DELETED,
// The background contents has crashed. The source is the parent Profile,
// and the details are the BackgroundContents.
NOTIFICATION_BACKGROUND_CONTENTS_TERMINATED,
// The background contents associated with a hosted app has changed (either
// a new background contents has been created, or an existing background
// contents has closed). The source is the parent Profile, and the details
// are the BackgroundContentsService.
NOTIFICATION_BACKGROUND_CONTENTS_SERVICE_CHANGED,
// Chrome has entered/exited background mode. The source is the
// BackgroundModeManager and the details are a boolean value which is set to
// true if Chrome is now in background mode.
NOTIFICATION_BACKGROUND_MODE_CHANGED,
// This is sent when a login prompt is shown. The source is the
// Source<NavigationController> for the tab in which the prompt is shown.
// Details are a LoginNotificationDetails which provide the LoginHandler
// that should be given authentication.
NOTIFICATION_AUTH_NEEDED,
// This is sent when authentication credentials have been supplied (either
// by the user or by an automation service), but before we've actually
// received another response from the server. The source is the
// Source<NavigationController> for the tab in which the prompt was shown.
// Details are an AuthSuppliedLoginNotificationDetails which provide the
// LoginHandler that should be given authentication as well as the supplied
// username and password.
NOTIFICATION_AUTH_SUPPLIED,
// This is sent when an authentication request has been dismissed without
// supplying credentials (either by the user or by an automation service).
// The source is the Source<NavigationController> for the tab in which the
// prompt was shown. Details are a LoginNotificationDetails which provide
// the LoginHandler that should be cancelled.
NOTIFICATION_AUTH_CANCELLED,
// History -----------------------------------------------------------------
// Sent when a history service has finished loading. The source is the
// profile that the history service belongs to, and the details is the
// HistoryService.
NOTIFICATION_HISTORY_LOADED,
// Sent when a URL has been added or modified. This is used by the in-memory
// URL database and the InMemoryURLIndex (both used by autocomplete) to track
// changes to the main history system.
//
// The source is the profile owning the history service that changed, and
// the details is history::URLsModifiedDetails that lists the modified or
// added URLs.
NOTIFICATION_HISTORY_URLS_MODIFIED,
// Sent when the user visits a URL.
//
// The source is the profile owning the history service that changed, and
// the details is history::URLVisitedDetails.
NOTIFICATION_HISTORY_URL_VISITED,
// Sent when one or more URLs are deleted.
//
// The source is the profile owning the history service that changed, and
// the details is history::URLsDeletedDetails that lists the deleted URLs.
NOTIFICATION_HISTORY_URLS_DELETED,
// Sent when a keyword search term is updated. The source is the Profile and
// the details is history::KeywordSearchUpdatedDetails.
NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED,
// Sent when a keyword search term is deleted. The source is the Profile and
// the details is history::KeywordSearchDeletedDetails.
NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_DELETED,
// Sent by history when the favicon of a URL changes. The source is the
// profile, and the details is FaviconChangedDetails (see
// chrome/browser/favicon/favicon_changed_details.h).
NOTIFICATION_FAVICON_CHANGED,
// Sent by FaviconTabHelper when a tab's favicon has been successfully
// updated. The details are a bool indicating whether the
// NavigationEntry's favicon URL has changed since the previous
// NOTIFICATION_FAVICON_UPDATED notification. The details are true if
// there was no previous NOTIFICATION_FAVICON_UPDATED notification for the
// current NavigationEntry.
NOTIFICATION_FAVICON_UPDATED,
// Profiles -----------------------------------------------------------------
// Sent after a Profile has been created. This notification is sent both for
// normal and OTR profiles.
// The details are none and the source is the new profile.
NOTIFICATION_PROFILE_CREATED,
// Sent after a Profile has been added to ProfileManager.
// The details are none and the source is the new profile.
NOTIFICATION_PROFILE_ADDED,
// Sent before a Profile is destroyed. This notification is sent both for
// normal and OTR profiles.
// The details are none and the source is a Profile*.
NOTIFICATION_PROFILE_DESTROYED,
// Sent after the URLRequestContextGetter for a Profile has been initialized.
// The details are none and the source is a Profile*.
NOTIFICATION_PROFILE_URL_REQUEST_CONTEXT_GETTER_INITIALIZED,
// TopSites ----------------------------------------------------------------
// Sent by TopSites when it finishes loading. The source is the profile the
// details the TopSites.
NOTIFICATION_TOP_SITES_LOADED,
// Sent by TopSites when the either one of the most visited urls changed, or
// one of the images changes. The source is the TopSites, the details not
// used.
NOTIFICATION_TOP_SITES_CHANGED,
// Task Manager ------------------------------------------------------------
// Sent when a renderer process is notified of new v8 heap statistics. The
// source is the ID of the renderer process, and the details are a
// V8HeapStatsDetails object.
NOTIFICATION_RENDERER_V8_HEAP_STATS_COMPUTED,
// Non-history storage services --------------------------------------------
// Sent when a TemplateURL is removed from the model. The source is the
// Profile, and the details the id of the TemplateURL being removed.
NOTIFICATION_TEMPLATE_URL_REMOVED,
// Sent when the prefs relating to the default search engine have changed due
// to policy. Source and details are unused.
NOTIFICATION_DEFAULT_SEARCH_POLICY_CHANGED,
// The state of a web resource has been changed. A resource may have been
// added, removed, or altered. Source is WebResourceService, and the
// details are NoDetails.
NOTIFICATION_PROMO_RESOURCE_STATE_CHANGED,
// A safe browsing database update completed. Source is the
// SafeBrowsingService and the details are a bool indicating whether the
// update was successful.
NOTIFICATION_SAFE_BROWSING_UPDATE_COMPLETE,
// Autocomplete ------------------------------------------------------------
// Sent by the autocomplete controller when done. The source is the
// AutocompleteController, the details not used.
NOTIFICATION_AUTOCOMPLETE_CONTROLLER_RESULT_READY,
// This is sent when an item of the Omnibox popup is selected. The source
// is the profile.
NOTIFICATION_OMNIBOX_OPENED_URL,
// This is sent from Instant when the omnibox focus state changes.
NOTIFICATION_OMNIBOX_FOCUS_CHANGED,
// Sent when the Google URL for a profile has been updated. Some services
// cache this value and need to update themselves when it changes. See
// google_util::GetGoogleURLAndUpdateIfNecessary(). The source is the
// Profile, the details a GoogleURLTracker::UpdatedDetails containing the old
// and new URLs.
//
// Note that because incognito mode requests for the GoogleURLTracker are
// redirected to the non-incognito profile's copy, this notification will only
// ever fire on non-incognito profiles; thus listeners should use
// GetOriginalProfile() when constructing a Source to filter against.
NOTIFICATION_GOOGLE_URL_UPDATED,
// Printing ----------------------------------------------------------------
// Notification from PrintJob that an event occurred. It can be that a page
// finished printing or that the print job failed. Details is
// PrintJob::EventDetails. Source is a PrintJob.
NOTIFICATION_PRINT_JOB_EVENT,
// Sent when a PrintJob has been released.
// Source is the WebContents that holds the print job.
NOTIFICATION_PRINT_JOB_RELEASED,
// Shutdown ----------------------------------------------------------------
// Sent when WM_ENDSESSION has been received, after the browsers have been
// closed but before browser process has been shutdown. The source/details
// are all source and no details.
NOTIFICATION_SESSION_END,
// User Scripts ------------------------------------------------------------
// Sent when there are new user scripts available. The details are a
// pointer to SharedMemory containing the new scripts.
NOTIFICATION_USER_SCRIPTS_UPDATED,
// Extensions --------------------------------------------------------------
// Sent when a CrxInstaller finishes. Source is the CrxInstaller that
// finished. The details are the extension which was installed.
NOTIFICATION_CRX_INSTALLER_DONE,
// Sent when the known installed extensions have all been loaded. In
// testing scenarios this can happen multiple times if extensions are
// unloaded and reloaded. The source is a Profile.
NOTIFICATION_EXTENSIONS_READY,
// Sent when an extension icon being displayed in the location bar is updated.
// The source is the Profile and the details are the WebContents for
// the tab.
NOTIFICATION_EXTENSION_LOCATION_BAR_UPDATED,
// DEPRECATED: Use ExtensionRegistry::AddObserver instead.
//
// Sent when a new extension is loaded. The details are an Extension, and
// the source is a Profile.
NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
// An error occured while attempting to load an extension. The details are a
// string with details about why the load failed.
NOTIFICATION_EXTENSION_LOAD_ERROR,
// Sent when an extension is enabled. Under most circumstances, listeners
// will want to use NOTIFICATION_EXTENSION_LOADED_DEPRECATED. This
// notification is only
// fired when the "Enable" button is hit in the extensions tab. The details
// are an Extension, and the source is a Profile.
NOTIFICATION_EXTENSION_ENABLED,
// Sent when attempting to load a new extension, but they are disabled. The
// details are an Extension*, and the source is a Profile*.
NOTIFICATION_EXTENSION_UPDATE_DISABLED,
// Sent when an extension's permissions change. The details are an
// UpdatedExtensionPermissionsInfo, and the source is a Profile.
NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED,
// Sent when new extensions are installed, or existing extensions are updated.
// The details are an InstalledExtensionInfo, and the source is a Profile.
NOTIFICATION_EXTENSION_INSTALLED,
// An error occured during extension install. The details are a string with
// details about why the install failed.
NOTIFICATION_EXTENSION_INSTALL_ERROR,
// Sent when an extension has been uninstalled. The details are an Extension,
// and the source is a Profile.
NOTIFICATION_EXTENSION_UNINSTALLED,
// Sent when an extension uninstall is not allowed because the extension is
// not user manageable. The details are an Extension, and the source is a
// Profile.
NOTIFICATION_EXTENSION_UNINSTALL_NOT_ALLOWED,
// DEPRECATED: Use ExtensionRegistry::AddObserver instead.
//
// Sent when an extension is unloaded. This happens when an extension is
// uninstalled or disabled. The details are an UnloadedExtensionInfo, and
// the source is a Profile.
//
// Note that when this notification is sent, ExtensionService has already
// removed the extension from its internal state.
NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
// Sent when an Extension object is removed from ExtensionService. This
// can happen when an extension is uninstalled, upgraded, or blacklisted,
// including all cases when the Extension is deleted. The details are an
// Extension, and the source is a Profile.
NOTIFICATION_EXTENSION_REMOVED,
// Sent after a new ExtensionHost is created. The details are
// an ExtensionHost* and the source is a Profile*.
NOTIFICATION_EXTENSION_HOST_CREATED,
// Sent before an ExtensionHost is destroyed. The details are
// an ExtensionHost* and the source is a Profile*.
NOTIFICATION_EXTENSION_HOST_DESTROYED,
// Sent by an ExtensionHost when it has finished its initial page load,
// including any external resources.
// The details are an ExtensionHost* and the source is a Profile*.
NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
// Sent by an ExtensionHost when its render view requests closing through
// window.close(). The details are an ExtensionHost* and the source is a
// Profile*.
NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
// Sent when extension render process ends (whether it crashes or closes).
// The details are an ExtensionHost* and the source is a Profile*. Not sent
// during browser shutdown.
NOTIFICATION_EXTENSION_PROCESS_TERMINATED,
// Sent when a background page is ready so other components can load.
NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY,
// Sent when a browser action's state has changed. The source is the
// ExtensionAction* that changed. The details are the Profile* that the
// browser action belongs to.
NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED,
// Sent when the count of page actions has changed. Note that some of them
// may not apply to the current page. The source is a LocationBar*. There
// are no details.
NOTIFICATION_EXTENSION_PAGE_ACTION_COUNT_CHANGED,
// Sent when a browser action's visibility has changed. The source is the
// ExtensionPrefs* that changed, and the details are a std::string with the
// extension's ID.
NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED,
// Sent when a page action's visibility has changed. The source is the
// ExtensionAction* that changed. The details are a WebContents*.
NOTIFICATION_EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED,
// Sent when a system indicator action's state has changed. The source is the
// Profile* that the browser action belongs to. The details are the
// ExtensionAction* that changed.
NOTIFICATION_EXTENSION_SYSTEM_INDICATOR_UPDATED,
// Sent when an extension command has been removed. The source is the profile
// and the details is a std::pair of two std::string objects (an extension ID
// and the name of the command being removed).
NOTIFICATION_EXTENSION_COMMAND_REMOVED,
// Sent when an extension command has been added. The source is the profile
// and the details is a std::pair of two std::string objects (an extension ID
// and the name of the command being added).
NOTIFICATION_EXTENSION_COMMAND_ADDED,
// Sent when an extension command shortcut for a browser action is activated
// on Mac. The source is the profile and the details is a std::pair of a
// std::string containing an extension ID and a gfx::NativeWindow for the
// associated window.
NOTIFICATION_EXTENSION_COMMAND_BROWSER_ACTION_MAC,
// Sent when an extension command shortcut for a page action is activated
// on Mac. The source is the profile and the details is a std::pair of a
// std::string containing an extension ID and a gfx::NativeWindow for the
// associated window.
NOTIFICATION_EXTENSION_COMMAND_PAGE_ACTION_MAC,
// A new extension RenderViewHost has been registered. The details are
// the RenderViewHost*.
NOTIFICATION_EXTENSION_VIEW_REGISTERED,
// An extension RenderViewHost has been unregistered. The details are
// the RenderViewHost*.
NOTIFICATION_EXTENSION_VIEW_UNREGISTERED,
// Sent by an extension to notify the browser about the results of a unit
// test.
NOTIFICATION_EXTENSION_TEST_PASSED,
NOTIFICATION_EXTENSION_TEST_FAILED,
// Sent by extension test javascript code, typically in a browser test. The
// sender is a std::string representing the extension id, and the details
// are a std::string with some message. This is particularly useful when you
// want to have C++ code wait for javascript code to do something.
NOTIFICATION_EXTENSION_TEST_MESSAGE,
// Sent when an bookmarks extensions API function was successfully invoked.
// The source is the id of the extension that invoked the function, and the
// details are a pointer to the const BookmarksFunction in question.
NOTIFICATION_EXTENSION_BOOKMARKS_API_INVOKED,
// Sent when a downloads extensions API event is fired. The source is an
// ExtensionDownloadsEventRouter::NotificationSource, and the details is a
// std::string containing json. Used for testing.
NOTIFICATION_EXTENSION_DOWNLOADS_EVENT,
// Sent when an omnibox extension has sent back omnibox suggestions. The
// source is the profile, and the details are an
// extensions::api::omnibox::SendSuggestions::Params object.
NOTIFICATION_EXTENSION_OMNIBOX_SUGGESTIONS_READY,
// Sent when the user accepts the input in an extension omnibox keyword
// session. The source is the profile.
NOTIFICATION_EXTENSION_OMNIBOX_INPUT_ENTERED,
// Sent when an omnibox extension has updated the default suggestion. The
// source is the profile.
NOTIFICATION_EXTENSION_OMNIBOX_DEFAULT_SUGGESTION_CHANGED,
// Sent when the extension updater starts checking for updates to installed
// extensions. The source is a Profile, and there are no details.
NOTIFICATION_EXTENSION_UPDATING_STARTED,
// The extension updater found an update and will attempt to download and
// install it. The source is a Profile, and the details are an
// extensions::UpdateDetails object with the extension id and version of the
// found update.
NOTIFICATION_EXTENSION_UPDATE_FOUND,
// Upgrade notifications ---------------------------------------------------
// Sent when Chrome believes an update has been installed and available for
// long enough with the user shutting down to let it take effect. See
// upgrade_detector.cc for details on how long it waits. No details are
// expected.
NOTIFICATION_UPGRADE_RECOMMENDED,
// Sent when a critical update has been installed. No details are expected.
NOTIFICATION_CRITICAL_UPGRADE_INSTALLED,
// Sent when the current install is outdated. No details are expected.
NOTIFICATION_OUTDATED_INSTALL,
// Sent when the current install is outdated and auto-update (AU) is disabled.
// No details are expected.
NOTIFICATION_OUTDATED_INSTALL_NO_AU,
// Software incompatibility notifications ----------------------------------
// Sent when Chrome has finished compiling the list of loaded modules (and
// other modules of interest). No details are expected.
NOTIFICATION_MODULE_LIST_ENUMERATED,
// Sent when Chrome is done scanning the module list and when the user has
// acknowledged the module incompatibility. No details are expected.
NOTIFICATION_MODULE_INCOMPATIBILITY_BADGE_CHANGE,
// Content Settings --------------------------------------------------------
// Sent when content settings change. The source is a HostContentSettings
// object, the details are ContentSettingsNotificationsDetails.
NOTIFICATION_CONTENT_SETTINGS_CHANGED,
// Sent when the collect cookies dialog is shown. The source is a
// TabSpecificContentSettings object, there are no details.
NOTIFICATION_COLLECTED_COOKIES_SHOWN,
// Sent when a non-default setting in the the notification content settings
// map has changed. The source is the DesktopNotificationService, the
// details are None.
NOTIFICATION_DESKTOP_NOTIFICATION_SETTINGS_CHANGED,
// Sent when content settings change for a tab. The source is a
// content::WebContents object, the details are None.
NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
// Sync --------------------------------------------------------------------
// The sync service has finished the datatype configuration process. The
// source is the ProfileSyncService object of the Profile. There are no
// details.
NOTIFICATION_SYNC_CONFIGURE_DONE,
// A service is requesting a sync datatype refresh for the current profile.
// The details value is a const syncer::ModelTypeSet.
// If the payload map is empty, it should be treated as an invalidation for
// all enabled types. This is used by session sync.
NOTIFICATION_SYNC_REFRESH_LOCAL,
// External notification requesting a sync datatype refresh for the current
// profile. The details value is a const syncer::ObjectIdInvalidationMap.
// If the payload map is empty, it should be treated as an invalidation for
// all enabled types. This is used for notifications on Android.
NOTIFICATION_SYNC_REFRESH_REMOTE,
// The session service has been saved. This notification type is only sent
// if there were new SessionService commands to save, and not for no-op save
// operations.
NOTIFICATION_SESSION_SERVICE_SAVED,
// A foreign session has been updated. If a new tab page is open, the
// foreign session handler needs to update the new tab page's foreign
// session data.
NOTIFICATION_FOREIGN_SESSION_UPDATED,
// Foreign sessions has been disabled. New tabs should not display foreign
// session data.
NOTIFICATION_FOREIGN_SESSION_DISABLED,
// All tab metadata has been loaded from disk asynchronously.
// Sent on the UI thread.
// The source is the Profile. There are no details.
NOTIFICATION_SESSION_RESTORE_COMPLETE,
// Cookies -----------------------------------------------------------------
// Sent when a cookie changes. The source is a Profile object, the details
// are a ChromeCookieDetails object.
NOTIFICATION_COOKIE_CHANGED,
// Download Notifications --------------------------------------------------
// Sent when a download is initiated. It is possible that the download will
// not actually begin due to the DownloadRequestLimiter cancelling it
// prematurely.
// The source is the corresponding RenderViewHost. There are no details.
NOTIFICATION_DOWNLOAD_INITIATED,
// Misc --------------------------------------------------------------------
// Sent when PerformanceMonitor has finished all the initial steps of data
// collection and has begun passively observing. The source is the
// PerformanceMonitor*. No details are expected.
NOTIFICATION_PERFORMANCE_MONITOR_INITIALIZED,
#if defined(OS_CHROMEOS)
// Sent when a chromium os user logs in.
// The details are a chromeos::User object.
NOTIFICATION_LOGIN_USER_CHANGED,
// Sent immediately after the logged-in user's profile is ready.
// The details are a Profile object.
NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
// Sent when the chromium session of a particular user is started.
// If this is a new user on the machine this will not be sent until a profile
// picture has been selected, unlike NOTIFICATION_LOGIN_USER_CHANGED which is
// sent immediately after the user has logged in. This will be sent again if
// the browser crashes and restarts.
// The details are a chromeos::User object.
NOTIFICATION_SESSION_STARTED,
// Sent when user image is updated.
NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
// Sent by UserManager when a profile image download has been completed.
NOTIFICATION_PROFILE_IMAGE_UPDATED,
// Sent by UserManager when profile image download has failed or user has the
// default profile image or no profile image at all. No details are expected.
NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
// Sent when a chromium os user attempts to log in. The source is
// all and the details are AuthenticationNotificationDetails.
NOTIFICATION_LOGIN_AUTHENTICATION,
// Sent when a network error message is displayed on the WebUI login screen.
// First paint event of this fires NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE.
NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN,
// Sent when the specific part of login/lock WebUI is considered to be
// visible. That moment is tracked as the first paint event after one of the:
// NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN
//
// Possible series of notifications:
// 1. Boot into fresh OOBE
// NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE
// 2. Boot into user pods list (normal boot). Same for lock screen.
// NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE
// 3. Boot into GAIA sign in UI (user pods display disabled or no users):
// if no network is connected or flaky network
// (NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN +
// NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE)
// NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE
// 4. Boot into retail mode
// NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE
// 5. Boot into kiosk mode
// NOTIFICATION_KIOSK_APP_LAUNCHED
NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
// Sent when proxy dialog is closed.
NOTIFICATION_LOGIN_PROXY_CHANGED,
// Send when kiosk auto-launch warning screen is visible.
NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_VISIBLE,
// Send when kiosk auto-launch warning screen had completed.
NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_COMPLETED,
// Send when enable consumer kiosk warning screen is visible.
NOTIFICATION_KIOSK_ENABLE_WARNING_VISIBLE,
// Send when consumer kiosk has been enabled.
NOTIFICATION_KIOSK_ENABLED,
// Send when enable consumer kiosk warning screen had completed.
NOTIFICATION_KIOSK_ENABLE_WARNING_COMPLETED,
// Sent when kiosk app list is loaded in UI.
NOTIFICATION_KIOSK_APPS_LOADED,
// Sent when a kiosk app is launched.
NOTIFICATION_KIOSK_APP_LAUNCHED,
// Sent when the user list has changed.
NOTIFICATION_USER_LIST_CHANGED,
// Sent when the screen lock state has changed. The source is
// ScreenLocker and the details is a bool specifing that the
// screen is locked. When details is a false, the source object
// is being deleted, so the receiver shouldn't use the screen locker
// object.
NOTIFICATION_SCREEN_LOCK_STATE_CHANGED,
// Sent by DeviceSettingsService to indicate that the ownership status
// changed. If you can, please use DeviceSettingsService::Observer instead.
// Other singleton-based services can't use that because Observer
// unregistration is impossible due to unpredictable deletion order.
NOTIFICATION_OWNERSHIP_STATUS_CHANGED,
// Sent by SIM unlock dialog when it has finished with the process of
// updating RequirePin setting. RequirePin setting might have been changed
// to a new value or update might have been canceled.
// In either case notification is sent and details contain a bool
// that represents current value.
NOTIFICATION_REQUIRE_PIN_SETTING_CHANGE_ENDED,
// Sent by SIM unlock dialog when it has finished the EnterPin or
// EnterPuk dialog, either because the user cancelled, or entered a
// PIN or PUK.
NOTIFICATION_ENTER_PIN_ENDED,
#endif
#if defined(TOOLKIT_VIEWS)
// Sent when a bookmark's context menu is shown. Used to notify
// tests that the context menu has been created and shown.
NOTIFICATION_BOOKMARK_CONTEXT_MENU_SHOWN,
// Notification that the nested loop using during tab dragging has returned.
// Used for testing.
NOTIFICATION_TAB_DRAG_LOOP_DONE,
#endif
// Send when a context menu is shown. Used to notify tests that the context
// menu has been created and shown.
NOTIFICATION_RENDER_VIEW_CONTEXT_MENU_SHOWN,
// Sent when the Instant Controller determines whether an Instant tab supports
// the Instant API or not.
NOTIFICATION_INSTANT_TAB_SUPPORT_DETERMINED,
// Sent when the Instant Controller determines whether the NTP supports the
// Instant API or not.
NOTIFICATION_INSTANT_NTP_SUPPORT_DETERMINED,
// Sent when the CaptivePortalService checks if we're behind a captive portal.
// The Source is the Profile the CaptivePortalService belongs to, and the
// Details are a Details<CaptivePortalService::CheckResults>.
NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT,
// Sent when the applications in the NTP app launcher have been reordered.
// The details, if not NoDetails, is the std::string ID of the extension that
// was moved.
NOTIFICATION_EXTENSION_LAUNCHER_REORDERED,
// Sent when an app is installed and an NTP has been shown. Source is the
// WebContents that was shown, and Details is the string ID of the extension
// which was installed.
NOTIFICATION_APP_INSTALLED_TO_NTP,
// Similar to NOTIFICATION_APP_INSTALLED_TO_NTP but used to nofity ash AppList
// about installed app. Source is the profile in which the app is installed
// and Details is the string ID of the extension.
NOTIFICATION_APP_INSTALLED_TO_APPLIST,
#if defined(USE_ASH)
// Sent when wallpaper show animation has finished.
NOTIFICATION_WALLPAPER_ANIMATION_FINISHED,
// Sent when the Ash session has started. In its current incantation this is
// generated when the metro app has connected to the browser IPC channel.
// Used only on Windows.
NOTIFICATION_ASH_SESSION_STARTED,
// Sent when the Ash session ended. Currently this means the metro app exited.
// Used only on Windows.
NOTIFICATION_ASH_SESSION_ENDED,
#endif
// Protocol Handler Registry -----------------------------------------------
// Sent when a ProtocolHandlerRegistry is changed. The source is the profile.
NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED,
// Sent when the cached profile info has changed.
NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
// Sent when the cached profile has finished writing a profile picture to
// disk.
NOTIFICATION_PROFILE_CACHE_PICTURE_SAVED,
// Sent when the browser enters or exits fullscreen mode.
NOTIFICATION_FULLSCREEN_CHANGED,
// Sent when the FullscreenController changes, confirms, or denies mouse lock.
// The source is the browser's FullscreenController, no details.
NOTIFICATION_MOUSE_LOCK_CHANGED,
// Sent by the PluginPrefs when there is a change of plugin enable/disable
// status. The source is the profile.
NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED,
// Panels Notifications. The Panels are small browser windows near the bottom
// of the screen.
// Sent when all nonblocking bounds animations are finished across panels.
// Used only in unit testing.
NOTIFICATION_PANEL_BOUNDS_ANIMATIONS_FINISHED,
// Sent when panel gains/loses focus.
// The source is the Panel, no details.
// Used only in unit testing.
NOTIFICATION_PANEL_CHANGED_ACTIVE_STATUS,
// Sent when panel is minimized/restored/shows title only etc.
// The source is the Panel, no details.
NOTIFICATION_PANEL_CHANGED_EXPANSION_STATE,
// Sent when panel window size is known. This is for platforms where the
// window creation is async and size of the window only becomes known later.
// Used only in unit testing.
NOTIFICATION_PANEL_WINDOW_SIZE_KNOWN,
// Sent when panel app icon is loaded.
// Used only in unit testing.
NOTIFICATION_PANEL_APP_ICON_LOADED,
// Sent when panel collection get updated.
// The source is the PanelCollection, no details.
// Used only in coordination with notification balloons.
NOTIFICATION_PANEL_COLLECTION_UPDATED,
// Sent when panel is closed.
// The source is the Panel, no details.
NOTIFICATION_PANEL_CLOSED,
// Sent when a global error has changed and the error UI should update it
// self. The source is a Source<Profile> containing the profile for the
// error. The detail is a GlobalError object that has changed or NULL if
// all error UIs should update.
NOTIFICATION_GLOBAL_ERRORS_CHANGED,
// BrowsingDataRemover ----------------------------------------------------
// Sent on the UI thread after BrowsingDataRemover has removed browsing data
// but before it has notified its explicit observers. The source is a
// Source<Profile> containing the profile in which browsing data was removed,
// and the detail is a BrowsingDataRemover::NotificationDetail containing the
// removal mask and the start of the removal timeframe with which
// BrowsingDataRemove::Remove was called.
NOTIFICATION_BROWSING_DATA_REMOVED,
// The user accepted or dismissed a SSL client authentication request.
// The source is a Source<net::HttpNetworkSession>. Details is a
// (std::pair<net::SSLCertRequestInfo*, net::X509Certificate*>).
NOTIFICATION_SSL_CLIENT_AUTH_CERT_SELECTED,
// Session Restore --------------------------------------------------------
// Sent when synchronous (startup) session restore completes. No details or
// source.
NOTIFICATION_SESSION_RESTORE_DONE,
// Note:-
// Currently only Content and Chrome define and use notifications.
// Custom notifications not belonging to Content and Chrome should start
// from here.
NOTIFICATION_CHROME_END,
};
} // namespace chrome
#endif // CHROME_BROWSER_CHROME_NOTIFICATION_TYPES_H_

View File

@@ -0,0 +1,367 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/printing/print_job.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/message_loop/message_loop.h"
#include "base/threading/thread_restrictions.h"
#include "base/threading/worker_pool.h"
#include "base/timer/timer.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/printing/print_job_worker.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
#include "printing/printed_document.h"
#include "printing/printed_page.h"
using base::TimeDelta;
namespace {
// Helper function to ensure |owner| is valid until at least |callback| returns.
void HoldRefCallback(const scoped_refptr<printing::PrintJobWorkerOwner>& owner,
const base::Closure& callback) {
callback.Run();
}
} // namespace
namespace printing {
PrintJob::PrintJob()
: ui_message_loop_(base::MessageLoop::current()),
source_(NULL),
worker_(),
settings_(),
is_job_pending_(false),
is_canceling_(false),
quit_factory_(this) {
DCHECK(ui_message_loop_);
// This is normally a UI message loop, but in unit tests, the message loop is
// of the 'default' type.
DCHECK(base::MessageLoopForUI::IsCurrent() ||
ui_message_loop_->type() == base::MessageLoop::TYPE_DEFAULT);
ui_message_loop_->AddDestructionObserver(this);
}
PrintJob::~PrintJob() {
ui_message_loop_->RemoveDestructionObserver(this);
// The job should be finished (or at least canceled) when it is destroyed.
DCHECK(!is_job_pending_);
DCHECK(!is_canceling_);
if (worker_.get())
DCHECK(worker_->message_loop() == NULL);
DCHECK_EQ(ui_message_loop_, base::MessageLoop::current());
}
void PrintJob::Initialize(PrintJobWorkerOwner* job,
PrintedPagesSource* source,
int page_count) {
DCHECK(!source_);
DCHECK(!worker_.get());
DCHECK(!is_job_pending_);
DCHECK(!is_canceling_);
DCHECK(!document_.get());
source_ = source;
worker_.reset(job->DetachWorker(this));
settings_ = job->settings();
PrintedDocument* new_doc =
new PrintedDocument(settings_,
source_,
job->cookie(),
content::BrowserThread::GetBlockingPool());
new_doc->set_page_count(page_count);
UpdatePrintedDocument(new_doc);
// Don't forget to register to our own messages.
registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT,
content::Source<PrintJob>(this));
}
void PrintJob::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
DCHECK_EQ(ui_message_loop_, base::MessageLoop::current());
switch (type) {
case chrome::NOTIFICATION_PRINT_JOB_EVENT: {
OnNotifyPrintJobEvent(*content::Details<JobEventDetails>(details).ptr());
break;
}
default: {
break;
}
}
}
void PrintJob::GetSettingsDone(const PrintSettings& new_settings,
PrintingContext::Result result) {
NOTREACHED();
}
PrintJobWorker* PrintJob::DetachWorker(PrintJobWorkerOwner* new_owner) {
NOTREACHED();
return NULL;
}
base::MessageLoop* PrintJob::message_loop() {
return ui_message_loop_;
}
const PrintSettings& PrintJob::settings() const {
return settings_;
}
int PrintJob::cookie() const {
if (!document_.get())
// Always use an invalid cookie in this case.
return 0;
return document_->cookie();
}
void PrintJob::WillDestroyCurrentMessageLoop() {
NOTREACHED();
}
void PrintJob::StartPrinting() {
DCHECK_EQ(ui_message_loop_, base::MessageLoop::current());
DCHECK(worker_->message_loop());
DCHECK(!is_job_pending_);
if (!worker_->message_loop() || is_job_pending_)
return;
// Real work is done in PrintJobWorker::StartPrinting().
worker_->message_loop()->PostTask(
FROM_HERE,
base::Bind(&HoldRefCallback, make_scoped_refptr(this),
base::Bind(&PrintJobWorker::StartPrinting,
base::Unretained(worker_.get()), document_)));
// Set the flag right now.
is_job_pending_ = true;
// Tell everyone!
scoped_refptr<JobEventDetails> details(
new JobEventDetails(JobEventDetails::NEW_DOC, document_.get(), NULL));
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_PRINT_JOB_EVENT,
content::Source<PrintJob>(this),
content::Details<JobEventDetails>(details.get()));
}
void PrintJob::Stop() {
DCHECK_EQ(ui_message_loop_, base::MessageLoop::current());
if (quit_factory_.HasWeakPtrs()) {
// In case we're running a nested message loop to wait for a job to finish,
// and we finished before the timeout, quit the nested loop right away.
Quit();
quit_factory_.InvalidateWeakPtrs();
}
// Be sure to live long enough.
scoped_refptr<PrintJob> handle(this);
if (worker_->message_loop()) {
ControlledWorkerShutdown();
} else {
// Flush the cached document.
UpdatePrintedDocument(NULL);
}
}
void PrintJob::Cancel() {
if (is_canceling_)
return;
is_canceling_ = true;
// Be sure to live long enough.
scoped_refptr<PrintJob> handle(this);
DCHECK_EQ(ui_message_loop_, base::MessageLoop::current());
base::MessageLoop* worker_loop =
worker_.get() ? worker_->message_loop() : NULL;
if (worker_loop) {
// Call this right now so it renders the context invalid. Do not use
// InvokeLater since it would take too much time.
worker_->Cancel();
}
// Make sure a Cancel() is broadcast.
scoped_refptr<JobEventDetails> details(
new JobEventDetails(JobEventDetails::FAILED, NULL, NULL));
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_PRINT_JOB_EVENT,
content::Source<PrintJob>(this),
content::Details<JobEventDetails>(details.get()));
Stop();
is_canceling_ = false;
}
bool PrintJob::FlushJob(base::TimeDelta timeout) {
// Make sure the object outlive this message loop.
scoped_refptr<PrintJob> handle(this);
base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
base::Bind(&PrintJob::Quit, quit_factory_.GetWeakPtr()), timeout);
base::MessageLoop::ScopedNestableTaskAllower allow(
base::MessageLoop::current());
base::MessageLoop::current()->Run();
return true;
}
void PrintJob::DisconnectSource() {
source_ = NULL;
if (document_.get())
document_->DisconnectSource();
}
bool PrintJob::is_job_pending() const {
return is_job_pending_;
}
PrintedDocument* PrintJob::document() const {
return document_.get();
}
void PrintJob::UpdatePrintedDocument(PrintedDocument* new_document) {
if (document_.get() == new_document)
return;
document_ = new_document;
if (document_.get()) {
settings_ = document_->settings();
}
if (worker_.get() && worker_->message_loop()) {
DCHECK(!is_job_pending_);
// Sync the document with the worker.
worker_->message_loop()->PostTask(
FROM_HERE,
base::Bind(&HoldRefCallback, make_scoped_refptr(this),
base::Bind(&PrintJobWorker::OnDocumentChanged,
base::Unretained(worker_.get()), document_)));
}
}
void PrintJob::OnNotifyPrintJobEvent(const JobEventDetails& event_details) {
switch (event_details.type()) {
case JobEventDetails::FAILED: {
settings_.Clear();
// No need to cancel since the worker already canceled itself.
Stop();
break;
}
case JobEventDetails::USER_INIT_DONE:
case JobEventDetails::DEFAULT_INIT_DONE:
case JobEventDetails::USER_INIT_CANCELED: {
DCHECK_EQ(event_details.document(), document_.get());
break;
}
case JobEventDetails::NEW_DOC:
case JobEventDetails::NEW_PAGE:
case JobEventDetails::PAGE_DONE:
case JobEventDetails::JOB_DONE:
case JobEventDetails::ALL_PAGES_REQUESTED: {
// Don't care.
break;
}
case JobEventDetails::DOC_DONE: {
// This will call Stop() and broadcast a JOB_DONE message.
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(&PrintJob::OnDocumentDone, this));
break;
}
default: {
NOTREACHED();
break;
}
}
}
void PrintJob::OnDocumentDone() {
// Be sure to live long enough. The instance could be destroyed by the
// JOB_DONE broadcast.
scoped_refptr<PrintJob> handle(this);
// Stop the worker thread.
Stop();
scoped_refptr<JobEventDetails> details(
new JobEventDetails(JobEventDetails::JOB_DONE, document_.get(), NULL));
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_PRINT_JOB_EVENT,
content::Source<PrintJob>(this),
content::Details<JobEventDetails>(details.get()));
}
void PrintJob::ControlledWorkerShutdown() {
DCHECK_EQ(ui_message_loop_, base::MessageLoop::current());
// The deadlock this code works around is specific to window messaging on
// Windows, so we aren't likely to need it on any other platforms.
#if defined(OS_WIN)
// We could easily get into a deadlock case if worker_->Stop() is used; the
// printer driver created a window as a child of the browser window. By
// canceling the job, the printer driver initiated dialog box is destroyed,
// which sends a blocking message to its parent window. If the browser window
// thread is not processing messages, a deadlock occurs.
//
// This function ensures that the dialog box will be destroyed in a timely
// manner by the mere fact that the thread will terminate. So the potential
// deadlock is eliminated.
worker_->StopSoon();
// Delay shutdown until the worker terminates. We want this code path
// to wait on the thread to quit before continuing.
if (worker_->IsRunning()) {
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&PrintJob::ControlledWorkerShutdown, this),
base::TimeDelta::FromMilliseconds(100));
return;
}
#endif
// Now make sure the thread object is cleaned up. Do this on a worker
// thread because it may block.
base::WorkerPool::PostTaskAndReply(
FROM_HERE,
base::Bind(&PrintJobWorker::Stop, base::Unretained(worker_.get())),
base::Bind(&PrintJob::HoldUntilStopIsCalled, this),
false);
is_job_pending_ = false;
registrar_.RemoveAll();
UpdatePrintedDocument(NULL);
}
void PrintJob::HoldUntilStopIsCalled() {
}
void PrintJob::Quit() {
base::MessageLoop::current()->Quit();
}
// Takes settings_ ownership and will be deleted in the receiving thread.
JobEventDetails::JobEventDetails(Type type,
PrintedDocument* document,
PrintedPage* page)
: document_(document),
page_(page),
type_(type) {
}
JobEventDetails::~JobEventDetails() {
}
PrintedDocument* JobEventDetails::document() const { return document_.get(); }
PrintedPage* JobEventDetails::page() const { return page_.get(); }
} // namespace printing

View File

@@ -0,0 +1,212 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PRINTING_PRINT_JOB_H_
#define CHROME_BROWSER_PRINTING_PRINT_JOB_H_
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "chrome/browser/printing/print_job_worker_owner.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
class Thread;
namespace printing {
// See definition below.
class JobEventDetails;
class PrintedDocument;
class PrintedPage;
class PrintedPagesSource;
class PrintJobWorker;
class PrinterQuery;
// Manages the print work for a specific document. Talks to the printer through
// PrintingContext through PrintJobWorker. Hides access to PrintingContext in a
// worker thread so the caller never blocks. PrintJob will send notifications on
// any state change. While printing, the PrintJobManager instance keeps a
// reference to the job to be sure it is kept alive. All the code in this class
// runs in the UI thread.
class PrintJob : public PrintJobWorkerOwner,
public content::NotificationObserver,
public base::MessageLoop::DestructionObserver {
public:
// Create a empty PrintJob. When initializing with this constructor,
// post-constructor initialization must be done with Initialize().
PrintJob();
// Grabs the ownership of the PrintJobWorker from another job, which is
// usually a PrinterQuery. Set the expected page count of the print job.
void Initialize(PrintJobWorkerOwner* job, PrintedPagesSource* source,
int page_count);
// content::NotificationObserver implementation.
virtual void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE;
// PrintJobWorkerOwner implementation.
virtual void GetSettingsDone(const PrintSettings& new_settings,
PrintingContext::Result result) OVERRIDE;
virtual PrintJobWorker* DetachWorker(PrintJobWorkerOwner* new_owner) OVERRIDE;
virtual base::MessageLoop* message_loop() OVERRIDE;
virtual const PrintSettings& settings() const OVERRIDE;
virtual int cookie() const OVERRIDE;
// DestructionObserver implementation.
virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
// Starts the actual printing. Signals the worker that it should begin to
// spool as soon as data is available.
void StartPrinting();
// Asks for the worker thread to finish its queued tasks and disconnects the
// delegate object. The PrintJobManager will remove its reference. This may
// have the side-effect of destroying the object if the caller doesn't have a
// handle to the object. Use PrintJob::is_stopped() to check whether the
// worker thread has actually stopped.
void Stop();
// Cancels printing job and stops the worker thread. Takes effect immediately.
void Cancel();
// Synchronously wait for the job to finish. It is mainly useful when the
// process is about to be shut down and we're waiting for the spooler to eat
// our data.
bool FlushJob(base::TimeDelta timeout);
// Disconnects the PrintedPage source (PrintedPagesSource). It is done when
// the source is being destroyed.
void DisconnectSource();
// Returns true if the print job is pending, i.e. between a StartPrinting()
// and the end of the spooling.
bool is_job_pending() const;
// Access the current printed document. Warning: may be NULL.
PrintedDocument* document() const;
protected:
virtual ~PrintJob();
private:
// Updates document_ to a new instance.
void UpdatePrintedDocument(PrintedDocument* new_document);
// Processes a NOTIFY_PRINT_JOB_EVENT notification.
void OnNotifyPrintJobEvent(const JobEventDetails& event_details);
// Releases the worker thread by calling Stop(), then broadcasts a JOB_DONE
// notification.
void OnDocumentDone();
// Terminates the worker thread in a very controlled way, to work around any
// eventual deadlock.
void ControlledWorkerShutdown();
// Called at shutdown when running a nested message loop.
void Quit();
void HoldUntilStopIsCalled();
content::NotificationRegistrar registrar_;
// Main message loop reference. Used to send notifications in the right
// thread.
base::MessageLoop* const ui_message_loop_;
// Source that generates the PrintedPage's (i.e. a WebContents). It will be
// set back to NULL if the source is deleted before this object.
PrintedPagesSource* source_;
// All the UI is done in a worker thread because many Win32 print functions
// are blocking and enters a message loop without your consent. There is one
// worker thread per print job.
scoped_ptr<PrintJobWorker> worker_;
// Cache of the print context settings for access in the UI thread.
PrintSettings settings_;
// The printed document.
scoped_refptr<PrintedDocument> document_;
// Is the worker thread printing.
bool is_job_pending_;
// Is Canceling? If so, try to not cause recursion if on FAILED notification,
// the notified calls Cancel() again.
bool is_canceling_;
// Used at shutdown so that we can quit a nested message loop.
base::WeakPtrFactory<PrintJob> quit_factory_;
DISALLOW_COPY_AND_ASSIGN(PrintJob);
};
// Details for a NOTIFY_PRINT_JOB_EVENT notification. The members may be NULL.
class JobEventDetails : public base::RefCountedThreadSafe<JobEventDetails> {
public:
// Event type.
enum Type {
// Print... dialog box has been closed with OK button.
USER_INIT_DONE,
// Print... dialog box has been closed with CANCEL button.
USER_INIT_CANCELED,
// An automated initialization has been done, e.g. Init(false, NULL).
DEFAULT_INIT_DONE,
// A new document started printing.
NEW_DOC,
// A new page started printing.
NEW_PAGE,
// A page is done printing.
PAGE_DONE,
// A document is done printing. The worker thread is still alive. Warning:
// not a good moment to release the handle to PrintJob.
DOC_DONE,
// The worker thread is finished. A good moment to release the handle to
// PrintJob.
JOB_DONE,
// All missing pages have been requested.
ALL_PAGES_REQUESTED,
// An error occured. Printing is canceled.
FAILED,
};
JobEventDetails(Type type, PrintedDocument* document, PrintedPage* page);
// Getters.
PrintedDocument* document() const;
PrintedPage* page() const;
Type type() const {
return type_;
}
private:
friend class base::RefCountedThreadSafe<JobEventDetails>;
~JobEventDetails();
scoped_refptr<PrintedDocument> document_;
scoped_refptr<PrintedPage> page_;
const Type type_;
DISALLOW_COPY_AND_ASSIGN(JobEventDetails);
};
} // namespace printing
#endif // CHROME_BROWSER_PRINTING_PRINT_JOB_H_

View File

@@ -0,0 +1,159 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/printing/print_job_manager.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/printing/print_job.h"
#include "chrome/browser/printing/printer_query.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
#include "printing/printed_document.h"
#include "printing/printed_page.h"
namespace printing {
PrintQueriesQueue::PrintQueriesQueue() {
}
PrintQueriesQueue::~PrintQueriesQueue() {
base::AutoLock lock(lock_);
queued_queries_.clear();
}
void PrintQueriesQueue::SetDestination(PrintDestinationInterface* destination) {
base::AutoLock lock(lock_);
destination_ = destination;
}
void PrintQueriesQueue::QueuePrinterQuery(PrinterQuery* job) {
base::AutoLock lock(lock_);
DCHECK(job);
queued_queries_.push_back(make_scoped_refptr(job));
DCHECK(job->is_valid());
}
scoped_refptr<PrinterQuery> PrintQueriesQueue::PopPrinterQuery(
int document_cookie) {
base::AutoLock lock(lock_);
for (PrinterQueries::iterator itr = queued_queries_.begin();
itr != queued_queries_.end(); ++itr) {
if ((*itr)->cookie() == document_cookie && !(*itr)->is_callback_pending()) {
scoped_refptr<printing::PrinterQuery> current_query(*itr);
queued_queries_.erase(itr);
DCHECK(current_query->is_valid());
return current_query;
}
}
return NULL;
}
scoped_refptr<PrinterQuery> PrintQueriesQueue::CreatePrinterQuery() {
scoped_refptr<PrinterQuery> job = new printing::PrinterQuery;
base::AutoLock lock(lock_);
job->SetWorkerDestination(destination_);
return job;
}
void PrintQueriesQueue::Shutdown() {
base::AutoLock lock(lock_);
queued_queries_.clear();
destination_ = NULL;
}
PrintJobManager::PrintJobManager() : is_shutdown_(false) {
registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT,
content::NotificationService::AllSources());
}
PrintJobManager::~PrintJobManager() {
}
scoped_refptr<PrintQueriesQueue> PrintJobManager::queue() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
if (!queue_)
queue_ = new PrintQueriesQueue();
return queue_;
}
void PrintJobManager::Shutdown() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
DCHECK(!is_shutdown_);
is_shutdown_ = true;
registrar_.RemoveAll();
StopJobs(true);
if (queue_)
queue_->Shutdown();
queue_ = NULL;
}
void PrintJobManager::StopJobs(bool wait_for_finish) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
// Copy the array since it can be modified in transit.
PrintJobs to_stop;
to_stop.swap(current_jobs_);
for (PrintJobs::const_iterator job = to_stop.begin(); job != to_stop.end();
++job) {
// Wait for two minutes for the print job to be spooled.
if (wait_for_finish)
(*job)->FlushJob(base::TimeDelta::FromMinutes(2));
(*job)->Stop();
}
}
void PrintJobManager::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
switch (type) {
case chrome::NOTIFICATION_PRINT_JOB_EVENT: {
OnPrintJobEvent(content::Source<PrintJob>(source).ptr(),
*content::Details<JobEventDetails>(details).ptr());
break;
}
default: {
NOTREACHED();
break;
}
}
}
void PrintJobManager::OnPrintJobEvent(
PrintJob* print_job,
const JobEventDetails& event_details) {
switch (event_details.type()) {
case JobEventDetails::NEW_DOC: {
DCHECK(current_jobs_.end() == current_jobs_.find(print_job));
// Causes a AddRef().
current_jobs_.insert(print_job);
break;
}
case JobEventDetails::JOB_DONE: {
DCHECK(current_jobs_.end() != current_jobs_.find(print_job));
current_jobs_.erase(print_job);
break;
}
case JobEventDetails::FAILED: {
current_jobs_.erase(print_job);
break;
}
case JobEventDetails::USER_INIT_DONE:
case JobEventDetails::USER_INIT_CANCELED:
case JobEventDetails::DEFAULT_INIT_DONE:
case JobEventDetails::NEW_PAGE:
case JobEventDetails::PAGE_DONE:
case JobEventDetails::DOC_DONE:
case JobEventDetails::ALL_PAGES_REQUESTED: {
// Don't care.
break;
}
default: {
NOTREACHED();
break;
}
}
}
} // namespace printing

View File

@@ -0,0 +1,104 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PRINTING_PRINT_JOB_MANAGER_H_
#define CHROME_BROWSER_PRINTING_PRINT_JOB_MANAGER_H_
#include <set>
#include <vector>
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"
#include "base/threading/non_thread_safe.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "printing/print_destination_interface.h"
namespace printing {
class JobEventDetails;
class PrintJob;
class PrinterQuery;
class PrintQueriesQueue : public base::RefCountedThreadSafe<PrintQueriesQueue> {
public:
PrintQueriesQueue();
// Sets the print destination to be set on the next print job.
void SetDestination(PrintDestinationInterface* destination);
// Queues a semi-initialized worker thread. Can be called from any thread.
// Current use case is queuing from the I/O thread.
// TODO(maruel): Have them vanish after a timeout (~5 minutes?)
void QueuePrinterQuery(PrinterQuery* job);
// Pops a queued PrintJobWorkerOwner object that was previously queued or
// create new one. Can be called from any thread.
scoped_refptr<PrinterQuery> PopPrinterQuery(int document_cookie);
// Creates new query.
scoped_refptr<PrinterQuery> CreatePrinterQuery();
void Shutdown();
private:
friend class base::RefCountedThreadSafe<PrintQueriesQueue>;
typedef std::vector<scoped_refptr<PrinterQuery> > PrinterQueries;
virtual ~PrintQueriesQueue();
// Used to serialize access to queued_workers_.
base::Lock lock_;
PrinterQueries queued_queries_;
scoped_refptr<PrintDestinationInterface> destination_;
DISALLOW_COPY_AND_ASSIGN(PrintQueriesQueue);
};
class PrintJobManager : public content::NotificationObserver {
public:
PrintJobManager();
virtual ~PrintJobManager();
// On browser quit, we should wait to have the print job finished.
void Shutdown();
// content::NotificationObserver
virtual void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE;
// Returns queries queue. Never returns NULL. Must be called on Browser UI
// Thread. Reference could be stored and used from any thread.
scoped_refptr<PrintQueriesQueue> queue();
private:
typedef std::set<scoped_refptr<PrintJob> > PrintJobs;
// Processes a NOTIFY_PRINT_JOB_EVENT notification.
void OnPrintJobEvent(PrintJob* print_job,
const JobEventDetails& event_details);
// Stops all printing jobs. If wait_for_finish is true, tries to give jobs
// a chance to complete before stopping them.
void StopJobs(bool wait_for_finish);
content::NotificationRegistrar registrar_;
// Current print jobs that are active.
PrintJobs current_jobs_;
scoped_refptr<PrintQueriesQueue> queue_;
bool is_shutdown_;
DISALLOW_COPY_AND_ASSIGN(PrintJobManager);
};
} // namespace printing
#endif // CHROME_BROWSER_PRINTING_PRINT_JOB_MANAGER_H_

View File

@@ -0,0 +1,365 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/printing/print_job_worker.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/message_loop/message_loop.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/printing/print_job.h"
#include "chrome/browser/printing/printing_ui_web_contents_observer.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
#include "grit/generated_resources.h"
#include "printing/print_job_constants.h"
#include "printing/printed_document.h"
#include "printing/printed_page.h"
#include "printing/printing_utils.h"
#include "ui/base/l10n/l10n_util.h"
using content::BrowserThread;
namespace {
// Helper function to ensure |owner| is valid until at least |callback| returns.
void HoldRefCallback(const scoped_refptr<printing::PrintJobWorkerOwner>& owner,
const base::Closure& callback) {
callback.Run();
}
} // namespace
namespace printing {
void NotificationCallback(PrintJobWorkerOwner* print_job,
JobEventDetails::Type detail_type,
PrintedDocument* document,
PrintedPage* page) {
JobEventDetails* details = new JobEventDetails(detail_type, document, page);
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_PRINT_JOB_EVENT,
// We know that is is a PrintJob object in this circumstance.
content::Source<PrintJob>(static_cast<PrintJob*>(print_job)),
content::Details<JobEventDetails>(details));
}
PrintJobWorker::PrintJobWorker(PrintJobWorkerOwner* owner)
: Thread("Printing_Worker"),
owner_(owner),
weak_factory_(this) {
// The object is created in the IO thread.
DCHECK_EQ(owner_->message_loop(), base::MessageLoop::current());
printing_context_.reset(PrintingContext::Create(
g_browser_process->GetApplicationLocale()));
}
PrintJobWorker::~PrintJobWorker() {
// The object is normally deleted in the UI thread, but when the user
// cancels printing or in the case of print preview, the worker is destroyed
// on the I/O thread.
DCHECK_EQ(owner_->message_loop(), base::MessageLoop::current());
Stop();
}
void PrintJobWorker::SetNewOwner(PrintJobWorkerOwner* new_owner) {
DCHECK(page_number_ == PageNumber::npos());
owner_ = new_owner;
}
void PrintJobWorker::SetPrintDestination(
PrintDestinationInterface* destination) {
destination_ = destination;
}
void PrintJobWorker::GetSettings(
bool ask_user_for_settings,
scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,
int document_page_count,
bool has_selection,
MarginType margin_type) {
DCHECK_EQ(message_loop(), base::MessageLoop::current());
DCHECK_EQ(page_number_, PageNumber::npos());
// Recursive task processing is needed for the dialog in case it needs to be
// destroyed by a task.
// TODO(thestig): This code is wrong. SetNestableTasksAllowed(true) is needed
// on the thread where the PrintDlgEx is called, and definitely both calls
// should happen on the same thread. See http://crbug.com/73466
// MessageLoop::current()->SetNestableTasksAllowed(true);
printing_context_->set_margin_type(margin_type);
// When we delegate to a destination, we don't ask the user for settings.
// TODO(mad): Ask the destination for settings.
if (ask_user_for_settings && destination_.get() == NULL) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&HoldRefCallback, make_scoped_refptr(owner_),
base::Bind(&PrintJobWorker::GetSettingsWithUI,
base::Unretained(this),
base::Passed(&web_contents_observer),
document_page_count,
has_selection)));
} else {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&HoldRefCallback, make_scoped_refptr(owner_),
base::Bind(&PrintJobWorker::UseDefaultSettings,
base::Unretained(this))));
}
}
void PrintJobWorker::SetSettings(
const base::DictionaryValue* const new_settings) {
DCHECK_EQ(message_loop(), base::MessageLoop::current());
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
base::Bind(&HoldRefCallback,
make_scoped_refptr(owner_),
base::Bind(&PrintJobWorker::UpdatePrintSettings,
base::Unretained(this),
base::Owned(new_settings))));
}
void PrintJobWorker::UpdatePrintSettings(
const base::DictionaryValue* const new_settings) {
PrintingContext::Result result =
printing_context_->UpdatePrintSettings(*new_settings);
GetSettingsDone(result);
}
void PrintJobWorker::GetSettingsDone(PrintingContext::Result result) {
// Most PrintingContext functions may start a message loop and process
// message recursively, so disable recursive task processing.
// TODO(thestig): See above comment. SetNestableTasksAllowed(false) needs to
// be called on the same thread as the previous call. See
// http://crbug.com/73466
// MessageLoop::current()->SetNestableTasksAllowed(false);
// We can't use OnFailure() here since owner_ may not support notifications.
// PrintJob will create the new PrintedDocument.
owner_->message_loop()->PostTask(
FROM_HERE,
base::Bind(&PrintJobWorkerOwner::GetSettingsDone,
make_scoped_refptr(owner_), printing_context_->settings(),
result));
}
void PrintJobWorker::GetSettingsWithUI(
scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,
int document_page_count,
bool has_selection) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
gfx::NativeView parent_view = web_contents_observer->GetParentView();
if (!parent_view) {
GetSettingsWithUIDone(printing::PrintingContext::FAILED);
return;
}
printing_context_->AskUserForSettings(
parent_view, document_page_count, has_selection,
base::Bind(&PrintJobWorker::GetSettingsWithUIDone,
base::Unretained(this)));
}
void PrintJobWorker::GetSettingsWithUIDone(PrintingContext::Result result) {
message_loop()->PostTask(
FROM_HERE,
base::Bind(&HoldRefCallback, make_scoped_refptr(owner_),
base::Bind(&PrintJobWorker::GetSettingsDone,
base::Unretained(this), result)));
}
void PrintJobWorker::UseDefaultSettings() {
PrintingContext::Result result = printing_context_->UseDefaultSettings();
GetSettingsDone(result);
}
void PrintJobWorker::StartPrinting(PrintedDocument* new_document) {
DCHECK_EQ(message_loop(), base::MessageLoop::current());
DCHECK_EQ(page_number_, PageNumber::npos());
DCHECK_EQ(document_, new_document);
DCHECK(document_.get());
if (!document_.get() || page_number_ != PageNumber::npos() ||
document_.get() != new_document) {
return;
}
base::string16 document_name =
printing::SimplifyDocumentTitle(document_->name());
if (document_name.empty()) {
}
PrintingContext::Result result =
printing_context_->NewDocument(document_name);
if (result != PrintingContext::OK) {
OnFailure();
return;
}
// Try to print already cached data. It may already have been generated for
// the print preview.
OnNewPage();
// Don't touch this anymore since the instance could be destroyed. It happens
// if all the pages are printed a one sweep and the client doesn't have a
// handle to us anymore. There's a timing issue involved between the worker
// thread and the UI thread. Take no chance.
}
void PrintJobWorker::OnDocumentChanged(PrintedDocument* new_document) {
DCHECK_EQ(message_loop(), base::MessageLoop::current());
DCHECK_EQ(page_number_, PageNumber::npos());
if (page_number_ != PageNumber::npos())
return;
document_ = new_document;
}
void PrintJobWorker::OnNewPage() {
if (!document_.get()) // Spurious message.
return;
// message_loop() could return NULL when the print job is cancelled.
DCHECK_EQ(message_loop(), base::MessageLoop::current());
if (page_number_ == PageNumber::npos()) {
// Find first page to print.
int page_count = document_->page_count();
if (!page_count) {
// We still don't know how many pages the document contains. We can't
// start to print the document yet since the header/footer may refer to
// the document's page count.
return;
}
// We have enough information to initialize page_number_.
page_number_.Init(document_->settings(), page_count);
if (destination_.get() != NULL)
destination_->SetPageCount(page_count);
}
DCHECK_NE(page_number_, PageNumber::npos());
while (true) {
// Is the page available?
scoped_refptr<PrintedPage> page = document_->GetPage(page_number_.ToInt());
if (!page) {
// We need to wait for the page to be available.
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&PrintJobWorker::OnNewPage, weak_factory_.GetWeakPtr()),
base::TimeDelta::FromMilliseconds(500));
break;
}
// The page is there, print it.
SpoolPage(page.get());
++page_number_;
if (page_number_ == PageNumber::npos()) {
OnDocumentDone();
// Don't touch this anymore since the instance could be destroyed.
break;
}
}
}
void PrintJobWorker::Cancel() {
// This is the only function that can be called from any thread.
printing_context_->Cancel();
// Cannot touch any member variable since we don't know in which thread
// context we run.
}
void PrintJobWorker::OnDocumentDone() {
DCHECK_EQ(message_loop(), base::MessageLoop::current());
DCHECK_EQ(page_number_, PageNumber::npos());
DCHECK(document_.get());
if (printing_context_->DocumentDone() != PrintingContext::OK) {
OnFailure();
return;
}
owner_->message_loop()->PostTask(
FROM_HERE, base::Bind(NotificationCallback, make_scoped_refptr(owner_),
JobEventDetails::DOC_DONE, document_,
scoped_refptr<PrintedPage>()));
// Makes sure the variables are reinitialized.
document_ = NULL;
}
void PrintJobWorker::SpoolPage(PrintedPage* page) {
DCHECK_EQ(message_loop(), base::MessageLoop::current());
DCHECK_NE(page_number_, PageNumber::npos());
// Signal everyone that the page is about to be printed.
owner_->message_loop()->PostTask(
FROM_HERE, base::Bind(NotificationCallback, make_scoped_refptr(owner_),
JobEventDetails::NEW_PAGE, document_,
make_scoped_refptr(page)));
// Preprocess.
if (printing_context_->NewPage() != PrintingContext::OK) {
OnFailure();
return;
}
if (destination_.get() != NULL) {
std::vector<uint8> metabytes(page->metafile()->GetDataSize());
bool success = page->metafile()->GetData(
reinterpret_cast<void*>(&metabytes[0]), metabytes.size());
DCHECK(success) << "Failed to get metafile data.";
destination_->SetPageContent(
page->page_number(),
reinterpret_cast<void*>(&metabytes[0]),
metabytes.size());
return;
}
// Actual printing.
#if defined(OS_WIN) || defined(OS_MACOSX)
document_->RenderPrintedPage(*page, printing_context_->context());
#elif defined(OS_POSIX)
document_->RenderPrintedPage(*page, printing_context_.get());
#endif
// Postprocess.
if (printing_context_->PageDone() != PrintingContext::OK) {
OnFailure();
return;
}
// Signal everyone that the page is printed.
owner_->message_loop()->PostTask(
FROM_HERE,
base::Bind(NotificationCallback, make_scoped_refptr(owner_),
JobEventDetails::PAGE_DONE, document_,
make_scoped_refptr(page)));
}
void PrintJobWorker::OnFailure() {
DCHECK_EQ(message_loop(), base::MessageLoop::current());
// We may loose our last reference by broadcasting the FAILED event.
scoped_refptr<PrintJobWorkerOwner> handle(owner_);
owner_->message_loop()->PostTask(
FROM_HERE, base::Bind(NotificationCallback, make_scoped_refptr(owner_),
JobEventDetails::FAILED, document_,
scoped_refptr<PrintedPage>()));
Cancel();
// Makes sure the variables are reinitialized.
document_ = NULL;
page_number_ = PageNumber::npos();
}
} // namespace printing

View File

@@ -0,0 +1,145 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_H_
#define CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_H_
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread.h"
#include "printing/page_number.h"
#include "printing/print_destination_interface.h"
#include "printing/printing_context.h"
#include "printing/print_job_constants.h"
class PrintingUIWebContentsObserver;
namespace base {
class DictionaryValue;
}
namespace printing {
class PrintedDocument;
class PrintedPage;
class PrintJob;
class PrintJobWorkerOwner;
// Worker thread code. It manages the PrintingContext, which can be blocking
// and/or run a message loop. This is the object that generates most
// NOTIFY_PRINT_JOB_EVENT notifications, but they are generated through a
// NotificationTask task to be executed from the right thread, the UI thread.
// PrintJob always outlives its worker instance.
class PrintJobWorker : public base::Thread {
public:
explicit PrintJobWorker(PrintJobWorkerOwner* owner);
virtual ~PrintJobWorker();
void SetNewOwner(PrintJobWorkerOwner* new_owner);
// Set a destination for print.
// This supercedes the document's rendering destination.
void SetPrintDestination(PrintDestinationInterface* destination);
// Initializes the print settings. If |ask_user_for_settings| is true, a
// Print... dialog box will be shown to ask the user his preference.
void GetSettings(
bool ask_user_for_settings,
scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,
int document_page_count,
bool has_selection,
MarginType margin_type);
// Set the new print settings. This function takes ownership of
// |new_settings|.
void SetSettings(const base::DictionaryValue* const new_settings);
// Starts the printing loop. Every pages are printed as soon as the data is
// available. Makes sure the new_document is the right one.
void StartPrinting(PrintedDocument* new_document);
// Updates the printed document.
void OnDocumentChanged(PrintedDocument* new_document);
// Dequeues waiting pages. Called when PrintJob receives a
// NOTIFY_PRINTED_DOCUMENT_UPDATED notification. It's time to look again if
// the next page can be printed.
void OnNewPage();
// This is the only function that can be called in a thread.
void Cancel();
protected:
// Retrieves the context for testing only.
PrintingContext* printing_context() { return printing_context_.get(); }
private:
// The shared NotificationService service can only be accessed from the UI
// thread, so this class encloses the necessary information to send the
// notification from the right thread. Most NOTIFY_PRINT_JOB_EVENT
// notifications are sent this way, except USER_INIT_DONE, USER_INIT_CANCELED
// and DEFAULT_INIT_DONE. These three are sent through PrintJob::InitDone().
class NotificationTask;
// Renders a page in the printer.
void SpoolPage(PrintedPage* page);
// Closes the job since spooling is done.
void OnDocumentDone();
// Discards the current document, the current page and cancels the printing
// context.
void OnFailure();
// Asks the user for print settings. Must be called on the UI thread.
// Required on Mac and Linux. Windows can display UI from non-main threads,
// but sticks with this for consistency.
void GetSettingsWithUI(
scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,
int document_page_count,
bool has_selection);
// The callback used by PrintingContext::GetSettingsWithUI() to notify this
// object that the print settings are set. This is needed in order to bounce
// back into the IO thread for GetSettingsDone().
void GetSettingsWithUIDone(PrintingContext::Result result);
// Called on the UI thread to update the print settings. This function takes
// the ownership of |new_settings|.
void UpdatePrintSettings(const base::DictionaryValue* const new_settings);
// Reports settings back to owner_.
void GetSettingsDone(PrintingContext::Result result);
// Use the default settings. When using GTK+ or Mac, this can still end up
// displaying a dialog. So this needs to happen from the UI thread on these
// systems.
void UseDefaultSettings();
// Information about the printer setting.
scoped_ptr<PrintingContext> printing_context_;
// The printed document. Only has read-only access.
scoped_refptr<PrintedDocument> document_;
// The print destination, may be NULL.
scoped_refptr<PrintDestinationInterface> destination_;
// The print job owning this worker thread. It is guaranteed to outlive this
// object.
PrintJobWorkerOwner* owner_;
// Current page number to print.
PageNumber page_number_;
// Used to generate a WeakPtr for callbacks.
base::WeakPtrFactory<PrintJobWorker> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(PrintJobWorker);
};
} // namespace printing
#endif // CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_H_

View File

@@ -0,0 +1,50 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_OWNER_H__
#define CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_OWNER_H__
#include "base/memory/ref_counted.h"
#include "printing/printing_context.h"
namespace base {
class MessageLoop;
}
namespace printing {
class PrintJobWorker;
class PrintSettings;
class PrintJobWorkerOwner
: public base::RefCountedThreadSafe<PrintJobWorkerOwner> {
public:
// Finishes the initialization began by PrintJobWorker::GetSettings().
// Creates a new PrintedDocument if necessary. Solely meant to be called by
// PrintJobWorker.
virtual void GetSettingsDone(const PrintSettings& new_settings,
PrintingContext::Result result) = 0;
// Detach the PrintJobWorker associated to this object.
virtual PrintJobWorker* DetachWorker(PrintJobWorkerOwner* new_owner) = 0;
// Retrieves the message loop that is expected to process GetSettingsDone.
virtual base::MessageLoop* message_loop() = 0;
// Access the current settings.
virtual const PrintSettings& settings() const = 0;
// Cookie uniquely identifying the PrintedDocument and/or loaded settings.
virtual int cookie() const = 0;
protected:
friend class base::RefCountedThreadSafe<PrintJobWorkerOwner>;
virtual ~PrintJobWorkerOwner() {}
};
} // namespace printing
#endif // CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_OWNER_H__

View File

@@ -0,0 +1,533 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/printing/print_view_manager_base.h"
#include "base/bind.h"
#include "base/memory/scoped_ptr.h"
#include "base/prefs/pref_service.h"
#include "base/strings/utf_string_conversions.h"
#include "base/timer/timer.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/printing/print_job.h"
#include "chrome/browser/printing/print_job_manager.h"
#include "chrome/browser/printing/printer_query.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/simple_message_box.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/print_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "grit/generated_resources.h"
#include "printing/metafile_impl.h"
#include "printing/printed_document.h"
#include "ui/base/l10n/l10n_util.h"
using base::TimeDelta;
using content::BrowserThread;
namespace printing {
namespace {
#if defined(OS_WIN) && !defined(WIN_PDF_METAFILE_FOR_PRINTING)
// Limits memory usage by raster to 64 MiB.
const int kMaxRasterSizeInPixels = 16*1024*1024;
#endif
} // namespace
PrintViewManagerBase::PrintViewManagerBase(content::WebContents* web_contents)
: content::WebContentsObserver(web_contents),
number_pages_(0),
printing_succeeded_(false),
inside_inner_message_loop_(false),
cookie_(0),
queue_(g_browser_process->print_job_manager()->queue()) {
DCHECK(queue_);
#if (defined(OS_POSIX) && !defined(OS_MACOSX)) || \
defined(WIN_PDF_METAFILE_FOR_PRINTING)
expecting_first_page_ = true;
#endif
printing_enabled_ = true;
}
PrintViewManagerBase::~PrintViewManagerBase() {
ReleasePrinterQuery();
DisconnectFromCurrentPrintJob();
}
bool PrintViewManagerBase::PrintNow(bool silent, bool print_background) {
return PrintNowInternal(new PrintMsg_PrintPages(
routing_id(), silent, print_background));
}
void PrintViewManagerBase::NavigationStopped() {
// Cancel the current job, wait for the worker to finish.
TerminatePrintJob(true);
}
void PrintViewManagerBase::RenderProcessGone(base::TerminationStatus status) {
ReleasePrinterQuery();
if (!print_job_.get())
return;
scoped_refptr<PrintedDocument> document(print_job_->document());
if (document.get()) {
// If IsComplete() returns false, the document isn't completely rendered.
// Since our renderer is gone, there's nothing to do, cancel it. Otherwise,
// the print job may finish without problem.
TerminatePrintJob(!document->IsComplete());
}
}
base::string16 PrintViewManagerBase::RenderSourceName() {
base::string16 name(web_contents()->GetTitle());
return name;
}
void PrintViewManagerBase::OnDidGetPrintedPagesCount(int cookie,
int number_pages) {
DCHECK_GT(cookie, 0);
DCHECK_GT(number_pages, 0);
number_pages_ = number_pages;
OpportunisticallyCreatePrintJob(cookie);
}
void PrintViewManagerBase::OnDidGetDocumentCookie(int cookie) {
cookie_ = cookie;
}
void PrintViewManagerBase::OnDidPrintPage(
const PrintHostMsg_DidPrintPage_Params& params) {
if (!OpportunisticallyCreatePrintJob(params.document_cookie))
return;
PrintedDocument* document = print_job_->document();
if (!document || params.document_cookie != document->cookie()) {
// Out of sync. It may happen since we are completely asynchronous. Old
// spurious messages can be received if one of the processes is overloaded.
return;
}
#if (defined(OS_WIN) && !defined(WIN_PDF_METAFILE_FOR_PRINTING)) || \
defined(OS_MACOSX)
const bool metafile_must_be_valid = true;
#elif defined(OS_POSIX) || defined(WIN_PDF_METAFILE_FOR_PRINTING)
const bool metafile_must_be_valid = expecting_first_page_;
expecting_first_page_ = false;
#endif
base::SharedMemory shared_buf(params.metafile_data_handle, true);
if (metafile_must_be_valid) {
if (!shared_buf.Map(params.data_size)) {
NOTREACHED() << "couldn't map";
web_contents()->Stop();
return;
}
}
scoped_ptr<NativeMetafile> metafile(new NativeMetafile);
if (metafile_must_be_valid) {
if (!metafile->InitFromData(shared_buf.memory(), params.data_size)) {
NOTREACHED() << "Invalid metafile header";
web_contents()->Stop();
return;
}
}
#if defined(OS_WIN) && !defined(WIN_PDF_METAFILE_FOR_PRINTING)
bool big_emf = (params.data_size && params.data_size >= kMetafileMaxSize);
int raster_size =
std::min(params.page_size.GetArea(), kMaxRasterSizeInPixels);
if (big_emf) {
scoped_ptr<NativeMetafile> raster_metafile(
metafile->RasterizeMetafile(raster_size));
if (raster_metafile.get()) {
metafile.swap(raster_metafile);
} else if (big_emf) {
// Don't fall back to emf here.
NOTREACHED() << "size:" << params.data_size;
TerminatePrintJob(true);
web_contents()->Stop();
return;
}
}
#endif // OS_WIN && !WIN_PDF_METAFILE_FOR_PRINTING
#if !defined(WIN_PDF_METAFILE_FOR_PRINTING)
// Update the rendered document. It will send notifications to the listener.
document->SetPage(params.page_number,
metafile.release(),
#if defined(OS_WIN)
params.actual_shrink,
#endif // OS_WIN
params.page_size,
params.content_area);
ShouldQuitFromInnerMessageLoop();
#else
if (metafile_must_be_valid) {
scoped_refptr<base::RefCountedBytes> bytes = new base::RefCountedBytes(
reinterpret_cast<const unsigned char*>(shared_buf.memory()),
params.data_size);
document->DebugDumpData(bytes, FILE_PATH_LITERAL(".pdf"));
if (!pdf_to_emf_converter_)
pdf_to_emf_converter_ = PdfToEmfConverter::CreateDefault();
const int kPrinterDpi = print_job_->settings().dpi();
pdf_to_emf_converter_->Start(
bytes,
printing::PdfRenderSettings(params.content_area, kPrinterDpi, true),
base::Bind(&PrintViewManagerBase::OnPdfToEmfConverted,
base::Unretained(this),
params));
}
#endif // !WIN_PDF_METAFILE_FOR_PRINTING
}
void PrintViewManagerBase::OnPrintingFailed(int cookie) {
if (cookie != cookie_) {
NOTREACHED();
return;
}
ReleasePrinterQuery();
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_PRINT_JOB_RELEASED,
content::Source<content::WebContents>(web_contents()),
content::NotificationService::NoDetails());
}
void PrintViewManagerBase::OnShowInvalidPrinterSettingsError() {
LOG(ERROR) << "Invalid printer settings";
}
bool PrintViewManagerBase::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(PrintViewManagerBase, message)
IPC_MESSAGE_HANDLER(PrintHostMsg_DidGetPrintedPagesCount,
OnDidGetPrintedPagesCount)
IPC_MESSAGE_HANDLER(PrintHostMsg_DidGetDocumentCookie,
OnDidGetDocumentCookie)
IPC_MESSAGE_HANDLER(PrintHostMsg_DidPrintPage, OnDidPrintPage)
IPC_MESSAGE_HANDLER(PrintHostMsg_PrintingFailed, OnPrintingFailed)
IPC_MESSAGE_HANDLER(PrintHostMsg_ShowInvalidPrinterSettingsError,
OnShowInvalidPrinterSettingsError);
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void PrintViewManagerBase::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
switch (type) {
case chrome::NOTIFICATION_PRINT_JOB_EVENT: {
OnNotifyPrintJobEvent(*content::Details<JobEventDetails>(details).ptr());
break;
}
default: {
NOTREACHED();
break;
}
}
}
void PrintViewManagerBase::OnNotifyPrintJobEvent(
const JobEventDetails& event_details) {
switch (event_details.type()) {
case JobEventDetails::FAILED: {
TerminatePrintJob(true);
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_PRINT_JOB_RELEASED,
content::Source<content::WebContents>(web_contents()),
content::NotificationService::NoDetails());
break;
}
case JobEventDetails::USER_INIT_DONE:
case JobEventDetails::DEFAULT_INIT_DONE:
case JobEventDetails::USER_INIT_CANCELED: {
NOTREACHED();
break;
}
case JobEventDetails::ALL_PAGES_REQUESTED: {
ShouldQuitFromInnerMessageLoop();
break;
}
case JobEventDetails::NEW_DOC:
case JobEventDetails::NEW_PAGE:
case JobEventDetails::PAGE_DONE:
case JobEventDetails::DOC_DONE: {
// Don't care about the actual printing process.
break;
}
case JobEventDetails::JOB_DONE: {
// Printing is done, we don't need it anymore.
// print_job_->is_job_pending() may still be true, depending on the order
// of object registration.
printing_succeeded_ = true;
ReleasePrintJob();
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_PRINT_JOB_RELEASED,
content::Source<content::WebContents>(web_contents()),
content::NotificationService::NoDetails());
break;
}
default: {
NOTREACHED();
break;
}
}
}
bool PrintViewManagerBase::RenderAllMissingPagesNow() {
if (!print_job_.get() || !print_job_->is_job_pending())
return false;
// We can't print if there is no renderer.
if (!web_contents() ||
!web_contents()->GetRenderViewHost() ||
!web_contents()->GetRenderViewHost()->IsRenderViewLive()) {
return false;
}
// Is the document already complete?
if (print_job_->document() && print_job_->document()->IsComplete()) {
printing_succeeded_ = true;
return true;
}
// WebContents is either dying or a second consecutive request to print
// happened before the first had time to finish. We need to render all the
// pages in an hurry if a print_job_ is still pending. No need to wait for it
// to actually spool the pages, only to have the renderer generate them. Run
// a message loop until we get our signal that the print job is satisfied.
// PrintJob will send a ALL_PAGES_REQUESTED after having received all the
// pages it needs. MessageLoop::current()->Quit() will be called as soon as
// print_job_->document()->IsComplete() is true on either ALL_PAGES_REQUESTED
// or in DidPrintPage(). The check is done in
// ShouldQuitFromInnerMessageLoop().
// BLOCKS until all the pages are received. (Need to enable recursive task)
if (!RunInnerMessageLoop()) {
// This function is always called from DisconnectFromCurrentPrintJob() so we
// know that the job will be stopped/canceled in any case.
return false;
}
return true;
}
void PrintViewManagerBase::ShouldQuitFromInnerMessageLoop() {
// Look at the reason.
DCHECK(print_job_->document());
if (print_job_->document() &&
print_job_->document()->IsComplete() &&
inside_inner_message_loop_) {
// We are in a message loop created by RenderAllMissingPagesNow. Quit from
// it.
base::MessageLoop::current()->Quit();
inside_inner_message_loop_ = false;
}
}
bool PrintViewManagerBase::CreateNewPrintJob(PrintJobWorkerOwner* job) {
DCHECK(!inside_inner_message_loop_);
// Disconnect the current print_job_.
DisconnectFromCurrentPrintJob();
// We can't print if there is no renderer.
if (!web_contents()->GetRenderViewHost() ||
!web_contents()->GetRenderViewHost()->IsRenderViewLive()) {
return false;
}
// Ask the renderer to generate the print preview, create the print preview
// view and switch to it, initialize the printer and show the print dialog.
DCHECK(!print_job_.get());
DCHECK(job);
if (!job)
return false;
print_job_ = new PrintJob();
print_job_->Initialize(job, this, number_pages_);
registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT,
content::Source<PrintJob>(print_job_.get()));
printing_succeeded_ = false;
return true;
}
void PrintViewManagerBase::DisconnectFromCurrentPrintJob() {
// Make sure all the necessary rendered page are done. Don't bother with the
// return value.
bool result = RenderAllMissingPagesNow();
// Verify that assertion.
if (print_job_.get() &&
print_job_->document() &&
!print_job_->document()->IsComplete()) {
DCHECK(!result);
// That failed.
TerminatePrintJob(true);
} else {
// DO NOT wait for the job to finish.
ReleasePrintJob();
}
#if (defined(OS_POSIX) && !defined(OS_MACOSX)) || \
defined(WIN_PDF_METAFILE_FOR_PRINTING)
expecting_first_page_ = true;
#endif
}
void PrintViewManagerBase::PrintingDone(bool success) {
if (!print_job_.get())
return;
Send(new PrintMsg_PrintingDone(routing_id(), success));
}
void PrintViewManagerBase::TerminatePrintJob(bool cancel) {
if (!print_job_.get())
return;
if (cancel) {
// We don't need the metafile data anymore because the printing is canceled.
print_job_->Cancel();
inside_inner_message_loop_ = false;
} else {
DCHECK(!inside_inner_message_loop_);
DCHECK(!print_job_->document() || print_job_->document()->IsComplete());
// WebContents is either dying or navigating elsewhere. We need to render
// all the pages in an hurry if a print job is still pending. This does the
// trick since it runs a blocking message loop:
print_job_->Stop();
}
ReleasePrintJob();
}
void PrintViewManagerBase::ReleasePrintJob() {
if (!print_job_.get())
return;
PrintingDone(printing_succeeded_);
registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_EVENT,
content::Source<PrintJob>(print_job_.get()));
print_job_->DisconnectSource();
// Don't close the worker thread.
print_job_ = NULL;
}
bool PrintViewManagerBase::RunInnerMessageLoop() {
// This value may actually be too low:
//
// - If we're looping because of printer settings initialization, the premise
// here is that some poor users have their print server away on a VPN over a
// slow connection. In this situation, the simple fact of opening the printer
// can be dead slow. On the other side, we don't want to die infinitely for a
// real network error. Give the printer 60 seconds to comply.
//
// - If we're looping because of renderer page generation, the renderer could
// be CPU bound, the page overly complex/large or the system just
// memory-bound.
static const int kPrinterSettingsTimeout = 60000;
base::OneShotTimer<base::MessageLoop> quit_timer;
quit_timer.Start(FROM_HERE,
TimeDelta::FromMilliseconds(kPrinterSettingsTimeout),
base::MessageLoop::current(), &base::MessageLoop::Quit);
inside_inner_message_loop_ = true;
// Need to enable recursive task.
{
base::MessageLoop::ScopedNestableTaskAllower allow(
base::MessageLoop::current());
base::MessageLoop::current()->Run();
}
bool success = true;
if (inside_inner_message_loop_) {
// Ok we timed out. That's sad.
inside_inner_message_loop_ = false;
success = false;
}
return success;
}
bool PrintViewManagerBase::OpportunisticallyCreatePrintJob(int cookie) {
if (print_job_.get())
return true;
if (!cookie) {
// Out of sync. It may happens since we are completely asynchronous. Old
// spurious message can happen if one of the processes is overloaded.
return false;
}
// The job was initiated by a script. Time to get the corresponding worker
// thread.
scoped_refptr<PrinterQuery> queued_query = queue_->PopPrinterQuery(cookie);
if (!queued_query) {
NOTREACHED();
return false;
}
if (!CreateNewPrintJob(queued_query)) {
// Don't kill anything.
return false;
}
// Settings are already loaded. Go ahead. This will set
// print_job_->is_job_pending() to true.
print_job_->StartPrinting();
return true;
}
bool PrintViewManagerBase::PrintNowInternal(IPC::Message* message) {
// Don't print / print preview interstitials.
if (web_contents()->ShowingInterstitialPage()) {
delete message;
return false;
}
return Send(message);
}
void PrintViewManagerBase::ReleasePrinterQuery() {
if (!cookie_)
return;
int cookie = cookie_;
cookie_ = 0;
queue_->SetDestination(NULL);
printing::PrintJobManager* print_job_manager =
g_browser_process->print_job_manager();
// May be NULL in tests.
if (!print_job_manager)
return;
scoped_refptr<printing::PrinterQuery> printer_query;
printer_query = queue_->PopPrinterQuery(cookie);
if (!printer_query)
return;
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&PrinterQuery::StopWorker, printer_query.get()));
}
} // namespace printing

View File

@@ -0,0 +1,162 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_BASE_H_
#define CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_BASE_H_
#include "base/memory/ref_counted.h"
#include "base/prefs/pref_member.h"
#include "base/strings/string16.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
#include "printing/printed_pages_source.h"
struct PrintHostMsg_DidPrintPage_Params;
namespace content {
class RenderViewHost;
}
namespace printing {
class JobEventDetails;
class PdfToEmfConverter;
class PrintJob;
class PrintJobWorkerOwner;
class PrintQueriesQueue;
// Base class for managing the print commands for a WebContents.
class PrintViewManagerBase : public content::NotificationObserver,
public PrintedPagesSource,
public content::WebContentsObserver {
public:
virtual ~PrintViewManagerBase();
// Prints the current document immediately. Since the rendering is
// asynchronous, the actual printing will not be completed on the return of
// this function. Returns false if printing is impossible at the moment.
virtual bool PrintNow(bool silent, bool print_background);
// PrintedPagesSource implementation.
virtual base::string16 RenderSourceName() OVERRIDE;
protected:
explicit PrintViewManagerBase(content::WebContents* web_contents);
// Helper method for Print*Now().
bool PrintNowInternal(IPC::Message* message);
// Terminates or cancels the print job if one was pending.
virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE;
// content::WebContentsObserver implementation.
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
// IPC Message handlers.
virtual void OnPrintingFailed(int cookie);
private:
// content::NotificationObserver implementation.
virtual void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE;
// Cancels the print job.
virtual void NavigationStopped() OVERRIDE;
// IPC Message handlers.
void OnDidGetPrintedPagesCount(int cookie, int number_pages);
void OnDidGetDocumentCookie(int cookie);
void OnDidPrintPage(const PrintHostMsg_DidPrintPage_Params& params);
void OnShowInvalidPrinterSettingsError();
// Processes a NOTIFY_PRINT_JOB_EVENT notification.
void OnNotifyPrintJobEvent(const JobEventDetails& event_details);
// Requests the RenderView to render all the missing pages for the print job.
// No-op if no print job is pending. Returns true if at least one page has
// been requested to the renderer.
bool RenderAllMissingPagesNow();
// Quits the current message loop if these conditions hold true: a document is
// loaded and is complete and waiting_for_pages_to_be_rendered_ is true. This
// function is called in DidPrintPage() or on ALL_PAGES_REQUESTED
// notification. The inner message loop is created was created by
// RenderAllMissingPagesNow().
void ShouldQuitFromInnerMessageLoop();
// Creates a new empty print job. It has no settings loaded. If there is
// currently a print job, safely disconnect from it. Returns false if it is
// impossible to safely disconnect from the current print job or it is
// impossible to create a new print job.
bool CreateNewPrintJob(PrintJobWorkerOwner* job);
// Makes sure the current print_job_ has all its data before continuing, and
// disconnect from it.
void DisconnectFromCurrentPrintJob();
// Notify that the printing is done.
void PrintingDone(bool success);
// Terminates the print job. No-op if no print job has been created. If
// |cancel| is true, cancel it instead of waiting for the job to finish. Will
// call ReleasePrintJob().
void TerminatePrintJob(bool cancel);
// Releases print_job_. Correctly deregisters from notifications. No-op if
// no print job has been created.
void ReleasePrintJob();
// Runs an inner message loop. It will set inside_inner_message_loop_ to true
// while the blocking inner message loop is running. This is useful in cases
// where the RenderView is about to be destroyed while a printing job isn't
// finished.
bool RunInnerMessageLoop();
// In the case of Scripted Printing, where the renderer is controlling the
// control flow, print_job_ is initialized whenever possible. No-op is
// print_job_ is initialized.
bool OpportunisticallyCreatePrintJob(int cookie);
// Release the PrinterQuery associated with our |cookie_|.
void ReleasePrinterQuery();
content::NotificationRegistrar registrar_;
// Manages the low-level talk to the printer.
scoped_refptr<PrintJob> print_job_;
// Number of pages to print in the print job.
int number_pages_;
// Indication of success of the print job.
bool printing_succeeded_;
// Running an inner message loop inside RenderAllMissingPagesNow(). This means
// we are _blocking_ until all the necessary pages have been rendered or the
// print settings are being loaded.
bool inside_inner_message_loop_;
#if (defined(OS_POSIX) && !defined(OS_MACOSX)) || \
defined(WIN_PDF_METAFILE_FOR_PRINTING)
// Set to true when OnDidPrintPage() should be expecting the first page.
bool expecting_first_page_;
#endif
// The document cookie of the current PrinterQuery.
int cookie_;
// Whether printing is enabled.
bool printing_enabled_;
scoped_refptr<printing::PrintQueriesQueue> queue_;
DISALLOW_COPY_AND_ASSIGN(PrintViewManagerBase);
};
} // namespace printing
#endif // CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_BASE_H_

View File

@@ -0,0 +1,48 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/printing/print_view_manager_basic.h"
#if defined(OS_ANDROID)
#include "base/file_descriptor_posix.h"
#include "chrome/common/print_messages.h"
#include "printing/printing_context_android.h"
#endif
DEFINE_WEB_CONTENTS_USER_DATA_KEY(printing::PrintViewManagerBasic);
namespace printing {
PrintViewManagerBasic::PrintViewManagerBasic(content::WebContents* web_contents)
: PrintViewManagerBase(web_contents) {
}
PrintViewManagerBasic::~PrintViewManagerBasic() {
}
#if defined(OS_ANDROID)
void PrintViewManagerBasic::RenderProcessGone(base::TerminationStatus status) {
PrintingContextAndroid::PdfWritingDone(file_descriptor_.fd, false);
file_descriptor_ = base::FileDescriptor(-1, false);
PrintViewManagerBase::RenderProcessGone(status);
}
void PrintViewManagerBasic::OnPrintingFailed(int cookie) {
PrintingContextAndroid::PdfWritingDone(file_descriptor_.fd, false);
file_descriptor_ = base::FileDescriptor(-1, false);
PrintViewManagerBase::OnPrintingFailed(cookie);
}
bool PrintViewManagerBasic::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(PrintViewManagerBasic, message)
IPC_MESSAGE_HANDLER(PrintHostMsg_PrintingFailed, OnPrintingFailed)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled ? true : PrintViewManagerBase::OnMessageReceived(message);
}
#endif
} // namespace printing

View File

@@ -0,0 +1,57 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_BASIC_H_
#define CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_BASIC_H_
#include "chrome/browser/printing/print_view_manager_base.h"
#include "content/public/browser/web_contents_user_data.h"
#if defined(OS_ANDROID)
#include "base/file_descriptor_posix.h"
#endif
namespace printing {
// Manages the print commands for a WebContents - basic version.
class PrintViewManagerBasic
: public PrintViewManagerBase,
public content::WebContentsUserData<PrintViewManagerBasic> {
public:
virtual ~PrintViewManagerBasic();
#if defined(OS_ANDROID)
// Sets the file descriptor into which the PDF will be written.
void set_file_descriptor(const base::FileDescriptor& file_descriptor) {
file_descriptor_ = file_descriptor;
}
// Gets the file descriptor into which the PDF will be written.
base::FileDescriptor file_descriptor() const { return file_descriptor_; }
// content::WebContentsObserver implementation.
// Terminates or cancels the print job if one was pending.
virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE;
// content::WebContentsObserver implementation.
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
#endif
private:
explicit PrintViewManagerBasic(content::WebContents* web_contents);
friend class content::WebContentsUserData<PrintViewManagerBasic>;
#if defined(OS_ANDROID)
virtual void OnPrintingFailed(int cookie) OVERRIDE;
// The file descriptor into which the PDF of the page will be written.
base::FileDescriptor file_descriptor_;
#endif
DISALLOW_COPY_AND_ASSIGN(PrintViewManagerBasic);
};
} // namespace printing
#endif // CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_BASIC_H_

View File

@@ -0,0 +1,23 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_OBSERVER_H_
#define CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_OBSERVER_H_
namespace printing {
// An interface the PrintViewManager uses to notify an observer when the print
// dialog is shown. Register the observer via PrintViewManager::set_observer.
class PrintViewManagerObserver {
public:
// Notifies the observer that the print dialog was shown.
virtual void OnPrintDialogShown() = 0;
protected:
virtual ~PrintViewManagerObserver() {}
};
} // namespace printing
#endif // CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_OBSERVER_H_

View File

@@ -0,0 +1,143 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/printing/printer_query.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/message_loop/message_loop.h"
#include "base/threading/thread_restrictions.h"
#include "base/values.h"
#include "chrome/browser/printing/print_job_worker.h"
#include "chrome/browser/printing/printing_ui_web_contents_observer.h"
namespace printing {
PrinterQuery::PrinterQuery()
: io_message_loop_(base::MessageLoop::current()),
worker_(new PrintJobWorker(this)),
is_print_dialog_box_shown_(false),
cookie_(PrintSettings::NewCookie()),
last_status_(PrintingContext::FAILED) {
DCHECK(base::MessageLoopForIO::IsCurrent());
}
PrinterQuery::~PrinterQuery() {
// The job should be finished (or at least canceled) when it is destroyed.
DCHECK(!is_print_dialog_box_shown_);
// If this fires, it is that this pending printer context has leaked.
DCHECK(!worker_.get());
}
void PrinterQuery::GetSettingsDone(const PrintSettings& new_settings,
PrintingContext::Result result) {
is_print_dialog_box_shown_ = false;
last_status_ = result;
if (result != PrintingContext::FAILED) {
settings_ = new_settings;
cookie_ = PrintSettings::NewCookie();
} else {
// Failure.
cookie_ = 0;
}
if (!callback_.is_null()) {
// This may cause reentrancy like to call StopWorker().
callback_.Run();
callback_.Reset();
}
}
PrintJobWorker* PrinterQuery::DetachWorker(PrintJobWorkerOwner* new_owner) {
DCHECK(callback_.is_null());
DCHECK(worker_.get());
worker_->SetNewOwner(new_owner);
return worker_.release();
}
base::MessageLoop* PrinterQuery::message_loop() {
return io_message_loop_;
}
const PrintSettings& PrinterQuery::settings() const {
return settings_;
}
int PrinterQuery::cookie() const {
return cookie_;
}
void PrinterQuery::GetSettings(
GetSettingsAskParam ask_user_for_settings,
scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,
int expected_page_count,
bool has_selection,
MarginType margin_type,
const base::Closure& callback) {
DCHECK_EQ(io_message_loop_, base::MessageLoop::current());
DCHECK(!is_print_dialog_box_shown_);
StartWorker(callback);
// Real work is done in PrintJobWorker::GetSettings().
is_print_dialog_box_shown_ = ask_user_for_settings == ASK_USER;
worker_->message_loop()->PostTask(
FROM_HERE,
base::Bind(&PrintJobWorker::GetSettings,
base::Unretained(worker_.get()),
is_print_dialog_box_shown_,
base::Passed(&web_contents_observer),
expected_page_count,
has_selection,
margin_type));
}
void PrinterQuery::SetSettings(const base::DictionaryValue& new_settings,
const base::Closure& callback) {
StartWorker(callback);
worker_->message_loop()->PostTask(
FROM_HERE,
base::Bind(&PrintJobWorker::SetSettings,
base::Unretained(worker_.get()),
new_settings.DeepCopy()));
}
void PrinterQuery::SetWorkerDestination(
PrintDestinationInterface* destination) {
worker_->SetPrintDestination(destination);
}
void PrinterQuery::StartWorker(const base::Closure& callback) {
DCHECK(callback_.is_null());
DCHECK(worker_.get());
// Lazily create the worker thread. There is one worker thread per print job.
if (!worker_->message_loop())
worker_->Start();
callback_ = callback;
}
void PrinterQuery::StopWorker() {
if (worker_.get()) {
// http://crbug.com/66082: We're blocking on the PrinterQuery's worker
// thread. It's not clear to me if this may result in blocking the current
// thread for an unacceptable time. We should probably fix it.
base::ThreadRestrictions::ScopedAllowIO allow_io;
worker_->Stop();
worker_.reset();
}
}
bool PrinterQuery::is_callback_pending() const {
return !callback_.is_null();
}
bool PrinterQuery::is_valid() const {
return worker_.get() != NULL;
}
} // namespace printing

View File

@@ -0,0 +1,110 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PRINTING_PRINTER_QUERY_H_
#define CHROME_BROWSER_PRINTING_PRINTER_QUERY_H_
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "chrome/browser/printing/print_job_worker_owner.h"
#include "printing/print_job_constants.h"
class PrintingUIWebContentsObserver;
namespace base {
class DictionaryValue;
class MessageLoop;
}
namespace printing {
class PrintDestinationInterface;
class PrintJobWorker;
// Query the printer for settings.
class PrinterQuery : public PrintJobWorkerOwner {
public:
// GetSettings() UI parameter.
enum GetSettingsAskParam {
DEFAULTS,
ASK_USER,
};
PrinterQuery();
// PrintJobWorkerOwner implementation.
virtual void GetSettingsDone(const PrintSettings& new_settings,
PrintingContext::Result result) OVERRIDE;
virtual PrintJobWorker* DetachWorker(PrintJobWorkerOwner* new_owner) OVERRIDE;
virtual base::MessageLoop* message_loop() OVERRIDE;
virtual const PrintSettings& settings() const OVERRIDE;
virtual int cookie() const OVERRIDE;
// Initializes the printing context. It is fine to call this function multiple
// times to reinitialize the settings. |web_contents_observer| can be queried
// to find the owner of the print setting dialog box. It is unused when
// |ask_for_user_settings| is DEFAULTS.
void GetSettings(
GetSettingsAskParam ask_user_for_settings,
scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,
int expected_page_count,
bool has_selection,
MarginType margin_type,
const base::Closure& callback);
// Updates the current settings with |new_settings| dictionary values.
void SetSettings(const base::DictionaryValue& new_settings,
const base::Closure& callback);
// Set a destination for the worker.
void SetWorkerDestination(PrintDestinationInterface* destination);
// Stops the worker thread since the client is done with this object.
void StopWorker();
// Returns true if a GetSettings() call is pending completion.
bool is_callback_pending() const;
PrintingContext::Result last_status() const { return last_status_; }
// Returns if a worker thread is still associated to this instance.
bool is_valid() const;
private:
virtual ~PrinterQuery();
// Lazy create the worker thread. There is one worker thread per print job.
void StartWorker(const base::Closure& callback);
// Main message loop reference. Used to send notifications in the right
// thread.
base::MessageLoop* const io_message_loop_;
// All the UI is done in a worker thread because many Win32 print functions
// are blocking and enters a message loop without your consent. There is one
// worker thread per print job.
scoped_ptr<PrintJobWorker> worker_;
// Cache of the print context settings for access in the UI thread.
PrintSettings settings_;
// Is the Print... dialog box currently shown.
bool is_print_dialog_box_shown_;
// Cookie that make this instance unique.
int cookie_;
// Results from the last GetSettingsDone() callback.
PrintingContext::Result last_status_;
// Callback waiting to be run.
base::Closure callback_;
DISALLOW_COPY_AND_ASSIGN(PrinterQuery);
};
} // namespace printing
#endif // CHROME_BROWSER_PRINTING_PRINTER_QUERY_H_

View File

@@ -0,0 +1,233 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/printing/printing_message_filter.h"
#include <string>
#include "base/bind.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/printing/printer_query.h"
#include "chrome/browser/printing/print_job_manager.h"
#include "chrome/browser/printing/printing_ui_web_contents_observer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_io_data.h"
#include "chrome/common/print_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
using content::BrowserThread;
namespace {
void RenderParamsFromPrintSettings(const printing::PrintSettings& settings,
PrintMsg_Print_Params* params) {
params->page_size = settings.page_setup_device_units().physical_size();
params->content_size.SetSize(
settings.page_setup_device_units().content_area().width(),
settings.page_setup_device_units().content_area().height());
params->printable_area.SetRect(
settings.page_setup_device_units().printable_area().x(),
settings.page_setup_device_units().printable_area().y(),
settings.page_setup_device_units().printable_area().width(),
settings.page_setup_device_units().printable_area().height());
params->margin_top = settings.page_setup_device_units().content_area().y();
params->margin_left = settings.page_setup_device_units().content_area().x();
params->dpi = settings.dpi();
// Currently hardcoded at 1.25. See PrintSettings' constructor.
params->min_shrink = settings.min_shrink();
// Currently hardcoded at 2.0. See PrintSettings' constructor.
params->max_shrink = settings.max_shrink();
// Currently hardcoded at 72dpi. See PrintSettings' constructor.
params->desired_dpi = settings.desired_dpi();
// Always use an invalid cookie.
params->document_cookie = 0;
params->selection_only = settings.selection_only();
params->supports_alpha_blend = settings.supports_alpha_blend();
params->should_print_backgrounds = settings.should_print_backgrounds();
params->title = settings.title();
params->url = settings.url();
}
} // namespace
PrintingMessageFilter::PrintingMessageFilter(int render_process_id)
: BrowserMessageFilter(PrintMsgStart),
render_process_id_(render_process_id),
queue_(g_browser_process->print_job_manager()->queue()) {
DCHECK(queue_);
}
PrintingMessageFilter::~PrintingMessageFilter() {
}
bool PrintingMessageFilter::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(PrintingMessageFilter, message)
#if defined(OS_WIN)
IPC_MESSAGE_HANDLER(PrintHostMsg_DuplicateSection, OnDuplicateSection)
#endif
IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_GetDefaultPrintSettings,
OnGetDefaultPrintSettings)
IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_ScriptedPrint, OnScriptedPrint)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
#if defined(OS_WIN)
void PrintingMessageFilter::OnDuplicateSection(
base::SharedMemoryHandle renderer_handle,
base::SharedMemoryHandle* browser_handle) {
// Duplicate the handle in this process right now so the memory is kept alive
// (even if it is not mapped)
base::SharedMemory shared_buf(renderer_handle, true, PeerHandle());
shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), browser_handle);
}
#endif
content::WebContents* PrintingMessageFilter::GetWebContentsForRenderView(
int render_view_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
content::RenderViewHost* view = content::RenderViewHost::FromID(
render_process_id_, render_view_id);
return view ? content::WebContents::FromRenderViewHost(view) : NULL;
}
struct PrintingMessageFilter::GetPrintSettingsForRenderViewParams {
printing::PrinterQuery::GetSettingsAskParam ask_user_for_settings;
int expected_page_count;
bool has_selection;
printing::MarginType margin_type;
};
void PrintingMessageFilter::GetPrintSettingsForRenderView(
int render_view_id,
GetPrintSettingsForRenderViewParams params,
const base::Closure& callback,
scoped_refptr<printing::PrinterQuery> printer_query) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
content::WebContents* wc = GetWebContentsForRenderView(render_view_id);
if (wc) {
scoped_ptr<PrintingUIWebContentsObserver> wc_observer(
new PrintingUIWebContentsObserver(wc));
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&printing::PrinterQuery::GetSettings, printer_query,
params.ask_user_for_settings, base::Passed(&wc_observer),
params.expected_page_count, params.has_selection,
params.margin_type, callback));
} else {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&PrintingMessageFilter::OnGetPrintSettingsFailed, this,
callback, printer_query));
}
}
void PrintingMessageFilter::OnGetPrintSettingsFailed(
const base::Closure& callback,
scoped_refptr<printing::PrinterQuery> printer_query) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
printer_query->GetSettingsDone(printing::PrintSettings(),
printing::PrintingContext::FAILED);
callback.Run();
}
void PrintingMessageFilter::OnGetDefaultPrintSettings(IPC::Message* reply_msg) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
scoped_refptr<printing::PrinterQuery> printer_query;
if (false) {
// Reply with NULL query.
OnGetDefaultPrintSettingsReply(printer_query, reply_msg);
return;
}
printer_query = queue_->PopPrinterQuery(0);
if (!printer_query)
printer_query = queue_->CreatePrinterQuery();
// Loads default settings. This is asynchronous, only the IPC message sender
// will hang until the settings are retrieved.
GetPrintSettingsForRenderViewParams params;
params.ask_user_for_settings = printing::PrinterQuery::DEFAULTS;
params.expected_page_count = 0;
params.has_selection = false;
params.margin_type = printing::DEFAULT_MARGINS;
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&PrintingMessageFilter::GetPrintSettingsForRenderView, this,
reply_msg->routing_id(), params,
base::Bind(&PrintingMessageFilter::OnGetDefaultPrintSettingsReply,
this, printer_query, reply_msg),
printer_query));
}
void PrintingMessageFilter::OnGetDefaultPrintSettingsReply(
scoped_refptr<printing::PrinterQuery> printer_query,
IPC::Message* reply_msg) {
PrintMsg_Print_Params params;
if (!printer_query.get() ||
printer_query->last_status() != printing::PrintingContext::OK) {
params.Reset();
} else {
RenderParamsFromPrintSettings(printer_query->settings(), &params);
params.document_cookie = printer_query->cookie();
}
PrintHostMsg_GetDefaultPrintSettings::WriteReplyParams(reply_msg, params);
Send(reply_msg);
// If printing was enabled.
if (printer_query.get()) {
// If user hasn't cancelled.
if (printer_query->cookie() && printer_query->settings().dpi()) {
queue_->QueuePrinterQuery(printer_query.get());
} else {
printer_query->StopWorker();
}
}
}
void PrintingMessageFilter::OnScriptedPrint(
const PrintHostMsg_ScriptedPrint_Params& params,
IPC::Message* reply_msg) {
scoped_refptr<printing::PrinterQuery> printer_query =
queue_->PopPrinterQuery(params.cookie);
if (!printer_query)
printer_query = queue_->CreatePrinterQuery();
GetPrintSettingsForRenderViewParams settings_params;
settings_params.ask_user_for_settings = printing::PrinterQuery::ASK_USER;
settings_params.expected_page_count = params.expected_pages_count;
settings_params.has_selection = params.has_selection;
settings_params.margin_type = params.margin_type;
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&PrintingMessageFilter::GetPrintSettingsForRenderView, this,
reply_msg->routing_id(), settings_params,
base::Bind(&PrintingMessageFilter::OnScriptedPrintReply, this,
printer_query, reply_msg),
printer_query));
}
void PrintingMessageFilter::OnScriptedPrintReply(
scoped_refptr<printing::PrinterQuery> printer_query,
IPC::Message* reply_msg) {
PrintMsg_PrintPages_Params params;
if (printer_query->last_status() != printing::PrintingContext::OK ||
!printer_query->settings().dpi()) {
params.Reset();
} else {
RenderParamsFromPrintSettings(printer_query->settings(), &params.params);
params.params.document_cookie = printer_query->cookie();
params.pages =
printing::PageRange::GetPages(printer_query->settings().ranges());
}
PrintHostMsg_ScriptedPrint::WriteReplyParams(reply_msg, params);
Send(reply_msg);
if (params.params.dpi && params.params.document_cookie) {
queue_->QueuePrinterQuery(printer_query.get());
} else {
printer_query->StopWorker();
}
}

View File

@@ -0,0 +1,96 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PRINTING_PRINTING_MESSAGE_FILTER_H_
#define CHROME_BROWSER_PRINTING_PRINTING_MESSAGE_FILTER_H_
#include <string>
#include "base/compiler_specific.h"
#include "content/public/browser/browser_message_filter.h"
#if defined(OS_WIN)
#include "base/memory/shared_memory.h"
#endif
struct PrintHostMsg_ScriptedPrint_Params;
namespace base {
class DictionaryValue;
class FilePath;
}
namespace content {
class WebContents;
}
namespace printing {
class PrinterQuery;
class PrintJobManager;
class PrintQueriesQueue;
}
// This class filters out incoming printing related IPC messages for the
// renderer process on the IPC thread.
class PrintingMessageFilter : public content::BrowserMessageFilter {
public:
explicit PrintingMessageFilter(int render_process_id);
// content::BrowserMessageFilter methods.
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
private:
virtual ~PrintingMessageFilter();
#if defined(OS_WIN)
// Used to pass resulting EMF from renderer to browser in printing.
void OnDuplicateSection(base::SharedMemoryHandle renderer_handle,
base::SharedMemoryHandle* browser_handle);
#endif
// Given a render_view_id get the corresponding WebContents.
// Must be called on the UI thread.
content::WebContents* GetWebContentsForRenderView(int render_view_id);
// GetPrintSettingsForRenderView must be called via PostTask and
// base::Bind. Collapse the settings-specific params into a
// struct to avoid running into issues with too many params
// to base::Bind.
struct GetPrintSettingsForRenderViewParams;
// Retrieve print settings. Uses |render_view_id| to get a parent
// for any UI created if needed.
void GetPrintSettingsForRenderView(
int render_view_id,
GetPrintSettingsForRenderViewParams params,
const base::Closure& callback,
scoped_refptr<printing::PrinterQuery> printer_query);
void OnGetPrintSettingsFailed(
const base::Closure& callback,
scoped_refptr<printing::PrinterQuery> printer_query);
// Get the default print setting.
void OnGetDefaultPrintSettings(IPC::Message* reply_msg);
void OnGetDefaultPrintSettingsReply(
scoped_refptr<printing::PrinterQuery> printer_query,
IPC::Message* reply_msg);
// The renderer host have to show to the user the print dialog and returns
// the selected print settings. The task is handled by the print worker
// thread and the UI thread. The reply occurs on the IO thread.
void OnScriptedPrint(const PrintHostMsg_ScriptedPrint_Params& params,
IPC::Message* reply_msg);
void OnScriptedPrintReply(
scoped_refptr<printing::PrinterQuery> printer_query,
IPC::Message* reply_msg);
const int render_process_id_;
scoped_refptr<printing::PrintQueriesQueue> queue_;
DISALLOW_COPY_AND_ASSIGN(PrintingMessageFilter);
};
#endif // CHROME_BROWSER_PRINTING_PRINTING_MESSAGE_FILTER_H_

View File

@@ -0,0 +1,19 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/printing/printing_ui_web_contents_observer.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
PrintingUIWebContentsObserver::PrintingUIWebContentsObserver(
content::WebContents* web_contents)
: content::WebContentsObserver(web_contents) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
}
gfx::NativeView PrintingUIWebContentsObserver::GetParentView() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
return web_contents() ? web_contents()->GetNativeView() : NULL;
}

View File

@@ -0,0 +1,25 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PRINTING_PRINTING_UI_WEB_CONTENTS_OBSERVER_H_
#define CHROME_BROWSER_PRINTING_PRINTING_UI_WEB_CONTENTS_OBSERVER_H_
#include "base/basictypes.h"
#include "content/public/browser/web_contents_observer.h"
#include "ui/gfx/native_widget_types.h"
// Wrapper used to keep track of the lifetime of a WebContents.
// Lives on the UI thread.
class PrintingUIWebContentsObserver : public content::WebContentsObserver {
public:
explicit PrintingUIWebContentsObserver(content::WebContents* web_contents);
// Return the parent NativeView of the observed WebContents.
gfx::NativeView GetParentView();
private:
DISALLOW_COPY_AND_ASSIGN(PrintingUIWebContentsObserver);
};
#endif // CHROME_BROWSER_PRINTING_PRINTING_UI_WEB_CONTENTS_OBSERVER_H_

View File

View File

@@ -0,0 +1,60 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/common/print_messages.h"
#include "base/basictypes.h"
#include "base/strings/string16.h"
#include "ui/gfx/size.h"
PrintMsg_Print_Params::PrintMsg_Print_Params()
: page_size(),
content_size(),
printable_area(),
margin_top(0),
margin_left(0),
dpi(0),
min_shrink(0),
max_shrink(0),
desired_dpi(0),
document_cookie(0),
selection_only(false),
supports_alpha_blend(false),
print_scaling_option(blink::WebPrintScalingOptionSourceSize),
title(),
url(),
should_print_backgrounds(false) {
}
PrintMsg_Print_Params::~PrintMsg_Print_Params() {}
void PrintMsg_Print_Params::Reset() {
page_size = gfx::Size();
content_size = gfx::Size();
printable_area = gfx::Rect();
margin_top = 0;
margin_left = 0;
dpi = 0;
min_shrink = 0;
max_shrink = 0;
desired_dpi = 0;
document_cookie = 0;
selection_only = false;
supports_alpha_blend = false;
print_scaling_option = blink::WebPrintScalingOptionSourceSize;
title.clear();
url.clear();
should_print_backgrounds = false;
}
PrintMsg_PrintPages_Params::PrintMsg_PrintPages_Params()
: pages() {
}
PrintMsg_PrintPages_Params::~PrintMsg_PrintPages_Params() {}
void PrintMsg_PrintPages_Params::Reset() {
params.Reset();
pages = std::vector<int>();
}

View File

@@ -0,0 +1,241 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// IPC messages for printing.
// Multiply-included message file, hence no include guard.
#include <string>
#include <vector>
#include "base/memory/shared_memory.h"
#include "base/values.h"
#include "ipc/ipc_message_macros.h"
#include "printing/page_size_margins.h"
#include "printing/print_job_constants.h"
#include "third_party/WebKit/public/web/WebPrintScalingOption.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/rect.h"
#ifndef CHROME_COMMON_PRINT_MESSAGES_H_
#define CHROME_COMMON_PRINT_MESSAGES_H_
struct PrintMsg_Print_Params {
PrintMsg_Print_Params();
~PrintMsg_Print_Params();
// Resets the members of the struct to 0.
void Reset();
gfx::Size page_size;
gfx::Size content_size;
gfx::Rect printable_area;
int margin_top;
int margin_left;
double dpi;
double min_shrink;
double max_shrink;
int desired_dpi;
int document_cookie;
bool selection_only;
bool supports_alpha_blend;
blink::WebPrintScalingOption print_scaling_option;
base::string16 title;
base::string16 url;
bool should_print_backgrounds;
};
struct PrintMsg_PrintPages_Params {
PrintMsg_PrintPages_Params();
~PrintMsg_PrintPages_Params();
// Resets the members of the struct to 0.
void Reset();
PrintMsg_Print_Params params;
std::vector<int> pages;
};
#endif // CHROME_COMMON_PRINT_MESSAGES_H_
#define IPC_MESSAGE_START PrintMsgStart
IPC_ENUM_TRAITS_MAX_VALUE(printing::MarginType,
printing::MARGIN_TYPE_LAST)
IPC_ENUM_TRAITS_MAX_VALUE(blink::WebPrintScalingOption,
blink::WebPrintScalingOptionLast)
// Parameters for a render request.
IPC_STRUCT_TRAITS_BEGIN(PrintMsg_Print_Params)
// Physical size of the page, including non-printable margins,
// in pixels according to dpi.
IPC_STRUCT_TRAITS_MEMBER(page_size)
// In pixels according to dpi_x and dpi_y.
IPC_STRUCT_TRAITS_MEMBER(content_size)
// Physical printable area of the page in pixels according to dpi.
IPC_STRUCT_TRAITS_MEMBER(printable_area)
// The y-offset of the printable area, in pixels according to dpi.
IPC_STRUCT_TRAITS_MEMBER(margin_top)
// The x-offset of the printable area, in pixels according to dpi.
IPC_STRUCT_TRAITS_MEMBER(margin_left)
// Specifies dots per inch.
IPC_STRUCT_TRAITS_MEMBER(dpi)
// Minimum shrink factor. See PrintSettings::min_shrink for more information.
IPC_STRUCT_TRAITS_MEMBER(min_shrink)
// Maximum shrink factor. See PrintSettings::max_shrink for more information.
IPC_STRUCT_TRAITS_MEMBER(max_shrink)
// Desired apparent dpi on paper.
IPC_STRUCT_TRAITS_MEMBER(desired_dpi)
// Cookie for the document to ensure correctness.
IPC_STRUCT_TRAITS_MEMBER(document_cookie)
// Should only print currently selected text.
IPC_STRUCT_TRAITS_MEMBER(selection_only)
// Does the printer support alpha blending?
IPC_STRUCT_TRAITS_MEMBER(supports_alpha_blend)
// Specifies the page scaling option for preview printing.
IPC_STRUCT_TRAITS_MEMBER(print_scaling_option)
// Title string to be printed as header if requested by the user.
IPC_STRUCT_TRAITS_MEMBER(title)
// URL string to be printed as footer if requested by the user.
IPC_STRUCT_TRAITS_MEMBER(url)
// True if print backgrounds is requested by the user.
IPC_STRUCT_TRAITS_MEMBER(should_print_backgrounds)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_BEGIN(PrintMsg_PrintPage_Params)
// Parameters to render the page as a printed page. It must always be the same
// value for all the document.
IPC_STRUCT_MEMBER(PrintMsg_Print_Params, params)
// The page number is the indicator of the square that should be rendered
// according to the layout specified in PrintMsg_Print_Params.
IPC_STRUCT_MEMBER(int, page_number)
IPC_STRUCT_END()
IPC_STRUCT_TRAITS_BEGIN(printing::PageSizeMargins)
IPC_STRUCT_TRAITS_MEMBER(content_width)
IPC_STRUCT_TRAITS_MEMBER(content_height)
IPC_STRUCT_TRAITS_MEMBER(margin_left)
IPC_STRUCT_TRAITS_MEMBER(margin_right)
IPC_STRUCT_TRAITS_MEMBER(margin_top)
IPC_STRUCT_TRAITS_MEMBER(margin_bottom)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(PrintMsg_PrintPages_Params)
// Parameters to render the page as a printed page. It must always be the same
// value for all the document.
IPC_STRUCT_TRAITS_MEMBER(params)
// If empty, this means a request to render all the printed pages.
IPC_STRUCT_TRAITS_MEMBER(pages)
IPC_STRUCT_TRAITS_END()
// Parameters to describe a rendered page.
IPC_STRUCT_BEGIN(PrintHostMsg_DidPrintPage_Params)
// A shared memory handle to the EMF data. This data can be quite large so a
// memory map needs to be used.
IPC_STRUCT_MEMBER(base::SharedMemoryHandle, metafile_data_handle)
// Size of the metafile data.
IPC_STRUCT_MEMBER(uint32, data_size)
// Cookie for the document to ensure correctness.
IPC_STRUCT_MEMBER(int, document_cookie)
// Page number.
IPC_STRUCT_MEMBER(int, page_number)
// Shrink factor used to render this page.
IPC_STRUCT_MEMBER(double, actual_shrink)
// The size of the page the page author specified.
IPC_STRUCT_MEMBER(gfx::Size, page_size)
// The printable area the page author specified.
IPC_STRUCT_MEMBER(gfx::Rect, content_area)
IPC_STRUCT_END()
// Parameters for the IPC message ViewHostMsg_ScriptedPrint
IPC_STRUCT_BEGIN(PrintHostMsg_ScriptedPrint_Params)
IPC_STRUCT_MEMBER(int, cookie)
IPC_STRUCT_MEMBER(int, expected_pages_count)
IPC_STRUCT_MEMBER(bool, has_selection)
IPC_STRUCT_MEMBER(printing::MarginType, margin_type)
IPC_STRUCT_END()
// Messages sent from the browser to the renderer.
// Tells the render view to switch the CSS to print media type, renders every
// requested pages and switch back the CSS to display media type.
IPC_MESSAGE_ROUTED2(PrintMsg_PrintPages,
bool /* silent print */,
bool /* print page's background */)
// Tells the render view that printing is done so it can clean up.
IPC_MESSAGE_ROUTED1(PrintMsg_PrintingDone,
bool /* success */)
// Messages sent from the renderer to the browser.
#if defined(OS_WIN)
// Duplicates a shared memory handle from the renderer to the browser. Then
// the renderer can flush the handle.
IPC_SYNC_MESSAGE_ROUTED1_1(PrintHostMsg_DuplicateSection,
base::SharedMemoryHandle /* renderer handle */,
base::SharedMemoryHandle /* browser handle */)
#endif
// Tells the browser that the renderer is done calculating the number of
// rendered pages according to the specified settings.
IPC_MESSAGE_ROUTED2(PrintHostMsg_DidGetPrintedPagesCount,
int /* rendered document cookie */,
int /* number of rendered pages */)
// Sends the document cookie of the current printer query to the browser.
IPC_MESSAGE_ROUTED1(PrintHostMsg_DidGetDocumentCookie,
int /* rendered document cookie */)
// Tells the browser that the print dialog has been shown.
IPC_MESSAGE_ROUTED0(PrintHostMsg_DidShowPrintDialog)
// Sends back to the browser the rendered "printed page" that was requested by
// a ViewMsg_PrintPage message or from scripted printing. The memory handle in
// this message is already valid in the browser process.
IPC_MESSAGE_ROUTED1(PrintHostMsg_DidPrintPage,
PrintHostMsg_DidPrintPage_Params /* page content */)
// The renderer wants to know the default print settings.
IPC_SYNC_MESSAGE_ROUTED0_1(PrintHostMsg_GetDefaultPrintSettings,
PrintMsg_Print_Params /* default_settings */)
// It's the renderer that controls the printing process when it is generated
// by javascript. This step is about showing UI to the user to select the
// final print settings. The output parameter is the same as
// ViewMsg_PrintPages which is executed implicitly.
IPC_SYNC_MESSAGE_ROUTED1_1(PrintHostMsg_ScriptedPrint,
PrintHostMsg_ScriptedPrint_Params,
PrintMsg_PrintPages_Params
/* settings chosen by the user*/)
// This is sent when there are invalid printer settings.
IPC_MESSAGE_ROUTED0(PrintHostMsg_ShowInvalidPrinterSettingsError)
// Tell the browser printing failed.
IPC_MESSAGE_ROUTED1(PrintHostMsg_PrintingFailed,
int /* document cookie */)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,218 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_RENDERER_PRINTING_PRINT_WEB_VIEW_HELPER_H_
#define CHROME_RENDERER_PRINTING_PRINT_WEB_VIEW_HELPER_H_
#include <vector>
#include "base/memory/scoped_ptr.h"
#include "base/memory/shared_memory.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "content/public/renderer/render_view_observer.h"
#include "content/public/renderer/render_view_observer_tracker.h"
#include "printing/metafile_impl.h"
#include "third_party/WebKit/public/platform/WebCanvas.h"
#include "third_party/WebKit/public/web/WebNode.h"
#include "third_party/WebKit/public/web/WebPrintParams.h"
#include "ui/gfx/size.h"
struct PrintMsg_Print_Params;
struct PrintMsg_PrintPage_Params;
struct PrintMsg_PrintPages_Params;
namespace base {
class DictionaryValue;
}
namespace blink {
class WebFrame;
class WebView;
}
namespace printing {
struct PageSizeMargins;
class PrepareFrameAndViewForPrint;
// Stores reference to frame using WebVew and unique name.
// Workaround to modal dialog issue on Linux. crbug.com/236147.
// If WebFrame someday supports WeakPtr, we should use it here.
class FrameReference {
public:
explicit FrameReference(blink::WebLocalFrame* frame);
FrameReference();
~FrameReference();
void Reset(blink::WebLocalFrame* frame);
blink::WebLocalFrame* GetFrame();
blink::WebView* view();
private:
blink::WebView* view_;
blink::WebLocalFrame* frame_;
};
// PrintWebViewHelper handles most of the printing grunt work for RenderView.
// We plan on making print asynchronous and that will require copying the DOM
// of the document and creating a new WebView with the contents.
class PrintWebViewHelper
: public content::RenderViewObserver,
public content::RenderViewObserverTracker<PrintWebViewHelper> {
public:
explicit PrintWebViewHelper(content::RenderView* render_view);
virtual ~PrintWebViewHelper();
void PrintNode(const blink::WebNode& node);
private:
enum PrintingResult {
OK,
FAIL_PRINT_INIT,
FAIL_PRINT,
};
// RenderViewObserver implementation.
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
virtual void PrintPage(blink::WebLocalFrame* frame,
bool user_initiated) OVERRIDE;
// Message handlers ---------------------------------------------------------
void OnPrintPages(bool silent, bool print_background);
void OnPrintingDone(bool success);
// Get |page_size| and |content_area| information from
// |page_layout_in_points|.
void GetPageSizeAndContentAreaFromPageLayout(
const PageSizeMargins& page_layout_in_points,
gfx::Size* page_size,
gfx::Rect* content_area);
// Update |ignore_css_margins_| based on settings.
void UpdateFrameMarginsCssInfo(const base::DictionaryValue& settings);
// Main printing code -------------------------------------------------------
void Print(blink::WebLocalFrame* frame,
const blink::WebNode& node,
bool silent = false,
bool print_background = false);
// Notification when printing is done - signal tear-down/free resources.
void DidFinishPrinting(PrintingResult result);
// Print Settings -----------------------------------------------------------
// Initialize print page settings with default settings.
// Used only for native printing workflow.
bool InitPrintSettings(bool fit_to_paper_size);
// Calculate number of pages in source document.
bool CalculateNumberOfPages(blink::WebLocalFrame* frame,
const blink::WebNode& node,
int* number_of_pages);
// Get final print settings from the user.
// Return false if the user cancels or on error.
bool GetPrintSettingsFromUser(blink::WebFrame* frame,
const blink::WebNode& node,
int expected_pages_count);
// Page Printing / Rendering ------------------------------------------------
void OnFramePreparedForPrintPages();
void PrintPages();
bool PrintPagesNative(blink::WebFrame* frame,
int page_count,
const gfx::Size& canvas_size);
void FinishFramePrinting();
// Prints the page listed in |params|.
#if defined(OS_LINUX) || defined(OS_ANDROID)
void PrintPageInternal(const PrintMsg_PrintPage_Params& params,
const gfx::Size& canvas_size,
blink::WebFrame* frame,
Metafile* metafile);
#else
void PrintPageInternal(const PrintMsg_PrintPage_Params& params,
const gfx::Size& canvas_size,
blink::WebFrame* frame);
#endif
// Render the frame for printing.
bool RenderPagesForPrint(blink::WebLocalFrame* frame,
const blink::WebNode& node);
// Platform specific helper function for rendering page(s) to |metafile|.
#if defined(OS_WIN)
void RenderPage(const PrintMsg_Print_Params& params,
int page_number,
blink::WebFrame* frame,
bool is_preview,
Metafile* metafile,
double* scale_factor,
gfx::Size* page_size_in_dpi,
gfx::Rect* content_area_in_dpi);
#elif defined(OS_MACOSX)
void RenderPage(const PrintMsg_Print_Params& params,
int page_number,
blink::WebFrame* frame,
bool is_preview,
Metafile* metafile,
gfx::Size* page_size,
gfx::Rect* content_rect);
#endif // defined(OS_WIN)
// Renders page contents from |frame| to |content_area| of |canvas|.
// |page_number| is zero-based.
// When method is called, canvas should be setup to draw to |canvas_area|
// with |scale_factor|.
static float RenderPageContent(blink::WebFrame* frame,
int page_number,
const gfx::Rect& canvas_area,
const gfx::Rect& content_area,
double scale_factor,
blink::WebCanvas* canvas);
// Helper methods -----------------------------------------------------------
bool CopyMetafileDataToSharedMem(Metafile* metafile,
base::SharedMemoryHandle* shared_mem_handle);
// Helper method to get page layout in points and fit to page if needed.
static void ComputePageLayoutInPointsForCss(
blink::WebFrame* frame,
int page_index,
const PrintMsg_Print_Params& default_params,
bool ignore_css_margins,
double* scale_factor,
PageSizeMargins* page_layout_in_points);
bool GetPrintFrame(blink::WebLocalFrame** frame);
// Script Initiated Printing ------------------------------------------------
// WebView used only to print the selection.
scoped_ptr<PrepareFrameAndViewForPrint> prep_frame_view_;
scoped_ptr<PrintMsg_PrintPages_Params> print_pages_params_;
bool is_print_ready_metafile_sent_;
bool ignore_css_margins_;
// Let the browser process know of a printing failure. Only set to false when
// the failure came from the browser in the first place.
bool notify_browser_of_print_failure_;
bool print_node_in_progress_;
base::WeakPtrFactory<PrintWebViewHelper> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(PrintWebViewHelper);
};
} // namespace printing
#endif // CHROME_RENDERER_PRINTING_PRINT_WEB_VIEW_HELPER_H_

View File

@@ -0,0 +1,157 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/renderer/printing/print_web_view_helper.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "chrome/common/print_messages.h"
#include "content/public/renderer/render_thread.h"
#include "printing/metafile.h"
#include "printing/metafile_impl.h"
#include "printing/metafile_skia_wrapper.h"
#include "printing/page_size_margins.h"
#include "skia/ext/platform_device.h"
#include "skia/ext/vector_canvas.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
#include "base/process/process_handle.h"
#else
#include "base/file_descriptor_posix.h"
#endif // !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
namespace printing {
using blink::WebFrame;
bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame,
int page_count,
const gfx::Size& canvas_size) {
NativeMetafile metafile;
if (!metafile.Init())
return false;
const PrintMsg_PrintPages_Params& params = *print_pages_params_;
std::vector<int> printed_pages;
if (params.pages.empty()) {
for (int i = 0; i < page_count; ++i) {
printed_pages.push_back(i);
}
} else {
// TODO(vitalybuka): redesign to make more code cross platform.
for (size_t i = 0; i < params.pages.size(); ++i) {
if (params.pages[i] >= 0 && params.pages[i] < page_count) {
printed_pages.push_back(params.pages[i]);
}
}
}
if (printed_pages.empty())
return false;
PrintMsg_PrintPage_Params page_params;
page_params.params = params.params;
for (size_t i = 0; i < printed_pages.size(); ++i) {
page_params.page_number = printed_pages[i];
PrintPageInternal(page_params, canvas_size, frame, &metafile);
}
// blink::printEnd() for PDF should be called before metafile is closed.
FinishFramePrinting();
metafile.FinishDocument();
// Get the size of the resulting metafile.
uint32 buf_size = metafile.GetDataSize();
DCHECK_GT(buf_size, 0u);
#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
int sequence_number = -1;
base::FileDescriptor fd;
// Ask the browser to open a file for us.
Send(new PrintHostMsg_AllocateTempFileForPrinting(routing_id(),
&fd,
&sequence_number));
if (!metafile.SaveToFD(fd))
return false;
// Tell the browser we've finished writing the file.
Send(new PrintHostMsg_TempFileForPrintingWritten(routing_id(),
sequence_number));
return true;
#else
PrintHostMsg_DidPrintPage_Params printed_page_params;
printed_page_params.data_size = 0;
printed_page_params.document_cookie = params.params.document_cookie;
{
scoped_ptr<base::SharedMemory> shared_mem(
content::RenderThread::Get()->HostAllocateSharedMemoryBuffer(
buf_size).release());
if (!shared_mem.get()) {
NOTREACHED() << "AllocateSharedMemoryBuffer failed";
return false;
}
if (!shared_mem->Map(buf_size)) {
NOTREACHED() << "Map failed";
return false;
}
metafile.GetData(shared_mem->memory(), buf_size);
printed_page_params.data_size = buf_size;
shared_mem->GiveToProcess(base::GetCurrentProcessHandle(),
&(printed_page_params.metafile_data_handle));
}
for (size_t i = 0; i < printed_pages.size(); ++i) {
printed_page_params.page_number = printed_pages[i];
Send(new PrintHostMsg_DidPrintPage(routing_id(), printed_page_params));
// Send the rest of the pages with an invalid metafile handle.
printed_page_params.metafile_data_handle.fd = -1;
}
return true;
#endif // defined(OS_CHROMEOS)
}
void PrintWebViewHelper::PrintPageInternal(
const PrintMsg_PrintPage_Params& params,
const gfx::Size& canvas_size,
WebFrame* frame,
Metafile* metafile) {
PageSizeMargins page_layout_in_points;
double scale_factor = 1.0f;
ComputePageLayoutInPointsForCss(frame, params.page_number, params.params,
ignore_css_margins_, &scale_factor,
&page_layout_in_points);
gfx::Size page_size;
gfx::Rect content_area;
GetPageSizeAndContentAreaFromPageLayout(page_layout_in_points, &page_size,
&content_area);
gfx::Rect canvas_area = content_area;
SkBaseDevice* device = metafile->StartPageForVectorCanvas(page_size,
canvas_area,
scale_factor);
if (!device)
return;
// The printPage method take a reference to the canvas we pass down, so it
// can't be a stack object.
skia::RefPtr<skia::VectorCanvas> canvas =
skia::AdoptRef(new skia::VectorCanvas(device));
MetafileSkiaWrapper::SetMetafileOnCanvas(*canvas, metafile);
skia::SetIsDraftMode(*canvas, is_print_ready_metafile_sent_);
RenderPageContent(frame, params.page_number, canvas_area, content_area,
scale_factor, canvas.get());
// Done printing. Close the device context to retrieve the compiled metafile.
if (!metafile->FinishPage())
NOTREACHED() << "metafile failed";
}
} // namespace printing

View File

@@ -0,0 +1,99 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/renderer/printing/print_web_view_helper.h"
#import <AppKit/AppKit.h>
#include "base/logging.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include "base/metrics/histogram.h"
#include "chrome/common/print_messages.h"
#include "printing/metafile.h"
#include "printing/metafile_impl.h"
#include "printing/metafile_skia_wrapper.h"
#include "printing/page_size_margins.h"
#include "skia/ext/platform_device.h"
#include "skia/ext/vector_canvas.h"
#include "third_party/WebKit/public/platform/WebCanvas.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
namespace printing {
using blink::WebFrame;
void PrintWebViewHelper::PrintPageInternal(
const PrintMsg_PrintPage_Params& params,
const gfx::Size& canvas_size,
WebFrame* frame) {
NativeMetafile metafile;
if (!metafile.Init())
return;
int page_number = params.page_number;
gfx::Size page_size_in_dpi;
gfx::Rect content_area_in_dpi;
RenderPage(print_pages_params_->params, page_number, frame, false, &metafile,
&page_size_in_dpi, &content_area_in_dpi);
metafile.FinishDocument();
PrintHostMsg_DidPrintPage_Params page_params;
page_params.data_size = metafile.GetDataSize();
page_params.page_number = page_number;
page_params.document_cookie = params.params.document_cookie;
page_params.page_size = page_size_in_dpi;
page_params.content_area = content_area_in_dpi;
// Ask the browser to create the shared memory for us.
if (!CopyMetafileDataToSharedMem(&metafile,
&(page_params.metafile_data_handle))) {
page_params.data_size = 0;
}
Send(new PrintHostMsg_DidPrintPage(routing_id(), page_params));
}
void PrintWebViewHelper::RenderPage(
const PrintMsg_Print_Params& params, int page_number, WebFrame* frame,
bool is_preview, Metafile* metafile, gfx::Size* page_size,
gfx::Rect* content_rect) {
double scale_factor = 1.0f;
double webkit_shrink_factor = frame->getPrintPageShrink(page_number);
PageSizeMargins page_layout_in_points;
gfx::Rect content_area;
ComputePageLayoutInPointsForCss(frame, page_number, params,
ignore_css_margins_, &scale_factor,
&page_layout_in_points);
GetPageSizeAndContentAreaFromPageLayout(page_layout_in_points, page_size,
&content_area);
if (content_rect)
*content_rect = content_area;
scale_factor *= webkit_shrink_factor;
gfx::Rect canvas_area = content_area;
{
SkBaseDevice* device = metafile->StartPageForVectorCanvas(
*page_size, canvas_area, scale_factor);
if (!device)
return;
skia::RefPtr<skia::VectorCanvas> canvas =
skia::AdoptRef(new skia::VectorCanvas(device));
blink::WebCanvas* canvas_ptr = canvas.get();
MetafileSkiaWrapper::SetMetafileOnCanvas(*canvas, metafile);
skia::SetIsDraftMode(*canvas, is_print_ready_metafile_sent_);
skia::SetIsPreviewMetafile(*canvas, is_preview);
RenderPageContent(frame, page_number, canvas_area, content_area,
scale_factor, canvas_ptr);
}
// Done printing. Close the device context to retrieve the compiled metafile.
metafile->FinishPage();
}
} // namespace printing

View File

@@ -0,0 +1,193 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/renderer/printing/print_web_view_helper.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram.h"
#include "base/process/process_handle.h"
#include "base/win/scoped_gdi_object.h"
#include "base/win/scoped_hdc.h"
#include "base/win/scoped_select_object.h"
#include "chrome/common/print_messages.h"
#include "printing/metafile.h"
#include "printing/metafile_impl.h"
#include "printing/metafile_skia_wrapper.h"
#include "printing/page_size_margins.h"
#include "printing/units.h"
#include "skia/ext/platform_device.h"
#include "skia/ext/refptr.h"
#include "skia/ext/vector_canvas.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "ui/gfx/gdi_util.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
namespace printing {
using blink::WebFrame;
void PrintWebViewHelper::PrintPageInternal(
const PrintMsg_PrintPage_Params& params,
const gfx::Size& canvas_size,
WebFrame* frame) {
// Generate a memory-based metafile. It will use the current screen's DPI.
// Each metafile contains a single page.
scoped_ptr<NativeMetafile> metafile(new NativeMetafile);
metafile->Init();
DCHECK(metafile->context());
skia::InitializeDC(metafile->context());
int page_number = params.page_number;
// Calculate the dpi adjustment.
// Browser will render context using desired_dpi, so we need to calculate
// adjustment factor to play content on the printer DC later during the
// actual printing.
double actual_shrink = static_cast<float>(params.params.desired_dpi /
params.params.dpi);
gfx::Size page_size_in_dpi;
gfx::Rect content_area_in_dpi;
// Render page for printing.
RenderPage(params.params, page_number, frame, false, metafile.get(),
&actual_shrink, &page_size_in_dpi, &content_area_in_dpi);
// Close the device context to retrieve the compiled metafile.
if (!metafile->FinishDocument())
NOTREACHED();
if (!params.params.supports_alpha_blend && metafile->IsAlphaBlendUsed()) {
scoped_ptr<NativeMetafile> raster_metafile(
metafile->RasterizeAlphaBlend());
if (raster_metafile.get())
metafile.swap(raster_metafile);
}
// Get the size of the compiled metafile.
uint32 buf_size = metafile->GetDataSize();
DCHECK_GT(buf_size, 128u);
PrintHostMsg_DidPrintPage_Params page_params;
page_params.data_size = buf_size;
page_params.metafile_data_handle = NULL;
page_params.page_number = page_number;
page_params.document_cookie = params.params.document_cookie;
page_params.actual_shrink = actual_shrink;
page_params.page_size = page_size_in_dpi;
page_params.content_area = content_area_in_dpi;
if (!CopyMetafileDataToSharedMem(metafile.get(),
&(page_params.metafile_data_handle))) {
page_params.data_size = 0;
}
Send(new PrintHostMsg_DidPrintPage(routing_id(), page_params));
}
void PrintWebViewHelper::RenderPage(
const PrintMsg_Print_Params& params, int page_number, WebFrame* frame,
bool is_preview, Metafile* metafile, double* actual_shrink,
gfx::Size* page_size_in_dpi, gfx::Rect* content_area_in_dpi) {
PageSizeMargins page_layout_in_points;
double css_scale_factor = 1.0f;
ComputePageLayoutInPointsForCss(frame, page_number, params,
ignore_css_margins_, &css_scale_factor,
&page_layout_in_points);
gfx::Size page_size;
gfx::Rect content_area;
GetPageSizeAndContentAreaFromPageLayout(page_layout_in_points, &page_size,
&content_area);
int dpi = static_cast<int>(params.dpi);
// Calculate the actual page size and content area in dpi.
if (page_size_in_dpi) {
*page_size_in_dpi = gfx::Size(
static_cast<int>(ConvertUnitDouble(page_size.width(), kPointsPerInch,
dpi)),
static_cast<int>(ConvertUnitDouble(page_size.height(), kPointsPerInch,
dpi)));
}
if (content_area_in_dpi) {
*content_area_in_dpi = gfx::Rect(
static_cast<int>(ConvertUnitDouble(content_area.x(), kPointsPerInch,
dpi)),
static_cast<int>(ConvertUnitDouble(content_area.y(), kPointsPerInch,
dpi)),
static_cast<int>(ConvertUnitDouble(content_area.width(), kPointsPerInch,
dpi)),
static_cast<int>(ConvertUnitDouble(content_area.height(),
kPointsPerInch, dpi)));
}
float webkit_page_shrink_factor = frame->getPrintPageShrink(page_number);
float scale_factor = css_scale_factor * webkit_page_shrink_factor;
gfx::Rect canvas_area = content_area;
SkBaseDevice* device = metafile->StartPageForVectorCanvas(
page_size, canvas_area, scale_factor);
DCHECK(device);
// The printPage method may take a reference to the canvas we pass down, so it
// can't be a stack object.
skia::RefPtr<skia::VectorCanvas> canvas =
skia::AdoptRef(new skia::VectorCanvas(device));
float webkit_scale_factor = RenderPageContent(frame, page_number, canvas_area,
content_area, scale_factor,
canvas.get());
if (*actual_shrink <= 0 || webkit_scale_factor <= 0) {
NOTREACHED() << "Printing page " << page_number << " failed.";
} else {
// While rendering certain plugins (PDF) to metafile, we might need to
// set custom scale factor. Update |actual_shrink| with custom scale
// if it is set on canvas.
// TODO(gene): We should revisit this solution for the next versions.
// Consider creating metafile of the right size (or resizable)
// https://code.google.com/p/chromium/issues/detail?id=126037
if (!MetafileSkiaWrapper::GetCustomScaleOnCanvas(
*canvas, actual_shrink)) {
// Update the dpi adjustment with the "page |actual_shrink|" calculated in
// webkit.
*actual_shrink /= (webkit_scale_factor * css_scale_factor);
}
}
bool result = metafile->FinishPage();
DCHECK(result);
}
bool PrintWebViewHelper::CopyMetafileDataToSharedMem(
Metafile* metafile, base::SharedMemoryHandle* shared_mem_handle) {
uint32 buf_size = metafile->GetDataSize();
base::SharedMemory shared_buf;
if (buf_size >= kMetafileMaxSize) {
NOTREACHED() << "Buffer too large: " << buf_size;
return false;
}
// Allocate a shared memory buffer to hold the generated metafile data.
if (!shared_buf.CreateAndMapAnonymous(buf_size)) {
NOTREACHED() << "Buffer allocation failed";
return false;
}
// Copy the bits into shared memory.
if (!metafile->GetData(shared_buf.memory(), buf_size)) {
NOTREACHED() << "GetData() failed";
shared_buf.Unmap();
return false;
}
shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), shared_mem_handle);
shared_buf.Unmap();
Send(new PrintHostMsg_DuplicateSection(routing_id(), *shared_mem_handle,
shared_mem_handle));
return true;
}
} // namespace printing

View File

View File

@@ -4,6 +4,7 @@
* [Application distribution](tutorial/application-distribution.md)
* [Use native node modules](tutorial/use-native-node-modules.md)
* [Debugging browser process](tutorial/debugging-browser-process.md)
* [DevTools extension](tutorial/devtools-extension.md)
## API references

View File

@@ -63,6 +63,8 @@ normal browsers, see [Web Security](web-security.md) for more.
key is pressed.
* `enable-larger-than-screen` Boolean - Enable the window to be resized larger
than screen.
* `dark-theme` Boolean - Forces using dark theme for the window, only works on
some GTK+3 desktop environments.
* `web-preferences` Object - Settings of web page's features
* `javascript` Boolean
* `web-security` Boolean
@@ -136,6 +138,14 @@ Emitted when window loses focus.
Emitted when window gains focus.
### Event: 'devtools-opened'
Emitted when devtools is opened.
### Event: 'devtools-closed'
Emitted when devtools is closed.
### Class Method: BrowserWindow.getAllWindows()
Returns an array of all opened browser windows.
@@ -156,6 +166,21 @@ Find a window according to the `webContents` it owns
Find a window according to its ID.
### Class Method: BrowserWindow.addDevToolsExtension(path)
* `path` String
Adds devtools extension located at `path`, and returns extension's name.
The extension will be remembered so you only need to call this API once, this
API is not for programming use.
### Class Method: BrowserWindow.removeDevToolsExtension(name)
* `name` String
Remove the devtools extension whose name is `name`.
### BrowserWindow.webContents
The `WebContents` object this window owns, all web page related events and
@@ -336,11 +361,13 @@ Changes the title of native window to `title`.
Returns the title of the native window.
**Note:** The title of web page can be different from the title of the native
**window.
window.
### BrowserWindow.flashFrame()
### BrowserWindow.flashFrame(flag)
Flashes the window to attract user's attention.
* `flag` Boolean
Starts or stops flashing the window to attract user's attention.
### BrowserWindow.setSkipTaskbar(skip)
@@ -406,10 +433,10 @@ Starts inspecting element at position (`x`, `y`).
### BrowserWindow.capturePage([rect, ]callback)
* `rect` Object - The area of page to be captured
* `x`
* `y`
* `width`
* `height`
* `x` Integer
* `y` Integer
* `width` Integer
* `height` Integer
* `callback` Function
Captures the snapshot of page within `rect`, upon completion `callback` would be
@@ -424,6 +451,19 @@ encode it and use data URL to embed the image in HTML.
[remote](remote.md) if you are going to use this API in renderer
process.
### BrowserWindow.print([options])
* `options` Object
* `silent` Boolean - Don't ask user for print settings, defaults to `false`
* `printBackground` Boolean - Also prints the background color and image of
the web page, defaults to `false`.
Prints window's web page. When `silent` is set to `false`, atom-shell will pick
up system's default printer and default settings for printing.
Calling `window.print()` in web page is equivalent to call
`BrowserWindow.print({silent: false, printBackground: false})`.
### BrowserWindow.loadUrl(url)
Same with `webContents.loadUrl(url)`.

View File

@@ -13,7 +13,7 @@ console.log(dialog.showOpenDialog({ properties: [ 'openFile', 'openDirectory', '
**Note for OS X**: If you want to present dialogs as sheets, the only thing you have to do is to provide a `BrowserWindow` reference in the `browserWindow` parameter.
## dialog.showOpenDialog([browserWindow], options, [callback])
## dialog.showOpenDialog([browserWindow], [options], [callback])
* `browserWindow` BrowserWindow
* `options` Object
@@ -49,7 +49,7 @@ and directory selector at the same time, so if you set `properties` to
`['openFile', 'openDirectory']` on these platforms, a directory selector would
be showed.
## dialog.showSaveDialog([browserWindow], options, [callback])
## dialog.showSaveDialog([browserWindow], [options], [callback])
* `browserWindow` BrowserWindow
* `options` Object
@@ -67,7 +67,7 @@ The `filters` specifies an array of file types that can be displayed, see
If a `callback` is passed, the API call would be asynchronous and the result
would be passed via `callback(filename)`
## dialog.showMessageBox([browserWindow], options, [callback])
## dialog.showMessageBox([browserWindow], [options], [callback])
* `browserWindow` BrowserWindow
* `options` Object

View File

@@ -42,6 +42,13 @@ var template = [
{
type: 'separator'
},
{
label: 'Services',
submenu: []
},
{
type: 'separator'
},
{
label: 'Hide Atom Shell',
accelerator: 'Command+H',
@@ -141,6 +148,10 @@ var template = [
},
]
},
{
label: 'Help',
submenu: []
},
];
menu = Menu.buildFromTemplate(template);
@@ -175,7 +186,7 @@ emulating default Cocoa menu behaviors, usually you would just use the
* `template` Array
Generally, the `template` is just an array of `options` for constructing
`MenuItem`, the usage can be referenced above.
[MenuItem](menu-item.md), the usage can be referenced above.
You can also attach other fields to element of the `template`, and they will
become properties of the constructed menu items.
@@ -202,3 +213,34 @@ Inserts the `menuItem` to the `pos` position of the menu.
### Menu.items
Get the array containing the menu's items.
## Notes on OS X application menu
OS X has a completely different style of application menu from Windows and
Linux, and here are some notes on making your app's menu more native-like.
### Standard menus
On OS X there are many system defined standard menus, like the `Services` and
`Windows` menus. To make your menu a standard menu, you can just set your menu's
label to one of followings, and atom-shell will recognize them and make them
become standard menus:
* `Window`
* `Help`
* `Services`
### Standard menu item actions
OS X has provided standard actions for some menu items (which are called
`selector`s), like `About xxx`, `Hide xxx`, and `Hide Others`. To set the action
of a menu item to a standard action, you can set the `selector` attribute of the
menu item.
### Main menu's name
On OS X the label of application menu's first item is always your app's name,
no matter what label you set. To change it you have to change your app's name
by modifying your app bundle's `Info.plist` file. See
[About Information Property List Files](https://developer.apple.com/library/ios/documentation/general/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html)
for more.

View File

@@ -33,13 +33,13 @@ $ node-inspector
You can either start atom-shell with a debug flag like:
```bash
$ atom-shell --debug your/app
$ atom-shell --debug=5858 your/app
```
or, to pause your script on the first line:
```bash
$ atom-shell --debug-brk your/app
$ atom-shell --debug-brk=5858 your/app
```
### 3. Load the debugger UI

View File

@@ -0,0 +1,56 @@
# DevTools extension
To make debugging more easy, atom-shell has added basic support for
[Chrome DevTools Extension][devtools-extension].
For most devtools extensions, you can simply download their source codes and use
the `BrowserWindow.addDevToolsExtension` API to load them, the loaded extensions
will be remembered so you don't need to call the API every time when creating
a window.
For example to use the React DevTools Extension, first you need to download its
source code:
```bash
$ cd /some-directory
$ git clone --recursive https://github.com/facebook/react-devtools.git
```
Then you can load it in atom-shell by opening the devtools in arbitray window,
and run this code in the console of devtools:
```javascript
require('remote').require('browser-window').addDevToolsExtension('/some-directory/react-devtools')
```
To unload the extension, you can call `BrowserWindow.removeDevToolsExtension`
API with its name and it will disappear the next time you open the devtools:
```javascript
require('remote').require('browser-window').removeDevToolsExtension('React Developer Tools')
```
## Format of devtools extension
Ideally all devtools extension written for Chrome browser can be loaded by
atom-shell, but they have to be in a plain directory, for those packaged `crx`
extensions, there is no way in atom-shell to load them unless you find a way to
extract them into a directory.
## Background pages
Currently atom-shell doesn't support the background pages of chrome extensions,
so for some devtools extensions that rely on this feature, they may not work
well in atom-shell
## `chrome.*` APIs
Some chrome extensions use `chrome.*` APIs for some features, there is some
effort to implement those APIs in atom-shell to make them work, but we have
only implemented few for now.
So if the devtools extension is using APIs other than `chrome.devtools.*`, it is
very likely to fail, but you can report those extensions in the issues tracker
so we can add support for those APIs.
[devtools-extension]: https://developer.chrome.com/extensions/devtools

View File

@@ -1,6 +1,6 @@
{
"name": "atom-shell",
"version": "0.15.9",
"version": "0.16.0",
"licenses": [
{
@@ -10,7 +10,7 @@
],
"devDependencies": {
"atom-package-manager": "0.89.0",
"atom-package-manager": "0.93.0",
"coffee-script": "~1.7.1",
"coffeelint": "~1.3.0"
},

View File

@@ -4,7 +4,7 @@ import argparse
import os
import sys
from lib.config import LIBCHROMIUMCONTENT_COMMIT, BASE_URL, NODE_VERSION
from lib.config import LIBCHROMIUMCONTENT_COMMIT, BASE_URL
from lib.util import execute, scoped_cwd, enable_verbose_execute
@@ -22,7 +22,6 @@ def main():
enable_verbose_execute()
update_submodules()
update_node_modules('.')
update_atom_modules('atom/browser/default_app')
update_atom_modules('spec')
bootstrap_brightray(args.url)
if sys.platform == 'cygwin':
@@ -66,7 +65,6 @@ def update_node_modules(dirname):
def update_atom_modules(dirname):
os.environ['ATOM_NODE_VERSION'] = NODE_VERSION[1:]
with scoped_cwd(dirname):
apm = os.path.join(SOURCE_ROOT, 'node_modules', '.bin', 'apm')
if sys.platform in ['win32', 'cygwin']:

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