From c9fbde321c5595430fa869774f4bb942470e9221 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Fri, 2 Oct 2015 17:50:10 +0800 Subject: [PATCH 01/67] Implement desktop capture API on OS X. --- atom.gyp | 4 + atom/browser/api/atom_api_desktop_capturer.cc | 127 ++++++ atom/browser/api/atom_api_desktop_capturer.h | 51 +++ atom/browser/api/atom_api_screen.cc | 18 +- atom/browser/api/atom_api_screen.h | 5 + atom/browser/api/lib/app.coffee | 14 +- atom/common/node_bindings.cc | 1 + .../chrome/browser/media/desktop_media_list.h | 60 +++ .../media/desktop_media_list_observer.h | 22 ++ .../media/native_desktop_media_list.cc | 366 ++++++++++++++++++ .../browser/media/native_desktop_media_list.h | 100 +++++ filenames.gypi | 6 + 12 files changed, 768 insertions(+), 6 deletions(-) create mode 100644 atom/browser/api/atom_api_desktop_capturer.cc create mode 100644 atom/browser/api/atom_api_desktop_capturer.h create mode 100644 chromium_src/chrome/browser/media/desktop_media_list.h create mode 100644 chromium_src/chrome/browser/media/desktop_media_list_observer.h create mode 100644 chromium_src/chrome/browser/media/native_desktop_media_list.cc create mode 100644 chromium_src/chrome/browser/media/native_desktop_media_list.h diff --git a/atom.gyp b/atom.gyp index 3a46f242a238..ed885743c6a6 100644 --- a/atom.gyp +++ b/atom.gyp @@ -245,6 +245,10 @@ 'vendor/node/deps/cares/include', # The `third_party/WebKit/Source/platform/weborigin/SchemeRegistry.h` is using `platform/PlatformExport.h`. '<(libchromiumcontent_src_dir)/third_party/WebKit/Source', + # The 'third_party/libyuv/include/libyuv/scale_argb.h' is using 'libyuv/basic_types.h'. + '<(libchromiumcontent_src_dir)/third_party/libyuv/include', + # The 'third_party/webrtc/modules/desktop_capture/desktop_frame.h' is using 'webrtc/base/scoped_ptr.h'. + '<(libchromiumcontent_src_dir)/third_party/', ], 'direct_dependent_settings': { 'include_dirs': [ diff --git a/atom/browser/api/atom_api_desktop_capturer.cc b/atom/browser/api/atom_api_desktop_capturer.cc new file mode 100644 index 000000000000..c3a573715703 --- /dev/null +++ b/atom/browser/api/atom_api_desktop_capturer.cc @@ -0,0 +1,127 @@ +// Copyright (c) 2015 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/api/atom_api_desktop_capturer.h" + +#include "atom/common/api/atom_api_native_image.h" +#include "atom/common/native_mate_converters/callback.h" +#include "atom/common/node_includes.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/media/desktop_media_list.h" +#include "native_mate/dictionary.h" +#include "native_mate/handle.h" +#include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h" +#include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" +#include "third_party/webrtc/modules/desktop_capture/window_capturer.h" + +namespace mate { + +template<> +struct Converter { + static v8::Local ToV8(v8::Isolate* isolate, + const DesktopMediaList::Source& source) { + mate::Dictionary dict(isolate, v8::Object::New(isolate)); + content::DesktopMediaID id = source.id; + dict.Set("name", base::UTF16ToUTF8(source.name)); + dict.Set("id", id.ToString()); + dict.Set("thumbnail", + atom::api::NativeImage::Create(isolate, gfx::Image(source.thumbnail))); + return ConvertToV8(isolate, dict); + } +}; + +} // namespace mate + +namespace atom { + +namespace api { + +namespace { +// The wrapDesktopCapturer funtion which is implemented in JavaScript +using WrapDesktopCapturerCallback = base::Callback)>; +WrapDesktopCapturerCallback g_wrap_desktop_capturer; + +const int kThumbnailWidth = 150; +const int kThumbnailHeight = 150; +} // namespace + +DesktopCapturer::DesktopCapturer(bool show_screens, bool show_windows) { + scoped_ptr screen_capturer( + show_screens ? webrtc::ScreenCapturer::Create() : nullptr); + scoped_ptr window_capturer( + show_windows ? webrtc::WindowCapturer::Create() : nullptr); + media_list_.reset(new NativeDesktopMediaList(screen_capturer.Pass(), + window_capturer.Pass())); + media_list_->SetThumbnailSize(gfx::Size(kThumbnailWidth, kThumbnailHeight)); + media_list_->StartUpdating(this); +} + +DesktopCapturer::~DesktopCapturer() { +} + +const DesktopMediaList::Source& DesktopCapturer::GetSource(int index) { + return media_list_->GetSource(index); +} + +void DesktopCapturer::OnSourceAdded(int index) { + Emit("source-added", index); +} + +void DesktopCapturer::OnSourceRemoved(int index) { + Emit("source-removed", index); +} + +void DesktopCapturer::OnSourceMoved(int old_index, int new_index) { + Emit("source-moved", old_index, new_index); +} + +void DesktopCapturer::OnSourceNameChanged(int index) { + Emit("source-name-changed", index); +} + +void DesktopCapturer::OnSourceThumbnailChanged(int index) { + Emit("source-thumbnail-changed", index); +} + +mate::ObjectTemplateBuilder DesktopCapturer::GetObjectTemplateBuilder( + v8::Isolate* isolate) { + return mate::ObjectTemplateBuilder(isolate) + .SetMethod("getSource", &DesktopCapturer::GetSource); +} + +void SetWrapDesktopCapturer(const WrapDesktopCapturerCallback& callback) { + g_wrap_desktop_capturer = callback; +} + +void ClearWrapDesktopCapturer() { + g_wrap_desktop_capturer.Reset(); +} + +// static +mate::Handle DesktopCapturer::Create(v8::Isolate* isolate, + bool show_screens, bool show_windows) { + auto handle = mate::CreateHandle(isolate, + new DesktopCapturer(show_screens, show_windows)); + g_wrap_desktop_capturer.Run(handle.ToV8()); + return handle; +} + +} // namespace api + +} // namespace atom + +namespace { + +void Initialize(v8::Local exports, v8::Local unused, + v8::Local context, void* priv) { + v8::Isolate* isolate = context->GetIsolate(); + mate::Dictionary dict(isolate, exports); + dict.SetMethod("_setWrapDesktopCapturer", &atom::api::SetWrapDesktopCapturer); + dict.SetMethod("_clearWrapDesktopCapturer", + &atom::api::ClearWrapDesktopCapturer); +} + +} // namespace + +NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_desktop_capturer, Initialize); diff --git a/atom/browser/api/atom_api_desktop_capturer.h b/atom/browser/api/atom_api_desktop_capturer.h new file mode 100644 index 000000000000..aae0a8268b9d --- /dev/null +++ b/atom/browser/api/atom_api_desktop_capturer.h @@ -0,0 +1,51 @@ +// Copyright (c) 2015 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_API_ATOM_API_DESKTOP_CAPTURER_ +#define ATOM_BROWSER_API_ATOM_API_DESKTOP_CAPTURER_ + +#include "base/memory/scoped_ptr.h" +#include "atom/browser/api/event_emitter.h" +#include "chrome/browser/media/desktop_media_list_observer.h" +#include "chrome/browser/media/native_desktop_media_list.h" +#include "native_mate/handle.h" + +namespace atom { + +namespace api { + +class DesktopCapturer: public mate::EventEmitter, + public DesktopMediaListObserver { + public: + static mate::Handle Create(v8::Isolate* isolate, + bool show_screens, bool show_windows); + + const DesktopMediaList::Source& GetSource(int index); + + protected: + DesktopCapturer(bool show_screens, bool show_windows); + ~DesktopCapturer(); + + // DesktopMediaListObserver overrides. + void OnSourceAdded(int index) override; + void OnSourceRemoved(int index) override; + void OnSourceMoved(int old_index, int new_index) override; + void OnSourceNameChanged(int index) override; + void OnSourceThumbnailChanged(int index) override; + + private: + // mate::Wrappable: + mate::ObjectTemplateBuilder GetObjectTemplateBuilder( + v8::Isolate* isolate) override; + + scoped_ptr media_list_; + + DISALLOW_COPY_AND_ASSIGN(DesktopCapturer); +}; + +} // namespace api + +} // namespace atom + +#endif // ATOM_BROWSER_API_ATOM_API_DESKTOP_CAPTURER_ diff --git a/atom/browser/api/atom_api_screen.cc b/atom/browser/api/atom_api_screen.cc index b73bda9ced84..761ef28ef97e 100644 --- a/atom/browser/api/atom_api_screen.cc +++ b/atom/browser/api/atom_api_screen.cc @@ -56,6 +56,21 @@ Screen::~Screen() { screen_->RemoveObserver(this); } +mate::Handle Screen::GetDesktopCapturer( + const std::vector& sources) { + bool show_screens = false; + bool show_windows = false; + for (const auto& source_type : sources) { + if (source_type == "screen") { + show_screens = true; + } else if (source_type == "window") { + show_windows = true; + } + } + + return DesktopCapturer::Create(isolate(), show_screens, show_windows); +} + gfx::Point Screen::GetCursorScreenPoint() { return screen_->GetCursorScreenPoint(); } @@ -107,7 +122,8 @@ mate::ObjectTemplateBuilder Screen::GetObjectTemplateBuilder( .SetMethod("getPrimaryDisplay", &Screen::GetPrimaryDisplay) .SetMethod("getAllDisplays", &Screen::GetAllDisplays) .SetMethod("getDisplayNearestPoint", &Screen::GetDisplayNearestPoint) - .SetMethod("getDisplayMatching", &Screen::GetDisplayMatching); + .SetMethod("getDisplayMatching", &Screen::GetDisplayMatching) + .SetMethod("getDesktopCapturer", &Screen::GetDesktopCapturer); } // static diff --git a/atom/browser/api/atom_api_screen.h b/atom/browser/api/atom_api_screen.h index f724130fa7fc..619f6c8b3f7c 100644 --- a/atom/browser/api/atom_api_screen.h +++ b/atom/browser/api/atom_api_screen.h @@ -6,7 +6,9 @@ #define ATOM_BROWSER_API_ATOM_API_SCREEN_H_ #include +#include +#include "atom/browser/api/atom_api_desktop_capturer.h" #include "atom/browser/api/event_emitter.h" #include "native_mate/handle.h" #include "ui/gfx/display_observer.h" @@ -36,6 +38,9 @@ class Screen : public mate::EventEmitter, gfx::Display GetDisplayNearestPoint(const gfx::Point& point); gfx::Display GetDisplayMatching(const gfx::Rect& match_rect); + mate::Handle GetDesktopCapturer( + const std::vector& sources); + // gfx::DisplayObserver: void OnDisplayAdded(const gfx::Display& new_display) override; void OnDisplayRemoved(const gfx::Display& old_display) override; diff --git a/atom/browser/api/lib/app.coffee b/atom/browser/api/lib/app.coffee index 18c80dc2b1f4..9ff568cf8d26 100644 --- a/atom/browser/api/lib/app.coffee +++ b/atom/browser/api/lib/app.coffee @@ -3,17 +3,18 @@ EventEmitter = require('events').EventEmitter bindings = process.atomBinding 'app' sessionBindings = process.atomBinding 'session' downloadItemBindings = process.atomBinding 'download_item' +desktopCapturerBindings = process.atomBinding 'desktop_capturer' app = bindings.app app.__proto__ = EventEmitter.prototype -wrapSession = (session) -> - # session is an Event Emitter. - session.__proto__ = EventEmitter.prototype +wrapToEventListener = (item) -> + # item is an Event Emitter. + item.__proto__ = EventEmitter.prototype wrapDownloadItem = (download_item) -> # download_item is an Event Emitter. - download_item.__proto__ = EventEmitter.prototype + wrapToEventListener download_item # Be compatible with old APIs. download_item.url = download_item.getUrl() download_item.filename = download_item.getFilename() @@ -58,11 +59,14 @@ app.resolveProxy = -> @defaultSession.resolveProxy.apply @defaultSession, argume app.on 'activate', (event, hasVisibleWindows) -> @emit 'activate-with-no-open-windows' if not hasVisibleWindows # Session wrapper. -sessionBindings._setWrapSession wrapSession +sessionBindings._setWrapSession wrapToEventListener process.once 'exit', sessionBindings._clearWrapSession downloadItemBindings._setWrapDownloadItem wrapDownloadItem process.once 'exit', downloadItemBindings._clearWrapDownloadItem +desktopCapturerBindings._setWrapDesktopCapturer wrapToEventListener +process.once 'exit', desktopCapturerBindings._clearWrapDesktopCapturer + # Only one App object pemitted. module.exports = app diff --git a/atom/common/node_bindings.cc b/atom/common/node_bindings.cc index 2da68854ad14..9d2004deec8b 100644 --- a/atom/common/node_bindings.cc +++ b/atom/common/node_bindings.cc @@ -34,6 +34,7 @@ REFERENCE_MODULE(atom_browser_app); REFERENCE_MODULE(atom_browser_auto_updater); REFERENCE_MODULE(atom_browser_content_tracing); REFERENCE_MODULE(atom_browser_dialog); +REFERENCE_MODULE(atom_browser_desktop_capturer); REFERENCE_MODULE(atom_browser_download_item); REFERENCE_MODULE(atom_browser_menu); REFERENCE_MODULE(atom_browser_power_monitor); diff --git a/chromium_src/chrome/browser/media/desktop_media_list.h b/chromium_src/chrome/browser/media/desktop_media_list.h new file mode 100644 index 000000000000..fa0dbd815749 --- /dev/null +++ b/chromium_src/chrome/browser/media/desktop_media_list.h @@ -0,0 +1,60 @@ +// 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_MEDIA_DESKTOP_MEDIA_LIST_H_ +#define CHROME_BROWSER_MEDIA_DESKTOP_MEDIA_LIST_H_ + +#include "base/basictypes.h" +#include "base/time/time.h" +#include "content/public/browser/desktop_media_id.h" +#include "ui/gfx/image/image_skia.h" + +class DesktopMediaListObserver; + +// DesktopMediaList provides the list of desktop media source (screens, windows, +// tabs), and their thumbnails, to the desktop media picker dialog. It +// transparently updates the list in the background, and notifies the desktop +// media picker when something changes. +class DesktopMediaList { + public: + // Struct used to represent each entry in the list. + struct Source { + // Id of the source. + content::DesktopMediaID id; + + // Name of the source that should be shown to the user. + base::string16 name; + + // The thumbnail for the source. + gfx::ImageSkia thumbnail; + }; + + virtual ~DesktopMediaList() {} + + // Sets time interval between updates. By default list of sources and their + // thumbnail are updated once per second. If called after StartUpdating() then + // it will take effect only after the next update. + virtual void SetUpdatePeriod(base::TimeDelta period) = 0; + + // Sets size to which the thumbnails should be scaled. If called after + // StartUpdating() then some thumbnails may be still scaled to the old size + // until they are updated. + virtual void SetThumbnailSize(const gfx::Size& thumbnail_size) = 0; + + // Sets ID of the hosting desktop picker dialog. The window with this ID will + // be filtered out from the list of sources. + virtual void SetViewDialogWindowId(content::DesktopMediaID::Id dialog_id) = 0; + + // Starts updating the model. The model is initially empty, so OnSourceAdded() + // notifications will be generated for each existing source as it is + // enumerated. After the initial enumeration the model will be refreshed based + // on the update period, and notifications generated only for changes in the + // model. + virtual void StartUpdating(DesktopMediaListObserver* observer) = 0; + + virtual int GetSourceCount() const = 0; + virtual const Source& GetSource(int index) const = 0; +}; + +#endif // CHROME_BROWSER_MEDIA_DESKTOP_MEDIA_LIST_H_ diff --git a/chromium_src/chrome/browser/media/desktop_media_list_observer.h b/chromium_src/chrome/browser/media/desktop_media_list_observer.h new file mode 100644 index 000000000000..1988f52b5bca --- /dev/null +++ b/chromium_src/chrome/browser/media/desktop_media_list_observer.h @@ -0,0 +1,22 @@ +// 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_MEDIA_DESKTOP_MEDIA_LIST_OBSERVER_H_ +#define CHROME_BROWSER_MEDIA_DESKTOP_MEDIA_LIST_OBSERVER_H_ + +// Interface implemented by the desktop media picker dialog to receive +// notifications about changes in DesktopMediaList. +class DesktopMediaListObserver { + public: + virtual void OnSourceAdded(int index) = 0; + virtual void OnSourceRemoved(int index) = 0; + virtual void OnSourceMoved(int old_index, int new_index) = 0; + virtual void OnSourceNameChanged(int index) = 0; + virtual void OnSourceThumbnailChanged(int index) = 0; + + protected: + virtual ~DesktopMediaListObserver() {} +}; + +#endif // CHROME_BROWSER_MEDIA_DESKTOP_MEDIA_LIST_OBSERVER_H_ diff --git a/chromium_src/chrome/browser/media/native_desktop_media_list.cc b/chromium_src/chrome/browser/media/native_desktop_media_list.cc new file mode 100644 index 000000000000..1db22ab72db4 --- /dev/null +++ b/chromium_src/chrome/browser/media/native_desktop_media_list.cc @@ -0,0 +1,366 @@ +// 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/media/native_desktop_media_list.h" + +#include +#include +#include + +#include "base/hash.h" +#include "base/logging.h" +#include "base/strings/utf_string_conversions.h" +#include "base/threading/sequenced_worker_pool.h" +#include "chrome/browser/media/desktop_media_list_observer.h" +#include "content/public/browser/browser_thread.h" +#include "media/base/video_util.h" +#include "third_party/libyuv/include/libyuv/scale_argb.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" +#include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" +#include "third_party/webrtc/modules/desktop_capture/window_capturer.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/skia_util.h" + +using content::BrowserThread; +using content::DesktopMediaID; + +namespace { + +// Update the list every second. +const int kDefaultUpdatePeriod = 1000; + +// Returns a hash of a DesktopFrame content to detect when image for a desktop +// media source has changed. +uint32 GetFrameHash(webrtc::DesktopFrame* frame) { + int data_size = frame->stride() * frame->size().height(); + return base::SuperFastHash(reinterpret_cast(frame->data()), data_size); +} + +gfx::ImageSkia ScaleDesktopFrame(scoped_ptr frame, + gfx::Size size) { + gfx::Rect scaled_rect = media::ComputeLetterboxRegion( + gfx::Rect(0, 0, size.width(), size.height()), + gfx::Size(frame->size().width(), frame->size().height())); + + SkBitmap result; + result.allocN32Pixels(scaled_rect.width(), scaled_rect.height(), true); + result.lockPixels(); + + uint8* pixels_data = reinterpret_cast(result.getPixels()); + libyuv::ARGBScale(frame->data(), frame->stride(), + frame->size().width(), frame->size().height(), + pixels_data, result.rowBytes(), + scaled_rect.width(), scaled_rect.height(), + libyuv::kFilterBilinear); + + // Set alpha channel values to 255 for all pixels. + // TODO(sergeyu): Fix screen/window capturers to capture alpha channel and + // remove this code. Currently screen/window capturers (at least some + // implementations) only capture R, G and B channels and set Alpha to 0. + // crbug.com/264424 + for (int y = 0; y < result.height(); ++y) { + for (int x = 0; x < result.width(); ++x) { + pixels_data[result.rowBytes() * y + x * result.bytesPerPixel() + 3] = + 0xff; + } + } + + result.unlockPixels(); + + return gfx::ImageSkia::CreateFrom1xBitmap(result); +} + +} // namespace + +NativeDesktopMediaList::SourceDescription::SourceDescription( + DesktopMediaID id, + const base::string16& name) + : id(id), + name(name) { +} + +class NativeDesktopMediaList::Worker + : public webrtc::DesktopCapturer::Callback { + public: + Worker(base::WeakPtr media_list, + scoped_ptr screen_capturer, + scoped_ptr window_capturer); + ~Worker() override; + + void Refresh(const gfx::Size& thumbnail_size, + content::DesktopMediaID::Id view_dialog_id); + + private: + typedef std::map ImageHashesMap; + + // webrtc::DesktopCapturer::Callback interface. + webrtc::SharedMemory* CreateSharedMemory(size_t size) override; + void OnCaptureCompleted(webrtc::DesktopFrame* frame) override; + + base::WeakPtr media_list_; + + scoped_ptr screen_capturer_; + scoped_ptr window_capturer_; + + scoped_ptr current_frame_; + + ImageHashesMap image_hashes_; + + DISALLOW_COPY_AND_ASSIGN(Worker); +}; + +NativeDesktopMediaList::Worker::Worker( + base::WeakPtr media_list, + scoped_ptr screen_capturer, + scoped_ptr window_capturer) + : media_list_(media_list), + screen_capturer_(screen_capturer.Pass()), + window_capturer_(window_capturer.Pass()) { + if (screen_capturer_) + screen_capturer_->Start(this); + if (window_capturer_) + window_capturer_->Start(this); +} + +NativeDesktopMediaList::Worker::~Worker() {} + +void NativeDesktopMediaList::Worker::Refresh( + const gfx::Size& thumbnail_size, + content::DesktopMediaID::Id view_dialog_id) { + std::vector sources; + + if (screen_capturer_) { + webrtc::ScreenCapturer::ScreenList screens; + if (screen_capturer_->GetScreenList(&screens)) { + bool mutiple_screens = screens.size() > 1; + base::string16 title; + for (size_t i = 0; i < screens.size(); ++i) { + if (mutiple_screens) { + title = base::UTF8ToUTF16("Screen " + base::IntToString(i+1)); + } else { + title = base::UTF8ToUTF16("Entire screen"); + } + sources.push_back(SourceDescription(DesktopMediaID( + DesktopMediaID::TYPE_SCREEN, screens[i].id), title)); + } + } + } + + if (window_capturer_) { + webrtc::WindowCapturer::WindowList windows; + if (window_capturer_->GetWindowList(&windows)) { + for (webrtc::WindowCapturer::WindowList::iterator it = windows.begin(); + it != windows.end(); ++it) { + // Skip the picker dialog window. + if (it->id != view_dialog_id) { + sources.push_back(SourceDescription( + DesktopMediaID(DesktopMediaID::TYPE_WINDOW, it->id), + base::UTF8ToUTF16(it->title))); + } + } + } + } + // Update list of windows before updating thumbnails. + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&NativeDesktopMediaList::OnSourcesList, + media_list_, sources)); + + ImageHashesMap new_image_hashes; + + // Get a thumbnail for each source. + for (size_t i = 0; i < sources.size(); ++i) { + SourceDescription& source = sources[i]; + switch (source.id.type) { + case DesktopMediaID::TYPE_SCREEN: + if (!screen_capturer_->SelectScreen(source.id.id)) + continue; + screen_capturer_->Capture(webrtc::DesktopRegion()); + break; + + case DesktopMediaID::TYPE_WINDOW: + if (!window_capturer_->SelectWindow(source.id.id)) + continue; + window_capturer_->Capture(webrtc::DesktopRegion()); + break; + + default: + NOTREACHED(); + } + + // Expect that DesktopCapturer to always captures frames synchronously. + // |current_frame_| may be NULL if capture failed (e.g. because window has + // been closed). + if (current_frame_) { + uint32 frame_hash = GetFrameHash(current_frame_.get()); + new_image_hashes[source.id] = frame_hash; + + // Scale the image only if it has changed. + ImageHashesMap::iterator it = image_hashes_.find(source.id); + if (it == image_hashes_.end() || it->second != frame_hash) { + gfx::ImageSkia thumbnail = + ScaleDesktopFrame(current_frame_.Pass(), thumbnail_size); + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&NativeDesktopMediaList::OnSourceThumbnail, + media_list_, i, thumbnail)); + } + } + } + + image_hashes_.swap(new_image_hashes); + + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&NativeDesktopMediaList::OnRefreshFinished, media_list_)); +} + +webrtc::SharedMemory* NativeDesktopMediaList::Worker::CreateSharedMemory( + size_t size) { + return NULL; +} + +void NativeDesktopMediaList::Worker::OnCaptureCompleted( + webrtc::DesktopFrame* frame) { + current_frame_.reset(frame); +} + +NativeDesktopMediaList::NativeDesktopMediaList( + scoped_ptr screen_capturer, + scoped_ptr window_capturer) + : screen_capturer_(screen_capturer.Pass()), + window_capturer_(window_capturer.Pass()), + update_period_(base::TimeDelta::FromMilliseconds(kDefaultUpdatePeriod)), + thumbnail_size_(100, 100), + view_dialog_id_(-1), + observer_(NULL), + weak_factory_(this) { + base::SequencedWorkerPool* worker_pool = BrowserThread::GetBlockingPool(); + capture_task_runner_ = worker_pool->GetSequencedTaskRunner( + worker_pool->GetSequenceToken()); +} + +NativeDesktopMediaList::~NativeDesktopMediaList() { + capture_task_runner_->DeleteSoon(FROM_HERE, worker_.release()); +} + +void NativeDesktopMediaList::SetUpdatePeriod(base::TimeDelta period) { + DCHECK(!observer_); + update_period_ = period; +} + +void NativeDesktopMediaList::SetThumbnailSize( + const gfx::Size& thumbnail_size) { + thumbnail_size_ = thumbnail_size; +} + +void NativeDesktopMediaList::SetViewDialogWindowId( + content::DesktopMediaID::Id dialog_id) { + view_dialog_id_ = dialog_id; +} + +void NativeDesktopMediaList::StartUpdating(DesktopMediaListObserver* observer) { + DCHECK(!observer_); + DCHECK(screen_capturer_ || window_capturer_); + + observer_ = observer; + + worker_.reset(new Worker(weak_factory_.GetWeakPtr(), + screen_capturer_.Pass(), window_capturer_.Pass())); + Refresh(); +} + +int NativeDesktopMediaList::GetSourceCount() const { + return sources_.size(); +} + +const DesktopMediaList::Source& NativeDesktopMediaList::GetSource( + int index) const { + return sources_[index]; +} + +void NativeDesktopMediaList::Refresh() { + capture_task_runner_->PostTask( + FROM_HERE, base::Bind(&Worker::Refresh, base::Unretained(worker_.get()), + thumbnail_size_, view_dialog_id_)); +} + +void NativeDesktopMediaList::OnSourcesList( + const std::vector& new_sources) { + typedef std::set SourceSet; + SourceSet new_source_set; + for (size_t i = 0; i < new_sources.size(); ++i) { + new_source_set.insert(new_sources[i].id); + } + // Iterate through the old sources to find the removed sources. + for (size_t i = 0; i < sources_.size(); ++i) { + if (new_source_set.find(sources_[i].id) == new_source_set.end()) { + sources_.erase(sources_.begin() + i); + observer_->OnSourceRemoved(i); + --i; + } + } + // Iterate through the new sources to find the added sources. + if (new_sources.size() > sources_.size()) { + SourceSet old_source_set; + for (size_t i = 0; i < sources_.size(); ++i) { + old_source_set.insert(sources_[i].id); + } + + for (size_t i = 0; i < new_sources.size(); ++i) { + if (old_source_set.find(new_sources[i].id) == old_source_set.end()) { + sources_.insert(sources_.begin() + i, Source()); + sources_[i].id = new_sources[i].id; + sources_[i].name = new_sources[i].name; + observer_->OnSourceAdded(i); + } + } + } + DCHECK_EQ(new_sources.size(), sources_.size()); + + // Find the moved/changed sources. + size_t pos = 0; + while (pos < sources_.size()) { + if (!(sources_[pos].id == new_sources[pos].id)) { + // Find the source that should be moved to |pos|, starting from |pos + 1| + // of |sources_|, because entries before |pos| should have been sorted. + size_t old_pos = pos + 1; + for (; old_pos < sources_.size(); ++old_pos) { + if (sources_[old_pos].id == new_sources[pos].id) + break; + } + DCHECK(sources_[old_pos].id == new_sources[pos].id); + + // Move the source from |old_pos| to |pos|. + Source temp = sources_[old_pos]; + sources_.erase(sources_.begin() + old_pos); + sources_.insert(sources_.begin() + pos, temp); + + observer_->OnSourceMoved(old_pos, pos); + } + + if (sources_[pos].name != new_sources[pos].name) { + sources_[pos].name = new_sources[pos].name; + observer_->OnSourceNameChanged(pos); + } + ++pos; + } +} + +void NativeDesktopMediaList::OnSourceThumbnail( + int index, + const gfx::ImageSkia& image) { + DCHECK_LT(index, static_cast(sources_.size())); + sources_[index].thumbnail = image; + observer_->OnSourceThumbnailChanged(index); +} + +void NativeDesktopMediaList::OnRefreshFinished() { + BrowserThread::PostDelayedTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&NativeDesktopMediaList::Refresh, + weak_factory_.GetWeakPtr()), + update_period_); +} diff --git a/chromium_src/chrome/browser/media/native_desktop_media_list.h b/chromium_src/chrome/browser/media/native_desktop_media_list.h new file mode 100644 index 000000000000..81bd32152813 --- /dev/null +++ b/chromium_src/chrome/browser/media/native_desktop_media_list.h @@ -0,0 +1,100 @@ +// 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_MEDIA_NATIVE_DESKTOP_MEDIA_LIST_H_ +#define CHROME_BROWSER_MEDIA_NATIVE_DESKTOP_MEDIA_LIST_H_ + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/sequenced_task_runner.h" +#include "chrome/browser/media/desktop_media_list.h" +#include "content/public/browser/desktop_media_id.h" +#include "ui/gfx/image/image_skia.h" + +namespace webrtc { +class ScreenCapturer; +class WindowCapturer; +} + +// Implementation of DesktopMediaList that shows native screens and +// native windows. +class NativeDesktopMediaList : public DesktopMediaList { + public: + // Caller may pass NULL for either of the arguments in case when only some + // types of sources the model should be populated with (e.g. it will only + // contain windows, if |screen_capturer| is NULL). + NativeDesktopMediaList( + scoped_ptr screen_capturer, + scoped_ptr window_capturer); + ~NativeDesktopMediaList() override; + + // DesktopMediaList interface. + void SetUpdatePeriod(base::TimeDelta period) override; + void SetThumbnailSize(const gfx::Size& thumbnail_size) override; + void StartUpdating(DesktopMediaListObserver* observer) override; + int GetSourceCount() const override; + const Source& GetSource(int index) const override; + void SetViewDialogWindowId(content::DesktopMediaID::Id dialog_id) override; + + private: + class Worker; + friend class Worker; + + // Struct used to represent sources list the model gets from the Worker. + struct SourceDescription { + SourceDescription(content::DesktopMediaID id, const base::string16& name); + + content::DesktopMediaID id; + base::string16 name; + }; + + // Order comparator for sources. Used to sort list of sources. + static bool CompareSources(const SourceDescription& a, + const SourceDescription& b); + + // Post a task for the |worker_| to update list of windows and get thumbnails. + void Refresh(); + + // Called by |worker_| to refresh the model. First it posts tasks for + // OnSourcesList() with the fresh list of sources, then follows with + // OnSourceThumbnail() for each changed thumbnail and then calls + // OnRefreshFinished() at the end. + void OnSourcesList(const std::vector& sources); + void OnSourceThumbnail(int index, const gfx::ImageSkia& thumbnail); + void OnRefreshFinished(); + + // Capturers specified in SetCapturers() and passed to the |worker_| later. + scoped_ptr screen_capturer_; + scoped_ptr window_capturer_; + + // Time interval between mode updates. + base::TimeDelta update_period_; + + // Size of thumbnails generated by the model. + gfx::Size thumbnail_size_; + + // ID of the hosting dialog. + content::DesktopMediaID::Id view_dialog_id_; + + // The observer passed to StartUpdating(). + DesktopMediaListObserver* observer_; + + // Task runner used for the |worker_|. + scoped_refptr capture_task_runner_; + + // An object that does all the work of getting list of sources on a background + // thread (see |capture_task_runner_|). Destroyed on |capture_task_runner_| + // after the model is destroyed. + scoped_ptr worker_; + + // Current list of sources. + std::vector sources_; + + base::WeakPtrFactory weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(NativeDesktopMediaList); +}; + +#endif // CHROME_BROWSER_MEDIA_NATIVE_DESKTOP_MEDIA_LIST_H_ diff --git a/filenames.gypi b/filenames.gypi index cb6a2273eae3..81d4d87d3aab 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -71,6 +71,8 @@ 'atom/browser/api/atom_api_content_tracing.cc', 'atom/browser/api/atom_api_cookies.cc', 'atom/browser/api/atom_api_cookies.h', + 'atom/browser/api/atom_api_desktop_capturer.cc', + 'atom/browser/api/atom_api_desktop_capturer.h', 'atom/browser/api/atom_api_download_item.cc', 'atom/browser/api/atom_api_download_item.h', 'atom/browser/api/atom_api_dialog.cc', @@ -349,6 +351,10 @@ '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/media/desktop_media_list.h', + 'chromium_src/chrome/browser/media/desktop_media_list_observer.h', + 'chromium_src/chrome/browser/media/native_desktop_media_list.cc', + 'chromium_src/chrome/browser/media/native_desktop_media_list.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', From 48fbd4741645f2518fc8138d886bddded4ba363e Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Sat, 3 Oct 2015 10:41:08 +0800 Subject: [PATCH 02/67] Make desktop capture API work on Windows. --- atom.gyp | 11 +++++++++++ atom/browser/api/atom_api_desktop_capturer.cc | 17 +++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/atom.gyp b/atom.gyp index ed885743c6a6..77ad2e22ae39 100644 --- a/atom.gyp +++ b/atom.gyp @@ -275,8 +275,14 @@ '-lcomctl32.lib', '-lcomdlg32.lib', '-lwininet.lib', + '-lwinmm.lib', ], }, + 'defines': [ + # The usage of "webrtc/modules/desktop_capture/desktop_capture_options.h" + # is required to see this macro. + 'WEBRTC_WIN', + ], 'dependencies': [ # Node is built as static_library on Windows, so we also need to # include its dependencies here. @@ -290,6 +296,11 @@ ], }], # OS=="win" ['OS=="mac"', { + 'defines': [ + # The usage of "webrtc/modules/desktop_capture/desktop_capture_options.h" + # is required to see this macro. + 'WEBRTC_MAC', + ], 'dependencies': [ 'vendor/crashpad/client/client.gyp:crashpad_client', 'vendor/crashpad/handler/handler.gyp:crashpad_handler', diff --git a/atom/browser/api/atom_api_desktop_capturer.cc b/atom/browser/api/atom_api_desktop_capturer.cc index c3a573715703..96786d098912 100644 --- a/atom/browser/api/atom_api_desktop_capturer.cc +++ b/atom/browser/api/atom_api_desktop_capturer.cc @@ -47,10 +47,23 @@ const int kThumbnailHeight = 150; } // namespace DesktopCapturer::DesktopCapturer(bool show_screens, bool show_windows) { + webrtc::DesktopCaptureOptions options = + webrtc::DesktopCaptureOptions::CreateDefault(); + +#if defined(OS_WIN) + // On windows, desktop effects (e.g. Aero) will be disabled when the Desktop + // capture API is active by default. + // We keep the desktop effects in most times. Howerver, the screen still + // fickers when the API is capturing the window due to limitation of current + // implemetation. This is a known and wontFix issue in webrtc (see: + // http://code.google.com/p/webrtc/issues/detail?id=3373) + options.set_disable_effects(false); +#endif + scoped_ptr screen_capturer( - show_screens ? webrtc::ScreenCapturer::Create() : nullptr); + show_screens ? webrtc::ScreenCapturer::Create(options) : nullptr); scoped_ptr window_capturer( - show_windows ? webrtc::WindowCapturer::Create() : nullptr); + show_windows ? webrtc::WindowCapturer::Create(options) : nullptr); media_list_.reset(new NativeDesktopMediaList(screen_capturer.Pass(), window_capturer.Pass())); media_list_->SetThumbnailSize(gfx::Size(kThumbnailWidth, kThumbnailHeight)); From 1e69ef79de55fd4d26161fbb808edef8574c778c Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Sun, 4 Oct 2015 09:35:00 +0800 Subject: [PATCH 03/67] Refine: make desktop-capturer as a renderer module. --- atom/browser/api/atom_api_desktop_capturer.cc | 67 +++++----- atom/browser/api/atom_api_desktop_capturer.h | 17 +-- atom/browser/api/atom_api_screen.cc | 18 +-- atom/browser/api/atom_api_screen.h | 5 - atom/browser/api/lib/app.coffee | 14 +-- atom/browser/lib/desktop-capturer.coffee | 42 +++++++ atom/browser/lib/init.coffee | 3 + atom/renderer/api/lib/desktop-capturer.coffee | 22 ++++ .../media/native_desktop_media_list.cc | 2 +- docs/README.md | 1 + docs/api/desktop-capturer.md | 118 ++++++++++++++++++ filenames.gypi | 2 + 12 files changed, 237 insertions(+), 74 deletions(-) create mode 100644 atom/browser/lib/desktop-capturer.coffee create mode 100644 atom/renderer/api/lib/desktop-capturer.coffee create mode 100644 docs/api/desktop-capturer.md diff --git a/atom/browser/api/atom_api_desktop_capturer.cc b/atom/browser/api/atom_api_desktop_capturer.cc index 96786d098912..f3e05486e9b3 100644 --- a/atom/browser/api/atom_api_desktop_capturer.cc +++ b/atom/browser/api/atom_api_desktop_capturer.cc @@ -5,7 +5,6 @@ #include "atom/browser/api/atom_api_desktop_capturer.h" #include "atom/common/api/atom_api_native_image.h" -#include "atom/common/native_mate_converters/callback.h" #include "atom/common/node_includes.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/media/desktop_media_list.h" @@ -25,7 +24,8 @@ struct Converter { content::DesktopMediaID id = source.id; dict.Set("name", base::UTF16ToUTF8(source.name)); dict.Set("id", id.ToString()); - dict.Set("thumbnail", + dict.Set( + "thumbnail", atom::api::NativeImage::Create(isolate, gfx::Image(source.thumbnail))); return ConvertToV8(isolate, dict); } @@ -38,15 +38,29 @@ namespace atom { namespace api { namespace { -// The wrapDesktopCapturer funtion which is implemented in JavaScript -using WrapDesktopCapturerCallback = base::Callback)>; -WrapDesktopCapturerCallback g_wrap_desktop_capturer; - const int kThumbnailWidth = 150; const int kThumbnailHeight = 150; } // namespace -DesktopCapturer::DesktopCapturer(bool show_screens, bool show_windows) { +DesktopCapturer::DesktopCapturer() { +} + +DesktopCapturer::~DesktopCapturer() { +} + +void DesktopCapturer::StartUpdating(const std::vector& sources) { + bool show_screens = false; + bool show_windows = false; + for (const auto& source_type : sources) { + if (source_type == "screen") + show_screens = true; + else if (source_type == "window") + show_windows = true; + } + + if (!show_windows && !show_screens) + return; + webrtc::DesktopCaptureOptions options = webrtc::DesktopCaptureOptions::CreateDefault(); @@ -70,54 +84,39 @@ DesktopCapturer::DesktopCapturer(bool show_screens, bool show_windows) { media_list_->StartUpdating(this); } -DesktopCapturer::~DesktopCapturer() { -} - -const DesktopMediaList::Source& DesktopCapturer::GetSource(int index) { - return media_list_->GetSource(index); +void DesktopCapturer::StopUpdating() { + media_list_.reset(); } void DesktopCapturer::OnSourceAdded(int index) { - Emit("source-added", index); + Emit("source-added", media_list_->GetSource(index)); } void DesktopCapturer::OnSourceRemoved(int index) { - Emit("source-removed", index); + Emit("source-removed", media_list_->GetSource(index)); } void DesktopCapturer::OnSourceMoved(int old_index, int new_index) { - Emit("source-moved", old_index, new_index); } void DesktopCapturer::OnSourceNameChanged(int index) { - Emit("source-name-changed", index); + Emit("source-name-changed", media_list_->GetSource(index)); } void DesktopCapturer::OnSourceThumbnailChanged(int index) { - Emit("source-thumbnail-changed", index); + Emit("source-thumbnail-changed", media_list_->GetSource(index)); } mate::ObjectTemplateBuilder DesktopCapturer::GetObjectTemplateBuilder( v8::Isolate* isolate) { return mate::ObjectTemplateBuilder(isolate) - .SetMethod("getSource", &DesktopCapturer::GetSource); -} - -void SetWrapDesktopCapturer(const WrapDesktopCapturerCallback& callback) { - g_wrap_desktop_capturer = callback; -} - -void ClearWrapDesktopCapturer() { - g_wrap_desktop_capturer.Reset(); + .SetMethod("startUpdating", &DesktopCapturer::StartUpdating) + .SetMethod("stopUpdating", &DesktopCapturer::StopUpdating); } // static -mate::Handle DesktopCapturer::Create(v8::Isolate* isolate, - bool show_screens, bool show_windows) { - auto handle = mate::CreateHandle(isolate, - new DesktopCapturer(show_screens, show_windows)); - g_wrap_desktop_capturer.Run(handle.ToV8()); - return handle; +mate::Handle DesktopCapturer::Create(v8::Isolate* isolate) { + return mate::CreateHandle(isolate, new DesktopCapturer); } } // namespace api @@ -130,9 +129,7 @@ void Initialize(v8::Local exports, v8::Local unused, v8::Local context, void* priv) { v8::Isolate* isolate = context->GetIsolate(); mate::Dictionary dict(isolate, exports); - dict.SetMethod("_setWrapDesktopCapturer", &atom::api::SetWrapDesktopCapturer); - dict.SetMethod("_clearWrapDesktopCapturer", - &atom::api::ClearWrapDesktopCapturer); + dict.Set("desktopCapturer", atom::api::DesktopCapturer::Create(isolate)); } } // namespace diff --git a/atom/browser/api/atom_api_desktop_capturer.h b/atom/browser/api/atom_api_desktop_capturer.h index aae0a8268b9d..f4be410ed619 100644 --- a/atom/browser/api/atom_api_desktop_capturer.h +++ b/atom/browser/api/atom_api_desktop_capturer.h @@ -2,8 +2,11 @@ // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. -#ifndef ATOM_BROWSER_API_ATOM_API_DESKTOP_CAPTURER_ -#define ATOM_BROWSER_API_ATOM_API_DESKTOP_CAPTURER_ +#ifndef ATOM_BROWSER_API_ATOM_API_DESKTOP_CAPTURER_H_ +#define ATOM_BROWSER_API_ATOM_API_DESKTOP_CAPTURER_H_ + +#include +#include #include "base/memory/scoped_ptr.h" #include "atom/browser/api/event_emitter.h" @@ -18,13 +21,13 @@ namespace api { class DesktopCapturer: public mate::EventEmitter, public DesktopMediaListObserver { public: - static mate::Handle Create(v8::Isolate* isolate, - bool show_screens, bool show_windows); + static mate::Handle Create(v8::Isolate* isolate); - const DesktopMediaList::Source& GetSource(int index); + void StartUpdating(const std::vector& sources); + void StopUpdating(); protected: - DesktopCapturer(bool show_screens, bool show_windows); + DesktopCapturer(); ~DesktopCapturer(); // DesktopMediaListObserver overrides. @@ -48,4 +51,4 @@ class DesktopCapturer: public mate::EventEmitter, } // namespace atom -#endif // ATOM_BROWSER_API_ATOM_API_DESKTOP_CAPTURER_ +#endif // ATOM_BROWSER_API_ATOM_API_DESKTOP_CAPTURER_H_ diff --git a/atom/browser/api/atom_api_screen.cc b/atom/browser/api/atom_api_screen.cc index 761ef28ef97e..b73bda9ced84 100644 --- a/atom/browser/api/atom_api_screen.cc +++ b/atom/browser/api/atom_api_screen.cc @@ -56,21 +56,6 @@ Screen::~Screen() { screen_->RemoveObserver(this); } -mate::Handle Screen::GetDesktopCapturer( - const std::vector& sources) { - bool show_screens = false; - bool show_windows = false; - for (const auto& source_type : sources) { - if (source_type == "screen") { - show_screens = true; - } else if (source_type == "window") { - show_windows = true; - } - } - - return DesktopCapturer::Create(isolate(), show_screens, show_windows); -} - gfx::Point Screen::GetCursorScreenPoint() { return screen_->GetCursorScreenPoint(); } @@ -122,8 +107,7 @@ mate::ObjectTemplateBuilder Screen::GetObjectTemplateBuilder( .SetMethod("getPrimaryDisplay", &Screen::GetPrimaryDisplay) .SetMethod("getAllDisplays", &Screen::GetAllDisplays) .SetMethod("getDisplayNearestPoint", &Screen::GetDisplayNearestPoint) - .SetMethod("getDisplayMatching", &Screen::GetDisplayMatching) - .SetMethod("getDesktopCapturer", &Screen::GetDesktopCapturer); + .SetMethod("getDisplayMatching", &Screen::GetDisplayMatching); } // static diff --git a/atom/browser/api/atom_api_screen.h b/atom/browser/api/atom_api_screen.h index 619f6c8b3f7c..f724130fa7fc 100644 --- a/atom/browser/api/atom_api_screen.h +++ b/atom/browser/api/atom_api_screen.h @@ -6,9 +6,7 @@ #define ATOM_BROWSER_API_ATOM_API_SCREEN_H_ #include -#include -#include "atom/browser/api/atom_api_desktop_capturer.h" #include "atom/browser/api/event_emitter.h" #include "native_mate/handle.h" #include "ui/gfx/display_observer.h" @@ -38,9 +36,6 @@ class Screen : public mate::EventEmitter, gfx::Display GetDisplayNearestPoint(const gfx::Point& point); gfx::Display GetDisplayMatching(const gfx::Rect& match_rect); - mate::Handle GetDesktopCapturer( - const std::vector& sources); - // gfx::DisplayObserver: void OnDisplayAdded(const gfx::Display& new_display) override; void OnDisplayRemoved(const gfx::Display& old_display) override; diff --git a/atom/browser/api/lib/app.coffee b/atom/browser/api/lib/app.coffee index 9ff568cf8d26..18c80dc2b1f4 100644 --- a/atom/browser/api/lib/app.coffee +++ b/atom/browser/api/lib/app.coffee @@ -3,18 +3,17 @@ EventEmitter = require('events').EventEmitter bindings = process.atomBinding 'app' sessionBindings = process.atomBinding 'session' downloadItemBindings = process.atomBinding 'download_item' -desktopCapturerBindings = process.atomBinding 'desktop_capturer' app = bindings.app app.__proto__ = EventEmitter.prototype -wrapToEventListener = (item) -> - # item is an Event Emitter. - item.__proto__ = EventEmitter.prototype +wrapSession = (session) -> + # session is an Event Emitter. + session.__proto__ = EventEmitter.prototype wrapDownloadItem = (download_item) -> # download_item is an Event Emitter. - wrapToEventListener download_item + download_item.__proto__ = EventEmitter.prototype # Be compatible with old APIs. download_item.url = download_item.getUrl() download_item.filename = download_item.getFilename() @@ -59,14 +58,11 @@ app.resolveProxy = -> @defaultSession.resolveProxy.apply @defaultSession, argume app.on 'activate', (event, hasVisibleWindows) -> @emit 'activate-with-no-open-windows' if not hasVisibleWindows # Session wrapper. -sessionBindings._setWrapSession wrapToEventListener +sessionBindings._setWrapSession wrapSession process.once 'exit', sessionBindings._clearWrapSession downloadItemBindings._setWrapDownloadItem wrapDownloadItem process.once 'exit', downloadItemBindings._clearWrapDownloadItem -desktopCapturerBindings._setWrapDesktopCapturer wrapToEventListener -process.once 'exit', desktopCapturerBindings._clearWrapDesktopCapturer - # Only one App object pemitted. module.exports = app diff --git a/atom/browser/lib/desktop-capturer.coffee b/atom/browser/lib/desktop-capturer.coffee new file mode 100644 index 000000000000..29bb1ae60518 --- /dev/null +++ b/atom/browser/lib/desktop-capturer.coffee @@ -0,0 +1,42 @@ +ipc = require 'ipc' +BrowserWindow = require 'browser-window' +EventEmitter = require('events').EventEmitter + +# The browser module manages all desktop-capturer moduels in renderer process. +desktopCapturer = process.atomBinding('desktop_capturer').desktopCapturer +desktopCapturer.__proto__ = EventEmitter.prototype + +getWebContentsFromId = (id) -> + windows = BrowserWindow.getAllWindows() + return window.webContents for window in windows when window.webContents?.getId() == id + +# The set for tracking id of webContents. +webContentsIds = new Set + +stopDesktopCapture = (id) -> + webContentsIds.delete id + if webContentsIds.size is 0 + desktopCapturer.stopUpdating() + +ipc.on 'ATOM_BROWSER_DESKTOP_CAPTURER_REQUIRED', (event) -> + id = event.sender.getId() + # Remove the tracked webContents when it is destroyed. + getWebContentsFromId(id).on 'destroyed', ()-> + stopDesktopCapture id + event.returnValue = 'done' + +# Handle `desktopCapturer.startUpdating` API. +ipc.on 'ATOM_BROWSER_DESKTOP_CAPTURER_START_UPDATING', (event, args) -> + id = event.sender.getId() + webContentsIds.add id + desktopCapturer.startUpdating args + +# Handle `desktopCapturer.stopUpdating` API. +ipc.on 'ATOM_BROWSER_DESKTOP_CAPTURER_STOP_UPDATING', (event) -> + stopDesktopCapture event.sender.getId() + +for event_name in ['source-added', 'source-removed', 'source-name-changed', "source-thumbnail-changed"] + do (event_name) -> + desktopCapturer.on event_name, (event, source) -> + webContentsIds.forEach (id) -> + getWebContentsFromId(id).send event_name, { id: source.id, name: source.name, dataUrl: source.thumbnail.toDataUrl() } diff --git a/atom/browser/lib/init.coffee b/atom/browser/lib/init.coffee index 1299364d2fa6..6caaaf4bf056 100644 --- a/atom/browser/lib/init.coffee +++ b/atom/browser/lib/init.coffee @@ -92,6 +92,9 @@ app.setAppPath packagePath # Load the chrome extension support. require './chrome-extension' +# Load internal desktop-capturer module. +require './desktop-capturer' + # Set main startup script of the app. mainStartupScript = packageJson.main or 'index.js' diff --git a/atom/renderer/api/lib/desktop-capturer.coffee b/atom/renderer/api/lib/desktop-capturer.coffee new file mode 100644 index 000000000000..bf2d27597a08 --- /dev/null +++ b/atom/renderer/api/lib/desktop-capturer.coffee @@ -0,0 +1,22 @@ +ipc = require 'ipc' +remote = require 'remote' +NativeImage = require 'native-image' + +EventEmitter = require('events').EventEmitter +desktopCapturer = new EventEmitter + +# Tells main process the renderer is requiring 'desktop-capture' module. +ipc.sendSync 'ATOM_BROWSER_DESKTOP_CAPTURER_REQUIRED' + +desktopCapturer.startUpdating = (args) -> + ipc.send 'ATOM_BROWSER_DESKTOP_CAPTURER_START_UPDATING', args + +desktopCapturer.stopUpdating = () -> + ipc.send 'ATOM_BROWSER_DESKTOP_CAPTURER_STOP_UPDATING' + +for event_name in ['source-added', 'source-removed', 'source-name-changed', "source-thumbnail-changed"] + do (event_name) -> + ipc.on event_name, (source) -> + desktopCapturer.emit event_name, { id: source.id, name: source.name, thumbnail: NativeImage.createFromDataUrl source.dataUrl } + +module.exports = desktopCapturer diff --git a/chromium_src/chrome/browser/media/native_desktop_media_list.cc b/chromium_src/chrome/browser/media/native_desktop_media_list.cc index 1db22ab72db4..050c5e1d5a78 100644 --- a/chromium_src/chrome/browser/media/native_desktop_media_list.cc +++ b/chromium_src/chrome/browser/media/native_desktop_media_list.cc @@ -297,8 +297,8 @@ void NativeDesktopMediaList::OnSourcesList( // Iterate through the old sources to find the removed sources. for (size_t i = 0; i < sources_.size(); ++i) { if (new_source_set.find(sources_[i].id) == new_source_set.end()) { - sources_.erase(sources_.begin() + i); observer_->OnSourceRemoved(i); + sources_.erase(sources_.begin() + i); --i; } } diff --git a/docs/README.md b/docs/README.md index b2f95fe4b579..cc25e9d0ff66 100644 --- a/docs/README.md +++ b/docs/README.md @@ -46,6 +46,7 @@ ### Modules for the Renderer Process (Web Page): +* [desktop-capturer](api/desktop-capturer.md) * [ipc (renderer)](api/ipc-renderer.md) * [remote](api/remote.md) * [web-frame](api/web-frame.md) diff --git a/docs/api/desktop-capturer.md b/docs/api/desktop-capturer.md new file mode 100644 index 000000000000..8862762ddabb --- /dev/null +++ b/docs/api/desktop-capturer.md @@ -0,0 +1,118 @@ +# desktop-capturer + +The `desktop-capturer` is a renderer module used to capture the content of +screen and individual app windows. + +```javascript +// In the renderer process. +var desktopCapturer = require('desktop-capturer'); + +desktopCapturer.on('source-added', function(source) { + console.log("source " + source.name + " is added."); + // source.thumbnail is not ready to use here and webkitGetUserMedia neither. +}); + +desktopCapturer.on('source-thumbnail-changed', function(source) { + if (source.name == "Electron") { + // stopUpdating since we have found the window that we want to capture. + desktopCapturer.stopUpdating(); + + // It's ready to use webkitGetUserMedia right now. + navigator.webkitGetUserMedia({ + audio: false, + video: { + mandatory: { + chromeMediaSource: 'desktop', + chromeMediaSourceId: source.id, + minWidth: 1280, + maxWidth: 1280, + minHeight: 720, + maxHeight: 720 + } + } + }, gotStream, getUserMediaError); + } +}); + +// Let's start updating after setting all event of `desktopCapturer` +desktopCapturer.startUpdating(); + +function gotStream(stream) { + document.querySelector('video').src = URL.createObjectURL(stream); +} + +function getUserMediaError(e) { + console.log('getUserMediaError'); +} +``` + +## Events + +### Event: 'source-added' + +* `source` Source + +Emits when there is a new source added, usually a new window is created, +a new screen is attached. + +**Note:** The thumbnail of the source is not ready for use when 'source-added' +event is emitted, and `navigator.webkitGetUserMedia` neither. + +### Event: 'source-removed' + +* `source` Source + +Emits when there is a source removed. + +### Event: 'source-name-changed' + +* `source` Source + +Emits when the name of source is changed. + +### Event: 'source-thumbnail-changed' + +* `source` Source + +Emits when the thumbnail of source is changed. `desktopCapturer` will refresh +all sources every second. + +## Methods + +The `desktopCapturer` module has the following methods: + +### `desktopCapturer.startUpdating(options)` + +* `options` Array - An array of String that enums the types of desktop sources. + * `screen` String - Screen + * `window` String - Individual window + +Starts updating desktopCapturer. The events of `desktopCapturer` will only be +emitted after `startUpdating` API is invoked. + +**Note:** At beginning, the desktopCapturer is initially empty, so the +`source-added` event will be emitted for each existing source as it is +enumrated. +On Windows, you will see the screen ficker when desktopCapturer starts updating. +This is normal because the desktop effects(e.g. Aero) will be disabled when +desktop capturer is working. The ficker will disappear once +`desktopCapturer.stopUpdating()` is invoked. + +### `desktopCapturer.stopUpdating()` + +Stops updating desktopCapturer. The events of `desktopCapturer` will not be +emitted after the API is invoked. + +**Note:** It is a good practice to call `stopUpdating` when you do not need +getting any infomation of sources, usually after passing a id of source to +`navigator.webkitGetUserMedia`. + +## Source + +`Source` is an object represents a captured screen or individual window. It has +following properties: + +* `id` String - The id of the capturing window or screen used in + `navigator.webkitGetUserMedia`. +* `name` String - The descriped name of the capturing screen or window. +* `thumbnail` [NativeImage](NativeImage.md) - A thumbnail image. diff --git a/filenames.gypi b/filenames.gypi index 81d4d87d3aab..46e06bebd183 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -26,6 +26,7 @@ 'atom/browser/api/lib/tray.coffee', 'atom/browser/api/lib/web-contents.coffee', 'atom/browser/lib/chrome-extension.coffee', + 'atom/browser/lib/desktop-capturer.coffee', 'atom/browser/lib/guest-view-manager.coffee', 'atom/browser/lib/guest-window-manager.coffee', 'atom/browser/lib/init.coffee', @@ -45,6 +46,7 @@ 'atom/renderer/lib/web-view/web-view.coffee', 'atom/renderer/lib/web-view/web-view-attributes.coffee', 'atom/renderer/lib/web-view/web-view-constants.coffee', + 'atom/renderer/api/lib/desktop-capturer.coffee', 'atom/renderer/api/lib/ipc.coffee', 'atom/renderer/api/lib/remote.coffee', 'atom/renderer/api/lib/screen.coffee', From 36c0ad7fda2abf9476fd90c54580c2ed71edbffd Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Mon, 5 Oct 2015 11:32:12 +0800 Subject: [PATCH 04/67] Refine more about desktop capturer API. * Simplify the coffeescript code. * Add more options in desktopCapturer.startUpdating. --- atom.gyp | 10 --- atom/browser/api/atom_api_desktop_capturer.cc | 64 +++++++++++------- atom/browser/api/atom_api_desktop_capturer.h | 10 ++- atom/browser/lib/desktop-capturer.coffee | 26 ++++---- atom/renderer/api/lib/desktop-capturer.coffee | 11 ++-- .../media/desktop_media_list_observer.h | 1 + .../media/native_desktop_media_list.cc | 1 + docs/api/desktop-capturer.md | 65 +++++++++++-------- 8 files changed, 104 insertions(+), 84 deletions(-) diff --git a/atom.gyp b/atom.gyp index 77ad2e22ae39..b2e55e9be308 100644 --- a/atom.gyp +++ b/atom.gyp @@ -278,11 +278,6 @@ '-lwinmm.lib', ], }, - 'defines': [ - # The usage of "webrtc/modules/desktop_capture/desktop_capture_options.h" - # is required to see this macro. - 'WEBRTC_WIN', - ], 'dependencies': [ # Node is built as static_library on Windows, so we also need to # include its dependencies here. @@ -296,11 +291,6 @@ ], }], # OS=="win" ['OS=="mac"', { - 'defines': [ - # The usage of "webrtc/modules/desktop_capture/desktop_capture_options.h" - # is required to see this macro. - 'WEBRTC_MAC', - ], 'dependencies': [ 'vendor/crashpad/client/client.gyp:crashpad_client', 'vendor/crashpad/handler/handler.gyp:crashpad_handler', diff --git a/atom/browser/api/atom_api_desktop_capturer.cc b/atom/browser/api/atom_api_desktop_capturer.cc index f3e05486e9b3..a6556f6a89fa 100644 --- a/atom/browser/api/atom_api_desktop_capturer.cc +++ b/atom/browser/api/atom_api_desktop_capturer.cc @@ -14,30 +14,13 @@ #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" #include "third_party/webrtc/modules/desktop_capture/window_capturer.h" -namespace mate { - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - const DesktopMediaList::Source& source) { - mate::Dictionary dict(isolate, v8::Object::New(isolate)); - content::DesktopMediaID id = source.id; - dict.Set("name", base::UTF16ToUTF8(source.name)); - dict.Set("id", id.ToString()); - dict.Set( - "thumbnail", - atom::api::NativeImage::Create(isolate, gfx::Image(source.thumbnail))); - return ConvertToV8(isolate, dict); - } -}; - -} // namespace mate - namespace atom { namespace api { namespace { +// Refresh every second. +const int kUpdatePeriod = 1000; const int kThumbnailWidth = 150; const int kThumbnailHeight = 150; } // namespace @@ -48,7 +31,11 @@ DesktopCapturer::DesktopCapturer() { DesktopCapturer::~DesktopCapturer() { } -void DesktopCapturer::StartUpdating(const std::vector& sources) { +void DesktopCapturer::StartUpdating(const mate::Dictionary& args) { + std::vector sources; + if (!args.Get("types", &sources)) + return; + bool show_screens = false; bool show_windows = false; for (const auto& source_type : sources) { @@ -80,7 +67,16 @@ void DesktopCapturer::StartUpdating(const std::vector& sources) { show_windows ? webrtc::WindowCapturer::Create(options) : nullptr); media_list_.reset(new NativeDesktopMediaList(screen_capturer.Pass(), window_capturer.Pass())); - media_list_->SetThumbnailSize(gfx::Size(kThumbnailWidth, kThumbnailHeight)); + + int update_period = kUpdatePeriod; + int thumbnail_width = kThumbnailWidth, thumbnail_height = kThumbnailHeight; + args.Get("updatePeriod", &update_period); + args.Get("thumbnailWidth", &thumbnail_width); + args.Get("thumbnailHeight", &thumbnail_height); + + media_list_->SetUpdatePeriod(base::TimeDelta::FromMilliseconds( + update_period)); + media_list_->SetThumbnailSize(gfx::Size(thumbnail_width, thumbnail_height)); media_list_->StartUpdating(this); } @@ -89,22 +85,40 @@ void DesktopCapturer::StopUpdating() { } void DesktopCapturer::OnSourceAdded(int index) { - Emit("source-added", media_list_->GetSource(index)); + EmitDesktopCapturerEvent("source-added", index, false); } void DesktopCapturer::OnSourceRemoved(int index) { - Emit("source-removed", media_list_->GetSource(index)); + EmitDesktopCapturerEvent("source-removed", index, false); } +// Ignore this event. void DesktopCapturer::OnSourceMoved(int old_index, int new_index) { } void DesktopCapturer::OnSourceNameChanged(int index) { - Emit("source-name-changed", media_list_->GetSource(index)); + EmitDesktopCapturerEvent("source-removed", index, false); } void DesktopCapturer::OnSourceThumbnailChanged(int index) { - Emit("source-thumbnail-changed", media_list_->GetSource(index)); + EmitDesktopCapturerEvent("source-thumbnail-changed", index, true); +} + +void DesktopCapturer::OnRefreshFinished() { + Emit("refresh-finished"); +} + +void DesktopCapturer::EmitDesktopCapturerEvent( + const std::string& event_name, int index, bool with_thumbnail) { + const DesktopMediaList::Source& source = media_list_->GetSource(index); + content::DesktopMediaID id = source.id; + if (!with_thumbnail) + Emit(event_name, id.ToString(), base::UTF16ToUTF8(source.name)); + else { + Emit(event_name, id.ToString(), base::UTF16ToUTF8(source.name), + atom::api::NativeImage::Create(isolate(), + gfx::Image(source.thumbnail))); + } } mate::ObjectTemplateBuilder DesktopCapturer::GetObjectTemplateBuilder( diff --git a/atom/browser/api/atom_api_desktop_capturer.h b/atom/browser/api/atom_api_desktop_capturer.h index f4be410ed619..f0620c8e9cf8 100644 --- a/atom/browser/api/atom_api_desktop_capturer.h +++ b/atom/browser/api/atom_api_desktop_capturer.h @@ -14,6 +14,10 @@ #include "chrome/browser/media/native_desktop_media_list.h" #include "native_mate/handle.h" +namespace mate { +class Dictionary; +} + namespace atom { namespace api { @@ -23,7 +27,8 @@ class DesktopCapturer: public mate::EventEmitter, public: static mate::Handle Create(v8::Isolate* isolate); - void StartUpdating(const std::vector& sources); + void StartUpdating(const mate::Dictionary& args); + void StopUpdating(); protected: @@ -36,8 +41,11 @@ class DesktopCapturer: public mate::EventEmitter, void OnSourceMoved(int old_index, int new_index) override; void OnSourceNameChanged(int index) override; void OnSourceThumbnailChanged(int index) override; + void OnRefreshFinished() override; private: + void EmitDesktopCapturerEvent( + const std::string& event_name, int index, bool with_thumbnail); // mate::Wrappable: mate::ObjectTemplateBuilder GetObjectTemplateBuilder( v8::Isolate* isolate) override; diff --git a/atom/browser/lib/desktop-capturer.coffee b/atom/browser/lib/desktop-capturer.coffee index 29bb1ae60518..0177d9721bb5 100644 --- a/atom/browser/lib/desktop-capturer.coffee +++ b/atom/browser/lib/desktop-capturer.coffee @@ -1,10 +1,8 @@ ipc = require 'ipc' BrowserWindow = require 'browser-window' -EventEmitter = require('events').EventEmitter # The browser module manages all desktop-capturer moduels in renderer process. desktopCapturer = process.atomBinding('desktop_capturer').desktopCapturer -desktopCapturer.__proto__ = EventEmitter.prototype getWebContentsFromId = (id) -> windows = BrowserWindow.getAllWindows() @@ -15,28 +13,26 @@ webContentsIds = new Set stopDesktopCapture = (id) -> webContentsIds.delete id + # Stop updating if no renderer process listens the desktop capturer. if webContentsIds.size is 0 desktopCapturer.stopUpdating() -ipc.on 'ATOM_BROWSER_DESKTOP_CAPTURER_REQUIRED', (event) -> - id = event.sender.getId() - # Remove the tracked webContents when it is destroyed. - getWebContentsFromId(id).on 'destroyed', ()-> - stopDesktopCapture id - event.returnValue = 'done' - # Handle `desktopCapturer.startUpdating` API. ipc.on 'ATOM_BROWSER_DESKTOP_CAPTURER_START_UPDATING', (event, args) -> id = event.sender.getId() + if not webContentsIds.has id + # Stop sending desktop capturer events to the destroyed webContents. + event.sender.on 'destroyed', ()-> + stopDesktopCapture id + # Start updating the desktopCapturer if it doesn't. + if webContentsIds.size is 0 + desktopCapturer.startUpdating args webContentsIds.add id - desktopCapturer.startUpdating args # Handle `desktopCapturer.stopUpdating` API. ipc.on 'ATOM_BROWSER_DESKTOP_CAPTURER_STOP_UPDATING', (event) -> stopDesktopCapture event.sender.getId() -for event_name in ['source-added', 'source-removed', 'source-name-changed', "source-thumbnail-changed"] - do (event_name) -> - desktopCapturer.on event_name, (event, source) -> - webContentsIds.forEach (id) -> - getWebContentsFromId(id).send event_name, { id: source.id, name: source.name, dataUrl: source.thumbnail.toDataUrl() } +desktopCapturer.emit = (event_name, event, desktopId, name, thumbnail) -> + webContentsIds.forEach (id) -> + getWebContentsFromId(id).send 'ATOM_RENDERER_DESKTOP_CAPTURER', event_name, desktopId, name, thumbnail?.toDataUrl() diff --git a/atom/renderer/api/lib/desktop-capturer.coffee b/atom/renderer/api/lib/desktop-capturer.coffee index bf2d27597a08..ae5e054c2a75 100644 --- a/atom/renderer/api/lib/desktop-capturer.coffee +++ b/atom/renderer/api/lib/desktop-capturer.coffee @@ -5,18 +5,15 @@ NativeImage = require 'native-image' EventEmitter = require('events').EventEmitter desktopCapturer = new EventEmitter -# Tells main process the renderer is requiring 'desktop-capture' module. -ipc.sendSync 'ATOM_BROWSER_DESKTOP_CAPTURER_REQUIRED' - desktopCapturer.startUpdating = (args) -> ipc.send 'ATOM_BROWSER_DESKTOP_CAPTURER_START_UPDATING', args desktopCapturer.stopUpdating = () -> ipc.send 'ATOM_BROWSER_DESKTOP_CAPTURER_STOP_UPDATING' -for event_name in ['source-added', 'source-removed', 'source-name-changed', "source-thumbnail-changed"] - do (event_name) -> - ipc.on event_name, (source) -> - desktopCapturer.emit event_name, { id: source.id, name: source.name, thumbnail: NativeImage.createFromDataUrl source.dataUrl } +ipc.on 'ATOM_RENDERER_DESKTOP_CAPTURER', (event_name, id, name, thumbnail) -> + if not thumbnail + return desktopCapturer.emit event_name, id, name + desktopCapturer.emit event_name, id, name, NativeImage.createFromDataUrl thumbnail module.exports = desktopCapturer diff --git a/chromium_src/chrome/browser/media/desktop_media_list_observer.h b/chromium_src/chrome/browser/media/desktop_media_list_observer.h index 1988f52b5bca..eccaa407d2df 100644 --- a/chromium_src/chrome/browser/media/desktop_media_list_observer.h +++ b/chromium_src/chrome/browser/media/desktop_media_list_observer.h @@ -14,6 +14,7 @@ class DesktopMediaListObserver { virtual void OnSourceMoved(int old_index, int new_index) = 0; virtual void OnSourceNameChanged(int index) = 0; virtual void OnSourceThumbnailChanged(int index) = 0; + virtual void OnRefreshFinished() = 0; protected: virtual ~DesktopMediaListObserver() {} diff --git a/chromium_src/chrome/browser/media/native_desktop_media_list.cc b/chromium_src/chrome/browser/media/native_desktop_media_list.cc index 050c5e1d5a78..a326ded91b80 100644 --- a/chromium_src/chrome/browser/media/native_desktop_media_list.cc +++ b/chromium_src/chrome/browser/media/native_desktop_media_list.cc @@ -358,6 +358,7 @@ void NativeDesktopMediaList::OnSourceThumbnail( } void NativeDesktopMediaList::OnRefreshFinished() { + observer_->OnRefreshFinished(); BrowserThread::PostDelayedTask( BrowserThread::UI, FROM_HERE, base::Bind(&NativeDesktopMediaList::Refresh, diff --git a/docs/api/desktop-capturer.md b/docs/api/desktop-capturer.md index 8862762ddabb..6dc971cd2066 100644 --- a/docs/api/desktop-capturer.md +++ b/docs/api/desktop-capturer.md @@ -7,13 +7,13 @@ screen and individual app windows. // In the renderer process. var desktopCapturer = require('desktop-capturer'); -desktopCapturer.on('source-added', function(source) { - console.log("source " + source.name + " is added."); - // source.thumbnail is not ready to use here and webkitGetUserMedia neither. +desktopCapturer.on('source-added', function(id, name) { + console.log("source " + name + " is added."); + // navigator.webkitGetUserMedia is not ready for use now. }); -desktopCapturer.on('source-thumbnail-changed', function(source) { - if (source.name == "Electron") { +desktopCapturer.on('source-thumbnail-changed', function(id, name, thumbnail) { + if (name == "Electron") { // stopUpdating since we have found the window that we want to capture. desktopCapturer.stopUpdating(); @@ -23,7 +23,7 @@ desktopCapturer.on('source-thumbnail-changed', function(source) { video: { mandatory: { chromeMediaSource: 'desktop', - chromeMediaSourceId: source.id, + chromeMediaSourceId: id, minWidth: 1280, maxWidth: 1280, minHeight: 720, @@ -50,42 +50,65 @@ function getUserMediaError(e) { ### Event: 'source-added' -* `source` Source +* `id` String - The id of the captured window or screen used in + `navigator.webkitGetUserMedia`. The format looks like 'window:XX' or + 'screen:XX' where XX is a random generated number. +* `name` String - The descriped name of the capturing screen or window. If the + source is a screen, the name will be 'Entire Screen' or 'Screen '; if + it is a window, the name will be the window's title. -Emits when there is a new source added, usually a new window is created, -a new screen is attached. +Emits when there is a new source added, usually a new window is created or a new +screen is attached. -**Note:** The thumbnail of the source is not ready for use when 'source-added' -event is emitted, and `navigator.webkitGetUserMedia` neither. +**Note:** `navigator.webkitGetUserMedia` is not ready for use in this event. ### Event: 'source-removed' -* `source` Source +* `id` String - The id of the captured window or screen used in + `navigator.webkitGetUserMedia`. +* `name` String - The descriped name of the capturing screen or window. Emits when there is a source removed. ### Event: 'source-name-changed' -* `source` Source +* `id` String - The id of the captured window or screen used in + `navigator.webkitGetUserMedia`. +* `name` String - The descriped name of the capturing screen or window. Emits when the name of source is changed. ### Event: 'source-thumbnail-changed' -* `source` Source +* `id` String - The id of the captured window or screen used in + `navigator.webkitGetUserMedia`. +* `name` String - The descriped name of the capturing screen or window. +* `thumbnail` [NativeImage](NativeImage.md) - A thumbnail image. Emits when the thumbnail of source is changed. `desktopCapturer` will refresh all sources every second. +### Event: 'refresh-finished' + +Emits when `desktopCapturer` finishes a refresh. + ## Methods The `desktopCapturer` module has the following methods: ### `desktopCapturer.startUpdating(options)` -* `options` Array - An array of String that enums the types of desktop sources. +`options` Object, properties: + +* `types` Array - An array of String that enums the types of desktop sources. * `screen` String - Screen * `window` String - Individual window +* `updatePeriod` Integer (optional) - The update period in milliseconds. By + default, `desktopCapturer` updates every second. +* `thumbnailWidth` Integer (optional) - The width of thumbnail. By default, it + is 150px. +* `thumbnailHeight` Integer (optional) - The height of thumbnail. By default, it + is 150px. Starts updating desktopCapturer. The events of `desktopCapturer` will only be emitted after `startUpdating` API is invoked. @@ -104,15 +127,5 @@ Stops updating desktopCapturer. The events of `desktopCapturer` will not be emitted after the API is invoked. **Note:** It is a good practice to call `stopUpdating` when you do not need -getting any infomation of sources, usually after passing a id of source to +getting any infomation of sources, usually after passing a id to `navigator.webkitGetUserMedia`. - -## Source - -`Source` is an object represents a captured screen or individual window. It has -following properties: - -* `id` String - The id of the capturing window or screen used in - `navigator.webkitGetUserMedia`. -* `name` String - The descriped name of the capturing screen or window. -* `thumbnail` [NativeImage](NativeImage.md) - A thumbnail image. From dcb457e76ecc7ec530f9ececa5af2974ab5d17a5 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Tue, 6 Oct 2015 14:34:54 +0800 Subject: [PATCH 05/67] Refine API design: desktopCapturer.getSources. --- atom/browser/api/atom_api_desktop_capturer.cc | 69 ++++----- atom/browser/api/atom_api_desktop_capturer.h | 8 +- atom/browser/lib/desktop-capturer.coffee | 58 +++---- atom/renderer/api/lib/desktop-capturer.coffee | 21 +-- .../media/desktop_media_list_observer.h | 2 +- .../media/native_desktop_media_list.cc | 15 +- docs/api/desktop-capturer.md | 145 ++++++------------ 7 files changed, 124 insertions(+), 194 deletions(-) diff --git a/atom/browser/api/atom_api_desktop_capturer.cc b/atom/browser/api/atom_api_desktop_capturer.cc index a6556f6a89fa..116b0f4debf0 100644 --- a/atom/browser/api/atom_api_desktop_capturer.cc +++ b/atom/browser/api/atom_api_desktop_capturer.cc @@ -6,6 +6,7 @@ #include "atom/common/api/atom_api_native_image.h" #include "atom/common/node_includes.h" +#include "atom/common/native_mate_converters/gfx_converter.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/media/desktop_media_list.h" #include "native_mate/dictionary.h" @@ -14,13 +15,30 @@ #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" #include "third_party/webrtc/modules/desktop_capture/window_capturer.h" +namespace mate { + +template<> +struct Converter { + static v8::Local ToV8(v8::Isolate* isolate, + const DesktopMediaList::Source& source) { + mate::Dictionary dict(isolate, v8::Object::New(isolate)); + content::DesktopMediaID id = source.id; + dict.Set("name", base::UTF16ToUTF8(source.name)); + dict.Set("id", id.ToString()); + dict.Set( + "thumbnail", + atom::api::NativeImage::Create(isolate, gfx::Image(source.thumbnail))); + return ConvertToV8(isolate, dict); + } +}; + +} // namespace mate + namespace atom { namespace api { namespace { -// Refresh every second. -const int kUpdatePeriod = 1000; const int kThumbnailWidth = 150; const int kThumbnailHeight = 150; } // namespace @@ -31,7 +49,7 @@ DesktopCapturer::DesktopCapturer() { DesktopCapturer::~DesktopCapturer() { } -void DesktopCapturer::StartUpdating(const mate::Dictionary& args) { +void DesktopCapturer::StartHandling(const mate::Dictionary& args) { std::vector sources; if (!args.Get("types", &sources)) return; @@ -68,64 +86,41 @@ void DesktopCapturer::StartUpdating(const mate::Dictionary& args) { media_list_.reset(new NativeDesktopMediaList(screen_capturer.Pass(), window_capturer.Pass())); - int update_period = kUpdatePeriod; - int thumbnail_width = kThumbnailWidth, thumbnail_height = kThumbnailHeight; - args.Get("updatePeriod", &update_period); - args.Get("thumbnailWidth", &thumbnail_width); - args.Get("thumbnailHeight", &thumbnail_height); + gfx::Size thumbnail_size(kThumbnailWidth, kThumbnailHeight); + args.Get("thumbnailSize", &thumbnail_size); - media_list_->SetUpdatePeriod(base::TimeDelta::FromMilliseconds( - update_period)); - media_list_->SetThumbnailSize(gfx::Size(thumbnail_width, thumbnail_height)); + media_list_->SetThumbnailSize(thumbnail_size); media_list_->StartUpdating(this); } -void DesktopCapturer::StopUpdating() { - media_list_.reset(); -} - void DesktopCapturer::OnSourceAdded(int index) { - EmitDesktopCapturerEvent("source-added", index, false); } void DesktopCapturer::OnSourceRemoved(int index) { - EmitDesktopCapturerEvent("source-removed", index, false); } -// Ignore this event. void DesktopCapturer::OnSourceMoved(int old_index, int new_index) { } void DesktopCapturer::OnSourceNameChanged(int index) { - EmitDesktopCapturerEvent("source-removed", index, false); } void DesktopCapturer::OnSourceThumbnailChanged(int index) { - EmitDesktopCapturerEvent("source-thumbnail-changed", index, true); } -void DesktopCapturer::OnRefreshFinished() { - Emit("refresh-finished"); -} - -void DesktopCapturer::EmitDesktopCapturerEvent( - const std::string& event_name, int index, bool with_thumbnail) { - const DesktopMediaList::Source& source = media_list_->GetSource(index); - content::DesktopMediaID id = source.id; - if (!with_thumbnail) - Emit(event_name, id.ToString(), base::UTF16ToUTF8(source.name)); - else { - Emit(event_name, id.ToString(), base::UTF16ToUTF8(source.name), - atom::api::NativeImage::Create(isolate(), - gfx::Image(source.thumbnail))); - } +bool DesktopCapturer::OnRefreshFinished() { + std::vector sources; + for (int i = 0; i < media_list_->GetSourceCount(); ++i) + sources.push_back(media_list_->GetSource(i)); + media_list_.reset(); + Emit("refresh-finished", sources); + return false; } mate::ObjectTemplateBuilder DesktopCapturer::GetObjectTemplateBuilder( v8::Isolate* isolate) { return mate::ObjectTemplateBuilder(isolate) - .SetMethod("startUpdating", &DesktopCapturer::StartUpdating) - .SetMethod("stopUpdating", &DesktopCapturer::StopUpdating); + .SetMethod("startHandling", &DesktopCapturer::StartHandling); } // static diff --git a/atom/browser/api/atom_api_desktop_capturer.h b/atom/browser/api/atom_api_desktop_capturer.h index f0620c8e9cf8..32687abf7367 100644 --- a/atom/browser/api/atom_api_desktop_capturer.h +++ b/atom/browser/api/atom_api_desktop_capturer.h @@ -27,9 +27,7 @@ class DesktopCapturer: public mate::EventEmitter, public: static mate::Handle Create(v8::Isolate* isolate); - void StartUpdating(const mate::Dictionary& args); - - void StopUpdating(); + void StartHandling(const mate::Dictionary& args); protected: DesktopCapturer(); @@ -41,11 +39,9 @@ class DesktopCapturer: public mate::EventEmitter, void OnSourceMoved(int old_index, int new_index) override; void OnSourceNameChanged(int index) override; void OnSourceThumbnailChanged(int index) override; - void OnRefreshFinished() override; + bool OnRefreshFinished() override; private: - void EmitDesktopCapturerEvent( - const std::string& event_name, int index, bool with_thumbnail); // mate::Wrappable: mate::ObjectTemplateBuilder GetObjectTemplateBuilder( v8::Isolate* isolate) override; diff --git a/atom/browser/lib/desktop-capturer.coffee b/atom/browser/lib/desktop-capturer.coffee index 0177d9721bb5..daef854cb74e 100644 --- a/atom/browser/lib/desktop-capturer.coffee +++ b/atom/browser/lib/desktop-capturer.coffee @@ -1,38 +1,38 @@ ipc = require 'ipc' -BrowserWindow = require 'browser-window' # The browser module manages all desktop-capturer moduels in renderer process. desktopCapturer = process.atomBinding('desktop_capturer').desktopCapturer -getWebContentsFromId = (id) -> - windows = BrowserWindow.getAllWindows() - return window.webContents for window in windows when window.webContents?.getId() == id +isOptionsEqual = (opt1, opt2) -> + return JSON.stringify opt1 is JSON.stringify opt2 -# The set for tracking id of webContents. -webContentsIds = new Set +# A queue for holding all requests from renderer process. +requestsQueue = [] -stopDesktopCapture = (id) -> - webContentsIds.delete id - # Stop updating if no renderer process listens the desktop capturer. - if webContentsIds.size is 0 - desktopCapturer.stopUpdating() +ipc.on 'ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', (event, options) -> + request = { options: options, webContents: event.sender } + desktopCapturer.startHandling options if requestsQueue.length is 0 + requestsQueue.push request + # If the WebContents is destroyed before receiving result, just remove the + # reference from requestsQueue to make the module not send the result to it. + event.sender.once 'destroyed', () -> + request.webContents = null -# Handle `desktopCapturer.startUpdating` API. -ipc.on 'ATOM_BROWSER_DESKTOP_CAPTURER_START_UPDATING', (event, args) -> - id = event.sender.getId() - if not webContentsIds.has id - # Stop sending desktop capturer events to the destroyed webContents. - event.sender.on 'destroyed', ()-> - stopDesktopCapture id - # Start updating the desktopCapturer if it doesn't. - if webContentsIds.size is 0 - desktopCapturer.startUpdating args - webContentsIds.add id +desktopCapturer.emit = (event_name, event, sources) -> + # Receiving sources result from main process, now send them back to renderer. + handledRequest = requestsQueue.shift 0 + result = ({ id: source.id, name: source.name, thumbnail: source.thumbnail.toDataUrl() } for source in sources) + handledRequest.webContents?.send 'ATOM_REDNERER_DESKTOP_CAPTURER_RESULT', result -# Handle `desktopCapturer.stopUpdating` API. -ipc.on 'ATOM_BROWSER_DESKTOP_CAPTURER_STOP_UPDATING', (event) -> - stopDesktopCapture event.sender.getId() - -desktopCapturer.emit = (event_name, event, desktopId, name, thumbnail) -> - webContentsIds.forEach (id) -> - getWebContentsFromId(id).send 'ATOM_RENDERER_DESKTOP_CAPTURER', event_name, desktopId, name, thumbnail?.toDataUrl() + # Check the queue to see whether there is other same request. If has, handle + # it for reducing redunplicated `desktopCaptuer.startHandling` calls. + unhandledRequestsQueue = [] + for request in requestsQueue + if isOptionsEqual handledRequest.options, request.options + request.webContents?.send 'ATOM_REDNERER_DESKTOP_CAPTURER_RESULT', result + else + unhandledRequestsQueue.push request + requestsQueue = unhandledRequestsQueue + # If the requestsQueue is not empty, start a new request handling. + if requestsQueue.length > 0 + desktopCapturer.startHandling requestsQueue[0].options diff --git a/atom/renderer/api/lib/desktop-capturer.coffee b/atom/renderer/api/lib/desktop-capturer.coffee index ae5e054c2a75..7ac5a4024c9b 100644 --- a/atom/renderer/api/lib/desktop-capturer.coffee +++ b/atom/renderer/api/lib/desktop-capturer.coffee @@ -1,19 +1,10 @@ ipc = require 'ipc' -remote = require 'remote' NativeImage = require 'native-image' -EventEmitter = require('events').EventEmitter -desktopCapturer = new EventEmitter +getSources = (options, callback) -> + ipc.send 'ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', options + ipc.once 'ATOM_REDNERER_DESKTOP_CAPTURER_RESULT', (sources) -> + callback ({id: source.id, name: source.name, thumbnail: NativeImage.createFromDataUrl source.thumbnail} for source in sources) -desktopCapturer.startUpdating = (args) -> - ipc.send 'ATOM_BROWSER_DESKTOP_CAPTURER_START_UPDATING', args - -desktopCapturer.stopUpdating = () -> - ipc.send 'ATOM_BROWSER_DESKTOP_CAPTURER_STOP_UPDATING' - -ipc.on 'ATOM_RENDERER_DESKTOP_CAPTURER', (event_name, id, name, thumbnail) -> - if not thumbnail - return desktopCapturer.emit event_name, id, name - desktopCapturer.emit event_name, id, name, NativeImage.createFromDataUrl thumbnail - -module.exports = desktopCapturer +module.exports = + getSources: getSources diff --git a/chromium_src/chrome/browser/media/desktop_media_list_observer.h b/chromium_src/chrome/browser/media/desktop_media_list_observer.h index eccaa407d2df..34cd626bf6bf 100644 --- a/chromium_src/chrome/browser/media/desktop_media_list_observer.h +++ b/chromium_src/chrome/browser/media/desktop_media_list_observer.h @@ -14,7 +14,7 @@ class DesktopMediaListObserver { virtual void OnSourceMoved(int old_index, int new_index) = 0; virtual void OnSourceNameChanged(int index) = 0; virtual void OnSourceThumbnailChanged(int index) = 0; - virtual void OnRefreshFinished() = 0; + virtual bool OnRefreshFinished() = 0; protected: virtual ~DesktopMediaListObserver() {} diff --git a/chromium_src/chrome/browser/media/native_desktop_media_list.cc b/chromium_src/chrome/browser/media/native_desktop_media_list.cc index a326ded91b80..4d15b068b7c3 100644 --- a/chromium_src/chrome/browser/media/native_desktop_media_list.cc +++ b/chromium_src/chrome/browser/media/native_desktop_media_list.cc @@ -358,10 +358,13 @@ void NativeDesktopMediaList::OnSourceThumbnail( } void NativeDesktopMediaList::OnRefreshFinished() { - observer_->OnRefreshFinished(); - BrowserThread::PostDelayedTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&NativeDesktopMediaList::Refresh, - weak_factory_.GetWeakPtr()), - update_period_); + // Give a chance to the observer to stop the refresh work. + bool is_continue = observer_->OnRefreshFinished(); + if (is_continue) { + BrowserThread::PostDelayedTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&NativeDesktopMediaList::Refresh, + weak_factory_.GetWeakPtr()), + update_period_); + } } diff --git a/docs/api/desktop-capturer.md b/docs/api/desktop-capturer.md index 6dc971cd2066..916538a4e9f8 100644 --- a/docs/api/desktop-capturer.md +++ b/docs/api/desktop-capturer.md @@ -7,36 +7,27 @@ screen and individual app windows. // In the renderer process. var desktopCapturer = require('desktop-capturer'); -desktopCapturer.on('source-added', function(id, name) { - console.log("source " + name + " is added."); - // navigator.webkitGetUserMedia is not ready for use now. -}); - -desktopCapturer.on('source-thumbnail-changed', function(id, name, thumbnail) { - if (name == "Electron") { - // stopUpdating since we have found the window that we want to capture. - desktopCapturer.stopUpdating(); - - // It's ready to use webkitGetUserMedia right now. - navigator.webkitGetUserMedia({ - audio: false, - video: { - mandatory: { - chromeMediaSource: 'desktop', - chromeMediaSourceId: id, - minWidth: 1280, - maxWidth: 1280, - minHeight: 720, - maxHeight: 720 +desktopCapturer.getSources({types: ['window', 'screen']}, function(sources) { + for (var i = 0; i < sources.length; ++i) { + if (sources[i].name == "Electron") { + navigator.webkitGetUserMedia({ + audio: false, + video: { + mandatory: { + chromeMediaSource: 'desktop', + chromeMediaSourceId: sources[i].id, + minWidth: 1280, + maxWidth: 1280, + minHeight: 720, + maxHeight: 720 + } } - } - }, gotStream, getUserMediaError); + }, gotStream, getUserMediaError); + return; + } } }); -// Let's start updating after setting all event of `desktopCapturer` -desktopCapturer.startUpdating(); - function gotStream(stream) { document.querySelector('video').src = URL.createObjectURL(stream); } @@ -46,9 +37,35 @@ function getUserMediaError(e) { } ``` -## Events +## Methods -### Event: 'source-added' +The `desktopCapturer` module has the following methods: + +### `desktopCapturer.getSources(options, callback)` + +`options` Object, properties: +* `types` Array - An array of String that enums the types of desktop sources. + * `screen` String - Screen + * `window` String - Individual window +* `thumnailSize` Object (optional) - The suggested size that thumbnail should be + scaled. + * `width` Integer - The width of thumbnail. By default, it is 150px. + * `height` Integer - The height of thumbnail. By default, it is 150px. + +`callback` Function - `function(sources) {}` + +* `Sources` Array - An array of Source + +Gets all desktop sources. + +**Note:** There is no garuantee that the size of `source.thumbnail` is always +the same as the `thumnailSize` in `options`. It also depends on the scale of the +screen or window. + +## Source + +`Source` is an object represents a captured screen or individual window. It has +following properties: * `id` String - The id of the captured window or screen used in `navigator.webkitGetUserMedia`. The format looks like 'window:XX' or @@ -56,76 +73,4 @@ function getUserMediaError(e) { * `name` String - The descriped name of the capturing screen or window. If the source is a screen, the name will be 'Entire Screen' or 'Screen '; if it is a window, the name will be the window's title. - -Emits when there is a new source added, usually a new window is created or a new -screen is attached. - -**Note:** `navigator.webkitGetUserMedia` is not ready for use in this event. - -### Event: 'source-removed' - -* `id` String - The id of the captured window or screen used in - `navigator.webkitGetUserMedia`. -* `name` String - The descriped name of the capturing screen or window. - -Emits when there is a source removed. - -### Event: 'source-name-changed' - -* `id` String - The id of the captured window or screen used in - `navigator.webkitGetUserMedia`. -* `name` String - The descriped name of the capturing screen or window. - -Emits when the name of source is changed. - -### Event: 'source-thumbnail-changed' - -* `id` String - The id of the captured window or screen used in - `navigator.webkitGetUserMedia`. -* `name` String - The descriped name of the capturing screen or window. * `thumbnail` [NativeImage](NativeImage.md) - A thumbnail image. - -Emits when the thumbnail of source is changed. `desktopCapturer` will refresh -all sources every second. - -### Event: 'refresh-finished' - -Emits when `desktopCapturer` finishes a refresh. - -## Methods - -The `desktopCapturer` module has the following methods: - -### `desktopCapturer.startUpdating(options)` - -`options` Object, properties: - -* `types` Array - An array of String that enums the types of desktop sources. - * `screen` String - Screen - * `window` String - Individual window -* `updatePeriod` Integer (optional) - The update period in milliseconds. By - default, `desktopCapturer` updates every second. -* `thumbnailWidth` Integer (optional) - The width of thumbnail. By default, it - is 150px. -* `thumbnailHeight` Integer (optional) - The height of thumbnail. By default, it - is 150px. - -Starts updating desktopCapturer. The events of `desktopCapturer` will only be -emitted after `startUpdating` API is invoked. - -**Note:** At beginning, the desktopCapturer is initially empty, so the -`source-added` event will be emitted for each existing source as it is -enumrated. -On Windows, you will see the screen ficker when desktopCapturer starts updating. -This is normal because the desktop effects(e.g. Aero) will be disabled when -desktop capturer is working. The ficker will disappear once -`desktopCapturer.stopUpdating()` is invoked. - -### `desktopCapturer.stopUpdating()` - -Stops updating desktopCapturer. The events of `desktopCapturer` will not be -emitted after the API is invoked. - -**Note:** It is a good practice to call `stopUpdating` when you do not need -getting any infomation of sources, usually after passing a id to -`navigator.webkitGetUserMedia`. From 214f8477b32e7d4067742ed5b49a933dfe4dcffb Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Sat, 17 Oct 2015 19:28:14 +0800 Subject: [PATCH 06/67] Fix some typos. --- atom/browser/lib/desktop-capturer.coffee | 4 ++-- atom/renderer/api/lib/desktop-capturer.coffee | 2 +- docs/api/desktop-capturer.md | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/atom/browser/lib/desktop-capturer.coffee b/atom/browser/lib/desktop-capturer.coffee index daef854cb74e..fc3cdd5feaae 100644 --- a/atom/browser/lib/desktop-capturer.coffee +++ b/atom/browser/lib/desktop-capturer.coffee @@ -22,14 +22,14 @@ desktopCapturer.emit = (event_name, event, sources) -> # Receiving sources result from main process, now send them back to renderer. handledRequest = requestsQueue.shift 0 result = ({ id: source.id, name: source.name, thumbnail: source.thumbnail.toDataUrl() } for source in sources) - handledRequest.webContents?.send 'ATOM_REDNERER_DESKTOP_CAPTURER_RESULT', result + handledRequest.webContents?.send 'ATOM_RENDERER_DESKTOP_CAPTURER_RESULT', result # Check the queue to see whether there is other same request. If has, handle # it for reducing redunplicated `desktopCaptuer.startHandling` calls. unhandledRequestsQueue = [] for request in requestsQueue if isOptionsEqual handledRequest.options, request.options - request.webContents?.send 'ATOM_REDNERER_DESKTOP_CAPTURER_RESULT', result + request.webContents?.send 'ATOM_RENDERER_DESKTOP_CAPTURER_RESULT', result else unhandledRequestsQueue.push request requestsQueue = unhandledRequestsQueue diff --git a/atom/renderer/api/lib/desktop-capturer.coffee b/atom/renderer/api/lib/desktop-capturer.coffee index 7ac5a4024c9b..a82eb69e657c 100644 --- a/atom/renderer/api/lib/desktop-capturer.coffee +++ b/atom/renderer/api/lib/desktop-capturer.coffee @@ -3,7 +3,7 @@ NativeImage = require 'native-image' getSources = (options, callback) -> ipc.send 'ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', options - ipc.once 'ATOM_REDNERER_DESKTOP_CAPTURER_RESULT', (sources) -> + ipc.once 'ATOM_RENDERER_DESKTOP_CAPTURER_RESULT', (sources) -> callback ({id: source.id, name: source.name, thumbnail: NativeImage.createFromDataUrl source.thumbnail} for source in sources) module.exports = diff --git a/docs/api/desktop-capturer.md b/docs/api/desktop-capturer.md index 916538a4e9f8..8002451c463b 100644 --- a/docs/api/desktop-capturer.md +++ b/docs/api/desktop-capturer.md @@ -47,8 +47,8 @@ The `desktopCapturer` module has the following methods: * `types` Array - An array of String that enums the types of desktop sources. * `screen` String - Screen * `window` String - Individual window -* `thumnailSize` Object (optional) - The suggested size that thumbnail should be - scaled. +* `thumbnailSize` Object (optional) - The suggested size that thumbnail should + be scaled. * `width` Integer - The width of thumbnail. By default, it is 150px. * `height` Integer - The height of thumbnail. By default, it is 150px. @@ -59,8 +59,8 @@ The `desktopCapturer` module has the following methods: Gets all desktop sources. **Note:** There is no garuantee that the size of `source.thumbnail` is always -the same as the `thumnailSize` in `options`. It also depends on the scale of the -screen or window. +the same as the `thumnbailSize` in `options`. It also depends on the scale of +the screen or window. ## Source From fb4efec55da118628263f21744a0ec8f6fce193a Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Mon, 19 Oct 2015 10:54:12 +0800 Subject: [PATCH 07/67] Add options check. This patch avoids main process never response back to renderer if the options is invalid. --- atom/browser/api/atom_api_desktop_capturer.cc | 37 ++++++++++++------- atom/browser/lib/desktop-capturer.coffee | 9 +++-- atom/renderer/api/lib/desktop-capturer.coffee | 5 ++- docs/api/desktop-capturer.md | 8 ++-- 4 files changed, 37 insertions(+), 22 deletions(-) diff --git a/atom/browser/api/atom_api_desktop_capturer.cc b/atom/browser/api/atom_api_desktop_capturer.cc index 116b0f4debf0..21e98fe47c21 100644 --- a/atom/browser/api/atom_api_desktop_capturer.cc +++ b/atom/browser/api/atom_api_desktop_capturer.cc @@ -41,6 +41,24 @@ namespace api { namespace { const int kThumbnailWidth = 150; const int kThumbnailHeight = 150; + +bool GetCapturerTypes(const mate::Dictionary& args, + bool* show_windows, + bool* show_screens) { + *show_windows = false; + *show_screens = false; + std::vector sources; + if (!args.Get("types", &sources)) + return false; + for (const auto& source_type : sources) { + if (source_type == "screen") + *show_screens = true; + else if (source_type == "window") + *show_windows = true; + } + return !show_windows && !show_screens ? false : true; +} + } // namespace DesktopCapturer::DesktopCapturer() { @@ -50,21 +68,14 @@ DesktopCapturer::~DesktopCapturer() { } void DesktopCapturer::StartHandling(const mate::Dictionary& args) { - std::vector sources; - if (!args.Get("types", &sources)) - return; - bool show_screens = false; bool show_windows = false; - for (const auto& source_type : sources) { - if (source_type == "screen") - show_screens = true; - else if (source_type == "window") - show_windows = true; - } - - if (!show_windows && !show_screens) + if (!GetCapturerTypes(args, &show_windows, &show_screens)) { + Emit("handling-finished", + "Invalid options.", + std::vector()); return; + } webrtc::DesktopCaptureOptions options = webrtc::DesktopCaptureOptions::CreateDefault(); @@ -113,7 +124,7 @@ bool DesktopCapturer::OnRefreshFinished() { for (int i = 0; i < media_list_->GetSourceCount(); ++i) sources.push_back(media_list_->GetSource(i)); media_list_.reset(); - Emit("refresh-finished", sources); + Emit("handling-finished", "", sources); return false; } diff --git a/atom/browser/lib/desktop-capturer.coffee b/atom/browser/lib/desktop-capturer.coffee index fc3cdd5feaae..916eda7b68aa 100644 --- a/atom/browser/lib/desktop-capturer.coffee +++ b/atom/browser/lib/desktop-capturer.coffee @@ -11,25 +11,26 @@ requestsQueue = [] ipc.on 'ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', (event, options) -> request = { options: options, webContents: event.sender } - desktopCapturer.startHandling options if requestsQueue.length is 0 requestsQueue.push request + desktopCapturer.startHandling options if requestsQueue.length is 1 # If the WebContents is destroyed before receiving result, just remove the # reference from requestsQueue to make the module not send the result to it. event.sender.once 'destroyed', () -> request.webContents = null -desktopCapturer.emit = (event_name, event, sources) -> +desktopCapturer.emit = (event_name, event, error_message, sources) -> # Receiving sources result from main process, now send them back to renderer. handledRequest = requestsQueue.shift 0 + error = if error_message then Error error_message else null result = ({ id: source.id, name: source.name, thumbnail: source.thumbnail.toDataUrl() } for source in sources) - handledRequest.webContents?.send 'ATOM_RENDERER_DESKTOP_CAPTURER_RESULT', result + handledRequest.webContents?.send 'ATOM_RENDERER_DESKTOP_CAPTURER_RESULT', error_message, result # Check the queue to see whether there is other same request. If has, handle # it for reducing redunplicated `desktopCaptuer.startHandling` calls. unhandledRequestsQueue = [] for request in requestsQueue if isOptionsEqual handledRequest.options, request.options - request.webContents?.send 'ATOM_RENDERER_DESKTOP_CAPTURER_RESULT', result + request.webContents?.send 'ATOM_RENDERER_DESKTOP_CAPTURER_RESULT', error_message, result else unhandledRequestsQueue.push request requestsQueue = unhandledRequestsQueue diff --git a/atom/renderer/api/lib/desktop-capturer.coffee b/atom/renderer/api/lib/desktop-capturer.coffee index a82eb69e657c..5c8caf076a3a 100644 --- a/atom/renderer/api/lib/desktop-capturer.coffee +++ b/atom/renderer/api/lib/desktop-capturer.coffee @@ -3,8 +3,9 @@ NativeImage = require 'native-image' getSources = (options, callback) -> ipc.send 'ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', options - ipc.once 'ATOM_RENDERER_DESKTOP_CAPTURER_RESULT', (sources) -> - callback ({id: source.id, name: source.name, thumbnail: NativeImage.createFromDataUrl source.thumbnail} for source in sources) + ipc.once 'ATOM_RENDERER_DESKTOP_CAPTURER_RESULT', (error_message, sources) -> + error = if error_message then Error error_message else null + callback error, ({id: source.id, name: source.name, thumbnail: NativeImage.createFromDataUrl source.thumbnail} for source in sources) module.exports = getSources: getSources diff --git a/docs/api/desktop-capturer.md b/docs/api/desktop-capturer.md index 8002451c463b..2d805771cef0 100644 --- a/docs/api/desktop-capturer.md +++ b/docs/api/desktop-capturer.md @@ -7,7 +7,8 @@ screen and individual app windows. // In the renderer process. var desktopCapturer = require('desktop-capturer'); -desktopCapturer.getSources({types: ['window', 'screen']}, function(sources) { +desktopCapturer.getSources({types: ['window', 'screen']}, function(error, sources) { + if (error) throw error; for (var i = 0; i < sources.length; ++i) { if (sources[i].name == "Electron") { navigator.webkitGetUserMedia({ @@ -52,9 +53,10 @@ The `desktopCapturer` module has the following methods: * `width` Integer - The width of thumbnail. By default, it is 150px. * `height` Integer - The height of thumbnail. By default, it is 150px. -`callback` Function - `function(sources) {}` +`callback` Function - `function(error, sources) {}` -* `Sources` Array - An array of Source +* `error` Error +* `sources` Array - An array of Source Gets all desktop sources. From 9c861b9ad37a9c6335dde2e59d3005742fe75150 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Mon, 19 Oct 2015 18:07:35 +0800 Subject: [PATCH 08/67] Fix always passing the first result to renderer when the API is called multiple time at once. --- atom/browser/lib/desktop-capturer.coffee | 10 +++++----- atom/renderer/api/lib/desktop-capturer.coffee | 8 ++++++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/atom/browser/lib/desktop-capturer.coffee b/atom/browser/lib/desktop-capturer.coffee index 916eda7b68aa..29d952595cb0 100644 --- a/atom/browser/lib/desktop-capturer.coffee +++ b/atom/browser/lib/desktop-capturer.coffee @@ -4,13 +4,13 @@ ipc = require 'ipc' desktopCapturer = process.atomBinding('desktop_capturer').desktopCapturer isOptionsEqual = (opt1, opt2) -> - return JSON.stringify opt1 is JSON.stringify opt2 + return JSON.stringify(opt1) is JSON.stringify(opt2) # A queue for holding all requests from renderer process. requestsQueue = [] -ipc.on 'ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', (event, options) -> - request = { options: options, webContents: event.sender } +ipc.on 'ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', (event, options, id) -> + request = { id: id, options: options, webContents: event.sender } requestsQueue.push request desktopCapturer.startHandling options if requestsQueue.length is 1 # If the WebContents is destroyed before receiving result, just remove the @@ -23,14 +23,14 @@ desktopCapturer.emit = (event_name, event, error_message, sources) -> handledRequest = requestsQueue.shift 0 error = if error_message then Error error_message else null result = ({ id: source.id, name: source.name, thumbnail: source.thumbnail.toDataUrl() } for source in sources) - handledRequest.webContents?.send 'ATOM_RENDERER_DESKTOP_CAPTURER_RESULT', error_message, result + handledRequest.webContents?.send "ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_#{handledRequest.id}", error_message, result # Check the queue to see whether there is other same request. If has, handle # it for reducing redunplicated `desktopCaptuer.startHandling` calls. unhandledRequestsQueue = [] for request in requestsQueue if isOptionsEqual handledRequest.options, request.options - request.webContents?.send 'ATOM_RENDERER_DESKTOP_CAPTURER_RESULT', error_message, result + request.webContents?.send "ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_#{request.id}", error_message, result else unhandledRequestsQueue.push request requestsQueue = unhandledRequestsQueue diff --git a/atom/renderer/api/lib/desktop-capturer.coffee b/atom/renderer/api/lib/desktop-capturer.coffee index 5c8caf076a3a..95e67ff99927 100644 --- a/atom/renderer/api/lib/desktop-capturer.coffee +++ b/atom/renderer/api/lib/desktop-capturer.coffee @@ -1,9 +1,13 @@ ipc = require 'ipc' NativeImage = require 'native-image' +nextId = 0 +getNextId = -> ++nextId + getSources = (options, callback) -> - ipc.send 'ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', options - ipc.once 'ATOM_RENDERER_DESKTOP_CAPTURER_RESULT', (error_message, sources) -> + id = getNextId() + ipc.send 'ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', options, id + ipc.once "ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_#{id}", (error_message, sources) -> error = if error_message then Error error_message else null callback error, ({id: source.id, name: source.name, thumbnail: NativeImage.createFromDataUrl source.thumbnail} for source in sources) From 2c6d23225460be0102ab7aeb0da0c6c14b09f838 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Fri, 4 Dec 2015 11:02:55 +0800 Subject: [PATCH 09/67] Don't add too much listeners in BrowserWindowProxy --- atom/browser/lib/guest-window-manager.coffee | 2 +- atom/renderer/lib/override.coffee | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/atom/browser/lib/guest-window-manager.coffee b/atom/browser/lib/guest-window-manager.coffee index 35ef7b89bb44..eea26462b68d 100644 --- a/atom/browser/lib/guest-window-manager.coffee +++ b/atom/browser/lib/guest-window-manager.coffee @@ -44,7 +44,7 @@ createGuest = (embedder, url, frameName, options) -> guest.removeListener 'closed', closedByUser guest.destroy() closedByUser = -> - embedder.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSED', guestId + embedder.send "ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_#{guestId}" embedder.removeListener 'render-view-deleted', closedByEmbedder embedder.once 'render-view-deleted', closedByEmbedder guest.once 'closed', closedByUser diff --git a/atom/renderer/lib/override.coffee b/atom/renderer/lib/override.coffee index 0b60ce0d6686..cb4fb8fbac2d 100644 --- a/atom/renderer/lib/override.coffee +++ b/atom/renderer/lib/override.coffee @@ -10,9 +10,8 @@ resolveURL = (url) -> class BrowserWindowProxy constructor: (@guestId) -> @closed = false - ipcRenderer.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSED', (event, guestId) => - if guestId is @guestId - @closed = true + ipcRenderer.once "ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_#{@guestId}", => + @closed = true close: -> ipcRenderer.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', @guestId From 973ae06f214122686c501ec28ff5f55e60fd4f0e Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Fri, 4 Dec 2015 11:35:04 +0800 Subject: [PATCH 10/67] Destroy the native window in next tick It fixes a possible crash when native code is iterating all windows while the JavaScript code decides to destroy a window. --- atom/browser/api/atom_api_window.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 79c91db3fa5d..84e5c53ebe65 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -159,6 +159,10 @@ Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) { Window::~Window() { if (!window_->IsClosed()) window_->CloseContents(nullptr); + + // Destroy the native window in next tick because the native code might be + // iterating all windows. + base::MessageLoop::current()->DeleteSoon(FROM_HERE, window_.release()); } void Window::WillCloseWindow(bool* prevent_default) { From 5e5ae81c536948d4bd39fe78de26880dea3e46cb Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Fri, 4 Dec 2015 11:40:35 +0800 Subject: [PATCH 11/67] 'key of' is better than Object.keys --- atom/browser/lib/guest-window-manager.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/browser/lib/guest-window-manager.coffee b/atom/browser/lib/guest-window-manager.coffee index eea26462b68d..53bbb735b044 100644 --- a/atom/browser/lib/guest-window-manager.coffee +++ b/atom/browser/lib/guest-window-manager.coffee @@ -5,7 +5,7 @@ frameToGuest = {} # Copy attribute of |parent| to |child| if it is not defined in |child|. mergeOptions = (child, parent) -> - for own key, value of parent when key not in Object.keys child + for own key, value of parent when key not of child if typeof value is 'object' child[key] = mergeOptions {}, value else From 13c737823bee91f7f486f7d341b3d5712f6d5733 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Fri, 4 Dec 2015 11:52:34 +0800 Subject: [PATCH 12/67] spec: Suppress execFileSync test It somehow makes the test flaky after refresh. --- spec/asar-spec.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/asar-spec.coffee b/spec/asar-spec.coffee index 495d89734e5f..479443292b44 100644 --- a/spec/asar-spec.coffee +++ b/spec/asar-spec.coffee @@ -404,7 +404,8 @@ describe 'asar package', -> assert.equal stdout, 'test\n' done() - it 'execFileSync executes binaries', -> + # execFileSync makes the test flaky after a refresh. + xit 'execFileSync executes binaries', -> output = execFileSync echo, ['test'] assert.equal String(output), 'test\n' From 7c1ea0b0f46334c31c59928731efb776bdbc7cc2 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Fri, 4 Dec 2015 12:25:46 +0800 Subject: [PATCH 13/67] spec: Suppress flaky tests on Travis --- spec/api-protocol-spec.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spec/api-protocol-spec.coffee b/spec/api-protocol-spec.coffee index 5332b2b17ce6..034b9765927c 100644 --- a/spec/api-protocol-spec.coffee +++ b/spec/api-protocol-spec.coffee @@ -365,6 +365,9 @@ describe 'protocol module', -> done(error) it 'sends error when callback is called with nothing', (done) -> + # Flaky on Travis. + return done() if process.env.TRAVIS is 'true' + protocol.interceptBufferProtocol 'http', emptyHandler, (error) -> return done(error) if error $.ajax From c4f2d946e135b3a66572e685cd1856c9ed30b4d5 Mon Sep 17 00:00:00 2001 From: "Howard.Zuo" Date: Fri, 4 Dec 2015 15:18:55 +0800 Subject: [PATCH 14/67] add translation of using-native-node-modules for ZH-CN --- .../tutorial/using-native-node-modules.md | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 docs-translations/zh-CN/tutorial/using-native-node-modules.md diff --git a/docs-translations/zh-CN/tutorial/using-native-node-modules.md b/docs-translations/zh-CN/tutorial/using-native-node-modules.md new file mode 100644 index 000000000000..e03e7b8948a1 --- /dev/null +++ b/docs-translations/zh-CN/tutorial/using-native-node-modules.md @@ -0,0 +1,53 @@ +# 使用原生模块 + +Electron同样也支持原生模块,但由于和官方的Node相比使用了不同的V8引擎,如果你想编译原生模块,则需要手动设置Electron的headers的位置。 + +## 原生Node模块的兼容性 + +当Node开始换新的V8引擎版本时,原生模块可能“坏”掉。为确保一切工作正常,你需要检查你想要使用的原生模块是否被Electron内置的Node支持。你可以在[这里](https://github.com/atom/electron/releases)查看Electron内置的Node版本,或者使用`process.version`(参考:[快速入门](https://github.com/atom/electron/blob/master/docs/tutorial/quick-start.md))查看。 + +考虑到[NAN](https://github.com/nodejs/nan/)可以使你的开发更容易对多版本Node的支持,建议使用它来开发你自己的模块。你也可以使用[NAN](https://github.com/nodejs/nan/)来移植旧的模块到新的Node版本,以使它们可以在新的Electron下良好工作。 + +## 如何安装原生模块 + +如下三种方法教你安装原生模块: + +### 最简单方式 + +最简单的方式就是通过[`electron-rebuild`](https://github.com/paulcbetts/electron-rebuild)包重新编译原生模块,它帮你自动完成了下载headers、编译原生模块等步骤: + +```sh +npm install --save-dev electron-rebuild + +# 每次运行"npm install"时,也运行这条命令 +./node_modules/.bin/electron-rebuild + +# 在windows下如果上述命令遇到了问题,尝试这个: +.\node_modules\.bin\electron-rebuild.cmd +``` + +### 通过npm安装 + +你当然也可以通过`npm`安装原生模块。大部分步骤和安装普通模块时一样,除了以下一些系统环境变量你需要自己操作: + +```bash +export npm_config_disturl=https://atom.io/download/atom-shell +export npm_config_target=0.33.1 +export npm_config_arch=x64 +export npm_config_runtime=electron +HOME=~/.electron-gyp npm install module-name +``` + +### 通过node-gyp安装 + +你需要告诉`node-gyp`去哪下载Electron的headers,以及下载什么版本: + +```bash +$ cd /path-to-module/ +$ HOME=~/.electron-gyp node-gyp rebuild --target=0.29.1 --arch=x64 --dist-url=https://atom.io/download/atom-shell +``` + +`HOME=~/.electron-gyp`设置了去哪找开发时的headers。 +`--target=0.29.1`设置了Electron的版本 +`--dist-url=...`设置了Electron的headers的下载地址 +`--arch=x64`设置了该模块为适配64bit操作系统而编译 From c8e2be7b281d55bab8036058df9db52d90d14faa Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Fri, 4 Dec 2015 16:43:23 +0800 Subject: [PATCH 15/67] Bump v0.35.3 --- atom.gyp | 2 +- atom/browser/resources/mac/Info.plist | 4 ++-- atom/browser/resources/win/atom.rc | 8 ++++---- atom/common/atom_version.h | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/atom.gyp b/atom.gyp index 202a414003fc..2f97e206742a 100644 --- a/atom.gyp +++ b/atom.gyp @@ -4,7 +4,7 @@ 'product_name%': 'Electron', 'company_name%': 'GitHub, Inc', 'company_abbr%': 'github', - 'version%': '0.35.2', + 'version%': '0.35.3', }, 'includes': [ 'filenames.gypi', diff --git a/atom/browser/resources/mac/Info.plist b/atom/browser/resources/mac/Info.plist index fb4a2332334e..dbb1f5082690 100644 --- a/atom/browser/resources/mac/Info.plist +++ b/atom/browser/resources/mac/Info.plist @@ -17,9 +17,9 @@ CFBundleIconFile atom.icns CFBundleVersion - 0.35.2 + 0.35.3 CFBundleShortVersionString - 0.35.2 + 0.35.3 LSApplicationCategoryType public.app-category.developer-tools LSMinimumSystemVersion diff --git a/atom/browser/resources/win/atom.rc b/atom/browser/resources/win/atom.rc index 773871fd5583..aaceb3420c97 100644 --- a/atom/browser/resources/win/atom.rc +++ b/atom/browser/resources/win/atom.rc @@ -56,8 +56,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,35,2,0 - PRODUCTVERSION 0,35,2,0 + FILEVERSION 0,35,3,0 + PRODUCTVERSION 0,35,3,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -74,12 +74,12 @@ BEGIN BEGIN VALUE "CompanyName", "GitHub, Inc." VALUE "FileDescription", "Electron" - VALUE "FileVersion", "0.35.2" + VALUE "FileVersion", "0.35.3" VALUE "InternalName", "electron.exe" VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved." VALUE "OriginalFilename", "electron.exe" VALUE "ProductName", "Electron" - VALUE "ProductVersion", "0.35.2" + VALUE "ProductVersion", "0.35.3" VALUE "SquirrelAwareVersion", "1" END END diff --git a/atom/common/atom_version.h b/atom/common/atom_version.h index b5cc0982d0d7..c1593120fd16 100644 --- a/atom/common/atom_version.h +++ b/atom/common/atom_version.h @@ -7,7 +7,7 @@ #define ATOM_MAJOR_VERSION 0 #define ATOM_MINOR_VERSION 35 -#define ATOM_PATCH_VERSION 2 +#define ATOM_PATCH_VERSION 3 #define ATOM_VERSION_IS_RELEASE 1 From d14f15c33ae831704abc72f8f4d973ef46908b8d Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Fri, 4 Dec 2015 19:23:30 +0800 Subject: [PATCH 16/67] Update native_mate: isDestroy => isDestroyed --- vendor/native_mate | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/native_mate b/vendor/native_mate index e859228db163..5e70868fd0c0 160000 --- a/vendor/native_mate +++ b/vendor/native_mate @@ -1 +1 @@ -Subproject commit e859228db163c27410fb200c2df0715478fdf0d7 +Subproject commit 5e70868fd0c005dc2c43bea15ca6e93da0b68741 From e1d7ef7e24affd8f4ede3689c5354ef11036bf62 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Fri, 4 Dec 2015 19:23:48 +0800 Subject: [PATCH 17/67] Bump v0.35.4 --- atom.gyp | 2 +- atom/browser/resources/mac/Info.plist | 4 ++-- atom/browser/resources/win/atom.rc | 8 ++++---- atom/common/atom_version.h | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/atom.gyp b/atom.gyp index 2f97e206742a..9f1ffe582505 100644 --- a/atom.gyp +++ b/atom.gyp @@ -4,7 +4,7 @@ 'product_name%': 'Electron', 'company_name%': 'GitHub, Inc', 'company_abbr%': 'github', - 'version%': '0.35.3', + 'version%': '0.35.4', }, 'includes': [ 'filenames.gypi', diff --git a/atom/browser/resources/mac/Info.plist b/atom/browser/resources/mac/Info.plist index dbb1f5082690..179f26db03f3 100644 --- a/atom/browser/resources/mac/Info.plist +++ b/atom/browser/resources/mac/Info.plist @@ -17,9 +17,9 @@ CFBundleIconFile atom.icns CFBundleVersion - 0.35.3 + 0.35.4 CFBundleShortVersionString - 0.35.3 + 0.35.4 LSApplicationCategoryType public.app-category.developer-tools LSMinimumSystemVersion diff --git a/atom/browser/resources/win/atom.rc b/atom/browser/resources/win/atom.rc index aaceb3420c97..05fb3f336ff6 100644 --- a/atom/browser/resources/win/atom.rc +++ b/atom/browser/resources/win/atom.rc @@ -56,8 +56,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,35,3,0 - PRODUCTVERSION 0,35,3,0 + FILEVERSION 0,35,4,0 + PRODUCTVERSION 0,35,4,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -74,12 +74,12 @@ BEGIN BEGIN VALUE "CompanyName", "GitHub, Inc." VALUE "FileDescription", "Electron" - VALUE "FileVersion", "0.35.3" + VALUE "FileVersion", "0.35.4" VALUE "InternalName", "electron.exe" VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved." VALUE "OriginalFilename", "electron.exe" VALUE "ProductName", "Electron" - VALUE "ProductVersion", "0.35.3" + VALUE "ProductVersion", "0.35.4" VALUE "SquirrelAwareVersion", "1" END END diff --git a/atom/common/atom_version.h b/atom/common/atom_version.h index c1593120fd16..a4930d0edb2e 100644 --- a/atom/common/atom_version.h +++ b/atom/common/atom_version.h @@ -7,7 +7,7 @@ #define ATOM_MAJOR_VERSION 0 #define ATOM_MINOR_VERSION 35 -#define ATOM_PATCH_VERSION 3 +#define ATOM_PATCH_VERSION 4 #define ATOM_VERSION_IS_RELEASE 1 From 220d05a39866caa147588c96f7377fcd160ba5c0 Mon Sep 17 00:00:00 2001 From: Luke Page Date: Fri, 4 Dec 2015 21:07:33 +0000 Subject: [PATCH 18/67] Docs: Fix link to webcontents send channel --- docs/api/ipc-main.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/ipc-main.md b/docs/api/ipc-main.md index cdbc0ce34eec..7c37a26c034a 100644 --- a/docs/api/ipc-main.md +++ b/docs/api/ipc-main.md @@ -68,4 +68,4 @@ Returns the `webContents` that sent the message, you can call `event.sender.send` to reply to the asynchronous message, see [webContents.send][webcontents-send] for more information. -[webcontents-send]: web-contents.md#webcontentssendchannel-args +[webcontents-send]: web-contents.md#webcontentssendchannel-arg1-arg2- From dcfbd294bb5219403a2778b46b8e4bb18c3aec74 Mon Sep 17 00:00:00 2001 From: Artur de Oliveira Tsuda Date: Fri, 4 Dec 2015 21:55:03 -0200 Subject: [PATCH 19/67] :memo: [ci skip] browser window translation --- docs-translations/pt-BR/api/browser-window.md | 632 ++++++++++++++++++ 1 file changed, 632 insertions(+) create mode 100644 docs-translations/pt-BR/api/browser-window.md diff --git a/docs-translations/pt-BR/api/browser-window.md b/docs-translations/pt-BR/api/browser-window.md new file mode 100644 index 000000000000..143b6368bc1e --- /dev/null +++ b/docs-translations/pt-BR/api/browser-window.md @@ -0,0 +1,632 @@ +# BrowserWindow + +A classe `BrowserWindow` lhe dá a habilidade de criar uma janela do browser. Por exemplo: + +```javascript +const BrowserWindow = require('electron').BrowserWindow; + +var win = new BrowserWindow({ width: 800, height: 600, show: false }); +win.on('closed', function() { + win = null; +}); + +win.loadURL('https://github.com'); +win.show(); +``` + +Você também pode criar uma janela sem o chrome utilizando a API [Frameless Window](../../../docs/api/frameless-window.md). + +## Classe: BrowserWindow + +`BrowserWindow` é um [EventEmitter](http://nodejs.org/api/events.html#events_class_events_eventemitter). + +Ela cria uma nova `BrowserWindow` com propriedades nativas definidas pelo `options`. + +### `new BrowserWindow([options])` + +`options` Objeto (opcional), propriedades: + +* `width` Integer - Largura da janela em pixels. O padrão é `800`. +* `height` Integer - Altura da janela em pixels. O padrão é `600`. +* `x` Integer - Deslocamento da janela da esquerda da tela. O padrão é centralizar a janela. +* `y` Integer - Deslocamento da janela do topo da tela. O padrão é centralizar a janela. +* `useContentSize` Boolean - `width` e `height` seriam utilizados como o tamanho da página web, o que significa que o tamanho real da janela irá incluir o tamanho da moldura da janela e será um pouco maior. O padrão é `false`. +* `center` Boolean - Mostra a janela no centro da tela. +* `minWidth` Integer - Largura mínima da janela. O padrão é `0`. +* `minHeight` Integer - Altura mínima da janela. O padrão é `0`. +* `maxWidth` Integer - Largura máxima da janela. O padrão é sem limites. +* `maxHeight` Integer - Altura máxima da janela. O padrão é sem limites. +* `resizable` Boolean - Se é possível modificar o tamanho da janela. O padrão é `true`. +* `alwaysOnTop` Boolean - Se a janela deve sempre ficar à frente de outras janelas. O padrão é `false`. +* `fullscreen` Boolean - Se a janela deve estar em tela cheia. Quando definido como `false`, o botão de tela cheia estará escondido ou desabilitado no OS X. O padrão é `false`. +* `skipTaskbar` Boolean - Se deve mostrar a janela na barra de tarefas. O padrão é `false`. +* `kiosk` Boolean - Modo *kiosk*. O padrão é `false`. +* `title` String - Título padrão da janela. O padrão é `"Electron"`. +* `icon` [NativeImage](../../../docs/api/native-image.md) - O ícone da janela, quando omitido no Windows, o ícone do executável é utilizado como o ícone da janela. +* `show` Boolean - Se a janela deve ser exibida quando criada. O padrão é `true`. +* `frame` Boolean - Defina como `false` para criar uma [Frameless Window](../../../docs/api/frameless-window.md). O padrão é `true`. +* `acceptFirstMouse` Boolean - Se o *web view* aceita um evento *mouse-down* que ativa a janela simultaneamente. O padrão é `false`. +* `disableAutoHideCursor` Boolean - Se deve esconder o cursor quando estiver digitando. O padrão é `false`. +* `autoHideMenuBar` Boolean - Esconde a barra de menu automaticamente, a não ser que a tecla `Alt` seja pressionada. O padrão é `false`. +* `enableLargerThanScreen` Boolean - Possibilita que o tamanho da janela seja maior que a tela. O padrão é `false`. +* `backgroundColor` String - Cor de fundo da janela em hexadecimal, como `#66CD00` ou `#FFF`. Só é implementado no Linux e Windows. O padrão é `#000` (preto). +* `darkTheme` Boolean - Força a utilização do tema *dark* na janela, só funciona em alguns ambientes de desktop GTK+3. O padrão é `false`. +* `transparent` Boolean - Torna a janela [transparente](../../../docs/api/frameless-window.md). O padrão é `false`. +* `type` String - Define o tipo da janela, que aplica propriedades adicionais específicas da plataforma. Por padrão é indefinido e será criada uma janela de aplicativo comum. Possíveis valores: + * No Linux, os tipos possíveis são `desktop`, `dock`, `toolbar`, `splash`, + `notification`. + * No OS X, os tipos possíveis são `desktop`, `textured`. O tipo `textured` adiciona a aparência degradê metálica (`NSTexturedBackgroundWindowMask`). O tipo `desktop` coloca a janela no nível do fundo de tela do desktop (`kCGDesktopWindowLevel - 1`). Note que a janela `desktop` não irá receber foco, eventos de teclado ou mouse, mas você pode usar `globalShortcut` para receber entrada de dados ocasionalmente. +* `titleBarStyle` String, OS X - Define o estilo da barra de título da janela. Esta opção está suportada a partir da versão OS X 10.10 Yosemite. Há três possíveis valores: + * `default` ou não definido, resulta na barra de título cinza opaca padrão do Mac. + * `hidden` resulta numa barra de título oculta e a janela de conteúdo no tamanho máximo, porém a barra de título ainda possui os controles padrões de janela ("semáforo") no canto superior esquerdo. + * `hidden-inset` resulta numa barra de título oculta com uma aparência alternativa onde os botões de semáforo estão ligeiramente mais longe do canto da janela. +* `webPreferences` Object - Configurações das características da página web, propriedades: + * `nodeIntegration` Boolean - Se a integração com node está habilitada. O padrão é `true`. + * `preload` String - Define um *script* que será carregado antes que outros scripts rodem na página. Este script sempre terá acesso às APIs do node, não importa se `nodeIntegration` esteja habilitada ou não. O valor deve ser o endereço absoluto do scriot. Quando `nodeIntegration` não está habilitada, o script `preload` pode reintroduzir símbolos globais Node de volta ao escopo global. Veja um exemplo [aqui](process.md#evento-loaded). + * `partition` String - Define a sessão utilizada pela página. Se `partition` começa com `persist:`, a página irá utilizar uma sessão persistente disponível para todas as páginas do aplicativo com a mesma `partition`. Se não houver o prefixo `persist:`, a página irá utilizar uma sessão em memória. Ao utilizar a mesma `partition`, várias páginas podem compartilhar a mesma sessão. Se a `partition` for indefinida, então a sessão padrão do aplicativo será utilizada. + * `zoomFactor` Number - O fator de *zoom* da página, `3.0` representa `300%`. O padrão é `1.0`. + * `javascript` Boolean - Habilita suporte à JavaScript. O padrão é `true`. + * `webSecurity` Boolean - Quando definido como `false`, irá desabilitar a política de mesma origem (Geralmente usando sites de teste por pessoas), e definir `allowDisplayingInsecureContent` e `allowRunningInsecureContent` como + `true` se estas duas opções não tiverem sido definidas pelo usuário. O padrão é `true`. + * `allowDisplayingInsecureContent` Boolean - Permite que uma página https exiba conteúdo como imagens de URLs http. O padrão é `false`. + * `allowRunningInsecureContent` Boolean - Permite que uma página https rode JavaScript, CSS ou plugins de URLs http. O padrão é `false`. + * `images` Boolean - Habilita suporte a imagens. O padrão é `true`. + * `java` Boolean - Habilita suporte a Java. O padrão é `false`. + * `textAreasAreResizable` Boolean - Faz com que os elementos *TextArea* elements tenham tamanho variável. O padrão é `true`. + * `webgl` Boolean - Habiltia suporte a WebGL. O padrão é `true`. + * `webaudio` Boolean - Habilita suporte a WebAudio. O padrão é `true`. + * `plugins` Boolean - Se plugins devem ser habilitados. O padrão é `false`. + * `experimentalFeatures` Boolean - Habilita as características experimentais do Chromium. O padrão é `false`. + * `experimentalCanvasFeatures` Boolean - Habilita as características experimentais de canvas do Chromium. O padrão é `false`. + * `overlayScrollbars` Boolean - Habilita sobreposição das barras de rolagem. O padrão é `false`. + * `overlayFullscreenVideo` Boolean - Habilita sobreposição do vídeo em tela cheia. O padrão é `false`. + * `sharedWorker` Boolean - Habilita suporte a *Shared Worker*. O padrão é `false`. + * `directWrite` Boolean - Habilita o sistema de renderização de fontes *DirectWrite* no Windows. O padrão é `true`. + * `pageVisibility` Boolean - A página é forçada a permanecer visível ou oculta quando definido, em vez de refletir a visibilidade atual da janela. Usuários podem definir como `true` para evitar que os temporizadores do *DOM* sejam suprimidos. O padrão é `false`. + +## Eventos + +O objeto `BrowserWindow` emite os seguintes eventos: + +**Nota:** Alguns eventos só estão disponíveis em sistemas operacionais específicos e estão rotulados como tal. + +### Evento: 'page-title-updated' + +Retorna: + +* `event` Evento + +Emitido quando o documento muda seu título, chamar `event.preventDefault()` previne que o título nativo da janela mude. + +### Evento: 'close' + +Retorna: + +* `event` Evento + +Emitido quando a janela for fechar. É emitido antes dos eventos `beforeunload` e `unload` do DOM. Chamar `event.preventDefault()` cancela o fechamento. + +Normalmente você utiliza o manipulador de eventos do `beforeunload` para decidir se a janela deve ser fechada, que também será chamado quando a janela é recarregada. No Electron, retornar uma string vazia ou `false` cancela o fechamento. Por exemplo: + +```javascript +window.onbeforeunload = function(e) { + console.log('Não quero ser fechada'); + + // Diferente de navegadores comuns, nos quais uma string deve ser retornada e + // o usuário deve confirmar se a janela será fechada, o Electron dá mais opções + // aos desenvolvedores. Retornar uma string vazia ou false cancela o fechamento. + // Você também pode usar a API de diálogo para deixar que o usuário confirme o + // fechamento do aplicativo. + e.returnValue = false; +}; +``` + +### Evento: 'closed' + +Emitido quando a janela é fechada. Após você ter recebido este evento, você deve remover a referência da janela e evitar utilizá-la. + +### Evento: 'unresponsive' + +Emitido quando a página web para de responder. + +### Evento: 'responsive' + +Emitido quando a página web que não respondia volta a responder novamente. + +### Evento: 'blur' + +Emitido quando a janela perde foco. + +### Evento: 'focus' + +Emitido quando a janela ganha foco. + +### Evento: 'maximize' + +Emitido quando a janela é maximizada. + +### Evento: 'unmaximize' + +Emitido quando a janela sai do estado maximizado. + +### Evento: 'minimize' + +Emitido quando a janela é minimizada. + +### Evento: 'restore' + +Emitido quando a janela é restaurada do estado minimizado. + +### Evento: 'resize' + +Emitido quando o tamanho da janela está sendo alterado. + +### Evento: 'move' + +Emitido quando está sendo movida para uma nova posição. + +__Note__: No OS X este evento é apenas um apelido de `moved`. + +### Evento: 'moved' _OS X_ + +Emitido uma vez quando a janela é movida para uma nova posição. + +### Evento: 'enter-full-screen' + +Emitido quando a janela entra no estado tela cheia. + +### Evento: 'leave-full-screen' + +Emitido quando a janela sai do estado de tela cheia. + +### Evento: 'enter-html-full-screen' + +Emitido quando a janela entra no estado tela cheia, ocasionado por uma api de html. + +### Evento: 'leave-html-full-screen' + +Emitido quando a janela sai do estado de tela cheia, ocasionado por uma api de html. + +### Evento: 'app-command' _Windows_ + +Emitido quando um [App Command](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646275(v=vs.85).aspx) é invocado. Estes estão tipicamente relacionado às teclas de mídia do teclado, ou comandos do browser, assim como o botão "Voltar" existente em alguns modelos de mouse no Windows. + +```js +someWindow.on('app-command', function(e, cmd) { + // Navega a janela 'para trás' quando o usuário pressiona o botão voltar do mouse + if (cmd === 'browser-backward' && someWindow.webContents.canGoBack()) { + someWindow.webContents.goBack(); + } +}); +``` + +## Métodos + +O objeto `BrowserWindow` possui os seguintes métodos: + +### `BrowserWindow.getAllWindows()` + +Retorna um array de todas as janelas abertas. + +### `BrowserWindow.getFocusedWindow()` + +Retorna a janela que está focada no aplicativo. + +### `BrowserWindow.fromWebContents(webContents)` + +* `webContents` [WebContents](../../../docs/api/web-contents.md) + +Acha uma janela de acordo com os `webContents` que ela possui. + +### `BrowserWindow.fromId(id)` + +* `id` Integer + +Acha uma janela de acordo com o seu ID. + +### `BrowserWindow.addDevToolsExtension(path)` + +* `path` String + +Adiciona a extenção DevTools localizada no endereço `path`, e retorna o nome da extenção. + +A extenção será lembrada, então você só precisa chamar esta API uma vez, esta API não é para uso de programação. + +### `BrowserWindow.removeDevToolsExtension(name)` + +* `name` String + +Remove a extenção DevTools cujo nome é `name`. + +## Propriedades de Instância + +Objetos criados com `new BrowserWindow` possuem as seguintes propriedades: + +```javascript +// Neste exemplo `win` é a nossa instância +var win = new BrowserWindow({ width: 800, height: 600 }); +``` + +### `win.webContents` + +Todas os eventos e operações relacionados à pagina web serão feitos através do objeto `WebContents` que a esta janela possui. + +Veja a [documentação do `webContents`](../../../docs/api/web-contents.md) para seus métodos e eventos. + +### `win.id` + +O ID único desta janela. + +## Métodos de instância + +Objetos criados com `new BrowserWindow` possuem os seguintes métodos de instância: + +**Nota:** Alguns métodos só estão disponíveis em sistemas operacionais específicos e estão rotulados como tal. + +### `win.destroy()` + +Força o fechamento da janela, os eventos `unload` e `beforeunload` não serão emitidos para a página web, e o evento `close` também não será emitido para esta janela, mas garante que o evento `closed` será emitido. + +Você só deve utilizar este método quando o processo renderizador (página web) congelar. + +### `win.close()` + +Tenta fechar a janela, tem o mesmo efeito que o usuário manualmente clicar o botão de fechar a janela. Entretanto, a página web pode cancelar o fechamento, veja o [evento close](#evento-close). + +### `win.focus()` + +Foca na janela. + +### `win.isFocused()` + +Retorna um boolean, indicando se a janela está com foco. + +### `win.show()` + +Exibe e dá foco à janela. + +### `win.showInactive()` + +Exibe a janela, porém não dá foco à ela. + +### `win.hide()` + +Esconde a janela. + +### `win.isVisible()` + +Retorna um boolean, indicando se a janela está visível para o usuário. + +### `win.maximize()` + +Maximiza a janela. + +### `win.unmaximize()` + +Sai do estado maximizado da janela. + +### `win.isMaximized()` + +Retorna um boolean, indicando se a janela está maximizada. + +### `win.minimize()` + +Minimiza a janela. Em algumas plataformas, a janela minimizada será exibida no *Dock*. + +### `win.restore()` + +Restaura a janela do estado minimizado para o estado anterior. + +### `win.isMinimized()` + +Retorna um boolean, indicando se a janela está minimizada. + +### `win.setFullScreen(flag)` + +* `flag` Boolean + +Define se a janela deve estar em modo tela cheia. + +### `win.isFullScreen()` + +Retorna um boolean, indicando se a janela está em modo tela cheia. + +### `win.setAspectRatio(aspectRatio[, extraSize])` _OS X_ + +* `aspectRatio` A proporção que queremos manter para uma porção do conteúdo da *view*. +* `extraSize` Object (opcional) - O tamanho extra não incluído enquanto a proporção é mantida. Propriedades: + * `width` Integer + * `height` Integer + +Isto fará com que a janela mantenha sua proporção. O `extraSize` permite que o desenvolvedor tenha espaço, definido em pixels, não incluídos no cálculo da proporção. Esta API já leva em consideração a diferença entre o tamanho da janela e o tamanho de seu conteúdo. + +Suponha que exista uma janela normal com um *player* de vídeo HD e seus controles associados. Talvez tenha 15 pixels de controles na borda esquerda, 25 pixels de controles na borda direita e 50 abaixo do player. Para que seja mantida a proporção de 16:9 (proporção padrão para HD em 1920x1080) no próprio player, nós chamaríamos esta função com os argumentos 16/9 e [ 40, 50 ]. Para o segundo argumento, não interessa onde a largura e altura extras estão no conteúdo da view--apenas que elas existam. Apenas some qualquer área de largura e altura extras que você tem dentro da view do conteúdo. + +### `win.setBounds(options)` + +`options` Object, propriedades: + +* `x` Integer +* `y` Integer +* `width` Integer +* `height` Integer + +Redefine o tamanho e move a janela para `width`, `height`, `x`, `y`. + +### `win.getBounds()` + +Retorna um objeto que contém a largura, altura, posição x e y da janela. + +### `win.setSize(width, height)` + +* `width` Integer +* `height` Integer + +Redefine o tamanho da janela para largura `width` e altura `height`. + +### `win.getSize()` + +Retorna um array que contém a largura e altura da janela. + +### `win.setContentSize(width, height)` + +* `width` Integer +* `height` Integer + +Redefine a área de cliente da janela (a página web) para largura `width` e altura `height`. + +### `win.getContentSize()` + +Retorna um array que contém a largura e altura da área de cliente da janela. + +### `win.setMinimumSize(width, height)` + +* `width` Integer +* `height` Integer + +Define o tamanho mínimo da janela para largura `width` e altura `height`. + +### `win.getMinimumSize()` + +Retorna uma array que contém o tamanho mínimo da largura e altura da janela. + +### `win.setMaximumSize(width, height)` + +* `width` Integer +* `height` Integer + +Define o tamanho máximo da janela para largura `width` e altura `height`. + +### `win.getMaximumSize()` + +Retorna uma array que contém o tamanho máximo da largura e altura da janela. + +### `win.setResizable(resizable)` + +* `resizable` Boolean + +Define se a janela pode ter seu tamanho redefinido manualmente pelo usuário. + +### `win.isResizable()` + +Retorna um boolean indicando se a janela pode ter seu tamanho redefinido manualmente pelo usuário. + +### `win.setAlwaysOnTop(flag)` + +* `flag` Boolean + +Define se a janela deve estar sempre em cima de outras janelas. Após definir isso, a janela continua sendo uma janela normal, não uma janela *toolbox* que não pode receber foco. + +### `win.isAlwaysOnTop()` + +Retorna um boolean indicando se a janela está sempre em cima de outras janelas. + +### `win.center()` + +Move a janela para o centro da tela. + +### `win.setPosition(x, y)` + +* `x` Integer +* `y` Integer + +Move a janela para `x` e `y`. + +### `win.getPosition()` + +Retorna um array com a posição atual da janela. + +### `win.setTitle(title)` + +* `title` String + +Muda o título da janela nativa para `title`. + +### `win.getTitle()` + +Retorna o título da janela nativa. + +**Nota:** O título da página web pode ser diferente do título da janela nativa. + +### `win.flashFrame(flag)` + +* `flag` Boolean + +Inicia ou para de piscar a janela para atrair a atenção do usuário. + +### `win.setSkipTaskbar(skip)` + +* `skip` Boolean + +Faz com que a janela não apareça na barra de tarefas. + +### `win.setKiosk(flag)` + +* `flag` Boolean + +Entra ou sai do modo *kiosk*. + +### `win.isKiosk()` + +Retorna um boolean indicando se janela está no modo *kiosk*. + +### `win.hookWindowMessage(message, callback)` _Windows_ + +* `message` Integer +* `callback` Function + +Engancha uma mensagem de janela. O `callback` é chamado quando a mensagem é recebida no WndProc. + +### `win.isWindowMessageHooked(message)` _Windows_ + +* `message` Integer + +Retorna `true` ou `false` indicando se a mensagem está enganchada ou não. + +### `win.unhookWindowMessage(message)` _Windows_ + +* `message` Integer + +Desengancha a mensagem de janela. + +### `win.unhookAllWindowMessages()` _Windows_ + +Desengancha todas as mensagens de janela. + +### `win.setRepresentedFilename(filename)` _OS X_ + +* `filename` String + +Define o endereço do arquivo que a janela representa, e o ícone do arquivo será exibido na barra de título da janela. + +### `win.getRepresentedFilename()` _OS X_ + +Retorna o endereço do arquivo que a janela representa. + +### `win.setDocumentEdited(edited)` _OS X_ + +* `edited` Boolean + +Define se o documento da janela foi editado, e o ícone na barra de título se torna cinza quando definido como `true`. + +### `win.isDocumentEdited()` _OS X_ + +Retorna um boolean indicando se o documento da janela foi editado. + +### `win.focusOnWebView()` + +### `win.blurWebView()` + +### `win.capturePage([rect, ]callback)` + +* `rect` Object (opcional)- A área da página a ser capturada. Propriedades: + * `x` Integer + * `y` Integer + * `width` Integer + * `height` Integer +* `callback` Function + +Captura uma imagem da página dentro do `rect`. Após completar, `callback` será chamada com `callback(imagem)`. `imagem` é uma instância de [NativeImage](../../../docs/api/native-image.md) que guarda dados sobre a imagem. Omitir `rect` captura toda a página visível. + +### `win.print([options])` + +Igual a `webContents.print([options])` + +### `win.printToPDF(options, callback)` + +Igual a `webContents.printToPDF(options, callback)` + +### `win.loadURL(url[, options])` + +Igual a `webContents.loadURL(url[, options])`. + +### `win.reload()` + +Igual a `webContents.reload`. + +### `win.setMenu(menu)` _Linux_ _Windows_ + +* `menu` Menu + +Define `menu` como a barra de menu da janela, definir como `null` remove a barra de menu. + +### `win.setProgressBar(progress)` + +* `progress` Double + +Define o valor do progresso na barra de progresso. Extensão válida é [0, 1.0]. + +Remove a barra de progresso quando `progress` < 0. +Muda para o modo indeterminado quando `progress` > 1. + +Na plataforma Linux, apenas suporta o ambiente de desktop Unity, você precisa definir o nome do arquivo como `*.desktop` no campo `desktopName` no `package.json`. Por padrão, irá assumir `app.getName().desktop`. + +### `win.setOverlayIcon(overlay, description)` _Windows 7+_ + +* `overlay` [NativeImage](../../../docs/api/native-image.md) - o ícone a ser exibido no canto inferior direito da barra de tarefas. Se este parâmetro for `null`, a sobreposição é eliminada. +* `description` String - uma descrição que será providenciada a leitores de tela de acessibilidade. + +Define uma sobreposição de 16px sobre o ícone da barra de tarefas atual, geralmente utilizado para indicar algum tipo de status de aplicação, ou notificar passivamente o usuário. + +### `win.setThumbarButtons(buttons)` _Windows 7+_ + +`buttons` Array de objetos `button`: + +`button` Object, propriedades: + +* `icon` [NativeImage](../../../docs/api/native-image.md) - O ícone exibido na barra de ferramentas miniatura. +* `tooltip` String (opcional) - O texto do balão de dica do botão. +* `flags` Array (opcional) - Controla estados e comportamentos específicos do botão. Utiliza `enabled` por padrão. Pode incluir as seguintes strings: + * `enabled` - O botão está ativo e disponível para o usuário. + * `disabled` - O botão está desabilitado. Está presente, mas possui um estado visual indicando que não irá responder às ações do usuário. + * `dismissonclick` - Quando o botão é clicado, o *flyout* do botão da barra de tarefas fecha imediatamente. + * `nobackground` - Não desenhe a borda do botão, apenas utilize a imagem. + * `hidden` - O botão não é exibido para o usuário. + * `noninteractive` - O botão está habilitado, mas não interage; Não é exibido o estado de botão pressionado. Este valor está destinado a instâncias nas quais o botão é utilizado em uma notificação. +* `click` - Função + +Adiciona uma barra de ferramentes miniatura com um conjunto de botões específicos à imagem miniatura de uma janela no layout de um botão de barra de tarefas. Retorna um objeto `Boolean` indicando se a miniatura foi adicionada com sucesso. + +O número de botões na barra de ferramentas miniatura não deve ser maior que 7 devido ao espaço limitado. Uma vez que você define a barra de ferramentas miniatura, ela não pode ser removida por causa da limitação da plataforma. Mas você pode chamar a API com um array vazio para limpar todos os botões. + +### `win.showDefinitionForSelection()` _OS X_ + +Mostra um dicionário *pop-up* que procura a palavra selecionada na página. + +### `win.setAutoHideMenuBar(hide)` + +* `hide` Boolean + +Define se a barra de menu da janela deve se esconder automaticamente. Uma vez que for definida, a barra de menu só será exibida quando usuários pressionarem a tecla `Alt`. + +Se a barra de menu já estiver visível, chamar `setAutoHideMenuBar(true)` não irá escondê-la imediatamente. + +### `win.isMenuBarAutoHide()` + +Retorna um boolean indicando se a barra de menu se esconde automaticamente. + +### `win.setMenuBarVisibility(visible)` + +* `visible` Boolean + +Define se a barra de menu deve ser visível. Se a barra de menu se esconde automaticamente, os usuários ainda podem exibí-la ao pressionar a tecla `Alt`. + +### `win.isMenuBarVisible()` + +Retorna um boolean indicando se a barra de menu está visível. + +### `win.setVisibleOnAllWorkspaces(visible)` + +* `visible` Boolean + +Define se a janela deve estar visível em todos os *workspaces*. + +**Nota:** Esta API não faz nada no Windows. + +### `win.isVisibleOnAllWorkspaces()` + +Retorna um boolean indicando se a janela está visível em todos os *workspaces*. + +**Nota:** Esta API sempre retorna `false` no Windows. + + From c6167bdf0a058808d32b2f2ea3bc32e64ce8cf76 Mon Sep 17 00:00:00 2001 From: Clark Feusier Date: Fri, 4 Dec 2015 21:51:33 -0800 Subject: [PATCH 20/67] Fix broken link in Docs > Synopsis --- docs/api/synopsis.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/synopsis.md b/docs/api/synopsis.md index fcb7da2c1cd2..6886c6d78c41 100644 --- a/docs/api/synopsis.md +++ b/docs/api/synopsis.md @@ -11,7 +11,7 @@ both processes. The basic rule is: if a module is [GUI][gui] or low-level system related, then it should be only available in the main process. You need to be familiar with -the concept of [main process vs. renderer process][mai-process] scripts to be +the concept of [main process vs. renderer process][main-process] scripts to be able to use those modules. The main process script is just like a normal Node.js script: From a1154ad8168958f63e5b932a44b743dd911df458 Mon Sep 17 00:00:00 2001 From: "howard.zuo" Date: Sat, 5 Dec 2015 14:49:01 +0800 Subject: [PATCH 21/67] add ZH-CN translation for using-selenium-and-webdriver --- .../tutorial/using-selenium-and-webdriver.md | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 docs-translations/zh-CN/tutorial/using-selenium-and-webdriver.md diff --git a/docs-translations/zh-CN/tutorial/using-selenium-and-webdriver.md b/docs-translations/zh-CN/tutorial/using-selenium-and-webdriver.md new file mode 100644 index 000000000000..c05a3190eea1 --- /dev/null +++ b/docs-translations/zh-CN/tutorial/using-selenium-and-webdriver.md @@ -0,0 +1,119 @@ +# 使用Selenium和WebDriver + +引自[ChromeDriver - WebDriver for Chrome][chrome-driver]: + +> WebDriver是一款开源的支持多浏览器的自动化测试工具。它提供了操作网页、用户输入、JavaScript执行等能力。ChromeDriver是一个实现了WebDriver与Chromium联接协议的独立服务。它也是由开发了Chromium和WebDriver的团队开发的。 + +为了能够使`chromedriver`和Electron一起正常工作,我们需要告诉它Electron在哪,并且让它相信Electron就是Chrome浏览器。 + +## 通过WebDriverJs配置 + +[WebDriverJs](https://code.google.com/p/selenium/wiki/WebDriverJs) 是一个可以配合WebDriver做测试的node模块,我们会用它来做个演示。 + +### 1. 启动ChromeDriver + +首先,你要下载`chromedriver`,然后运行以下命令: + +```bash +$ ./chromedriver +Starting ChromeDriver (v2.10.291558) on port 9515 +Only local connections are allowed. +``` + +记住`9515`这个端口号,我们后面会用到 + +### 2. 安装WebDriverJS + +```bash +$ npm install selenium-webdriver +``` + +### 3. 联接到ChromeDriver + +在Electron下使用`selenium-webdriver`和其平时的用法并没有大的差异,只是你需要手动设置连接ChromeDriver,以及Electron的路径: + +```javascript +const webdriver = require('selenium-webdriver'); + +var driver = new webdriver.Builder() + // "9515" 是ChromeDriver使用的端口 + .usingServer('http://localhost:9515') + .withCapabilities({ + chromeOptions: { + // 这里设置Electron的路径 + binary: '/Path-to-Your-App.app/Contents/MacOS/Atom', + } + }) + .forBrowser('electron') + .build(); + +driver.get('http://www.google.com'); +driver.findElement(webdriver.By.name('q')).sendKeys('webdriver'); +driver.findElement(webdriver.By.name('btnG')).click(); +driver.wait(function() { + return driver.getTitle().then(function(title) { + return title === 'webdriver - Google Search'; + }); +}, 1000); + +driver.quit(); +``` + +## 通过WebdriverIO配置 + +[WebdriverIO](http://webdriver.io/)也是一个配合WebDriver用来测试的node模块 + +### 1. 启动ChromeDriver + +首先,下载`chromedriver`,然后运行以下命令: + +```bash +$ chromedriver --url-base=wd/hub --port=9515 +Starting ChromeDriver (v2.10.291558) on port 9515 +Only local connections are allowed. +``` + +记住`9515`端口,后面会用到 + +### 2. 安装WebdriverIO + +```bash +$ npm install webdriverio +``` + +### 3. 连接到ChromeDriver + +```javascript +const webdriverio = require('webdriverio'); +var options = { + host: "localhost", // 使用localhost作为ChromeDriver服务器 + port: 9515, // "9515"是ChromeDriver使用的端口 + desiredCapabilities: { + browserName: 'chrome', + chromeOptions: { + binary: '/Path-to-Your-App/electron', // Electron的路径 + args: [/* cli arguments */] // 可选参数,类似:'app=' + /path/to/your/app/ + } + } +}; + +var client = webdriverio.remote(options); + +client + .init() + .url('http://google.com') + .setValue('#q', 'webdriverio') + .click('#btnG') + .getTitle().then(function(title) { + console.log('Title was: ' + title); + }) + .end(); +``` + +## 工作流程 + +无需重新编译Electron,只要把app的源码放到[Electron的资源目录](https://github.com/atom/electron/blob/master/docs/tutorial/application-distribution.md)里就可直接开始测试了。 + +当然,你也可以在运行Electron时传入参数指定你app的所在文件夹。这步可以免去你拷贝-粘贴你的app到Electron的资源目录。 + +[chrome-driver]: https://sites.google.com/a/chromium.org/chromedriver/ From e6adf36d9856b365d090a8342ab0b70ef87ed0e9 Mon Sep 17 00:00:00 2001 From: Artur de Oliveira Tsuda Date: Sat, 5 Dec 2015 10:39:03 -0200 Subject: [PATCH 22/67] :memo: [ci skip] translation build instructions --- .../development/build-instructions-linux.md | 142 ++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 docs-translations/pt-BR/development/build-instructions-linux.md diff --git a/docs-translations/pt-BR/development/build-instructions-linux.md b/docs-translations/pt-BR/development/build-instructions-linux.md new file mode 100644 index 000000000000..532892a40833 --- /dev/null +++ b/docs-translations/pt-BR/development/build-instructions-linux.md @@ -0,0 +1,142 @@ +# Instruções de Build (Linux) + +Siga as orientações abaixo pra fazer o build do Electron no Linux. + +## Pré-requisitos + +* Python 2.7.x. Algumas distribuições como CentOS ainda usam Python 2.6.x, + então você precisa checar a sua versão do Python com `python -V`. +* Node.js v0.12.x. Há várias maneiras de instalar o Node. Você pode baixar o + código fonte do [Node.js](http://nodejs.org) e compilar a partir dele. + Fazer isto permite que você instale o Node no seu próprio diretório home + como um usuário comum. + Ou tente repositórios como [NodeSource](https://nodesource.com/blog/nodejs-v012-iojs-and-the-nodesource-linux-repositories). +* Clang 3.4 ou mais recente. +* Cabeçalhos de desenvolvimento do GTK+ e libnotify. + +No Ubuntu, instale as seguintes bibliotecas: + +```bash +$ sudo apt-get install build-essential clang libdbus-1-dev libgtk2.0-dev \ + libnotify-dev libgnome-keyring-dev libgconf2-dev \ + libasound2-dev libcap-dev libcups2-dev libxtst-dev \ + libxss1 libnss3-dev gcc-multilib g++-multilib +``` + +No Fedora, instale as seguintes bibliotecas: + +```bash +$ sudo yum install clang dbus-devel gtk2-devel libnotify-devel libgnome-keyring-devel \ + xorg-x11-server-utils libcap-devel cups-devel libXtst-devel \ + alsa-lib-devel libXrandr-devel GConf2-devel nss-devel +``` + +Outras distribuições podem oferecer pacotes similares para instalação através +do gerenciador de pacotes como o pacman. Ou você pode compilar a partir do +código fonte. + +## Se Você Utilizar Máquinas Virtuais Para Fazer O Build + +Se você planeja fazer o build do Electron numa máquina virtual, você vai precisar +de um container de tamanho fixo de pelo menos 25 gigabytes. + +## Baixando o Código + +```bash +$ git clone https://github.com/atom/electron.git +``` + +## Bootstrapping + +O script de *boostrap* irá baixar todas as dependências de build necessárias +e criar os arquivos de projeto do build. Você deve ter o Python 2.7.x para +executar o script com sucesso. +Baixar certos arquivos pode demorar bastante. Note que estamos utilizando +`ninja` para fazer o build do Electron, então não há um `Makefile` gerado. + +```bash +$ cd electron +$ ./script/bootstrap.py -v +``` + +### Compilação Cruzada + +Se você quer fazer o build para `arm`, você também deve instalar as seguintes +dependências: + +```bash +$ sudo apt-get install libc6-dev-armhf-cross linux-libc-dev-armhf-cross \ + g++-arm-linux-gnueabihf +``` + +E para fazer a compilação cruzada para `arm` ou `ia32`, você deve passar +o parâmetro `--target_arch` para o script `bootstrap.py`: + +```bash +$ ./script/bootstrap.py -v --target_arch=arm +``` + +## Building + +Se você quiser fazer o build para `Release` e `Debug`: + +```bash +$ ./script/build.py +``` + +Este script irá fazer com que um executável bem pesado do Electron seja +criado no diretório `out/R`. O arquivo possui mais de 1.3 gigabytes. +Isso acontece por que o binário do Release contém símbolos de debugging. +Para reduzir o tamanho do arquivo, rode o script `create-dist.py`: + +```bash +$ ./script/create-dist.py +``` + +Isso irá colocar uma distribuição funcional com arquivos muito menores +no diretório `dist`. Depois de rodar o script `create-dist.py`, talvez +você queira remover o binário de 1.3+ gigabytes que ainda está em `out/R`. + +Você também pode fazer apenas o build de `Debug`: + +```bash +$ ./script/build.py -c D +``` + +Depois de completar o build, você pode encontrar o binário de debug do `electron` +em `out/D`. + +## Limpando + +Para limpar os arquivos de build: + +```bash +$ ./script/clean.py +``` + +## Troubleshooting + +Certifique-se de que você tenha instalado todas as dependências do build. + +### Error While Loading Shared Libraries: libtinfo.so.5 + +O `clang` prebuilt irá tentar fazer o link com `libtinfo.so.5`. Dependendo +da arquitetura do host, faça um link simbólico para o `libncurses` apropriado: + +```bash +$ sudo ln -s /usr/lib/libncurses.so.5 /usr/lib/libtinfo.so.5 +``` + +## Testes + +Teste suas modificações conforme o estilo de código do projeto utilizando: + +```bash +$ ./script/cpplint.py +``` + +Teste funcionalidade utilizando: + +```bash +$ ./script/test.py +``` From 5f092a6c658c0d3f82ffcd9bac5975b124656b5a Mon Sep 17 00:00:00 2001 From: billyct Date: Sun, 6 Dec 2015 10:14:54 +0800 Subject: [PATCH 23/67] support an api with SetIgnoreMouseEvents, and worked fine with osx --- atom/browser/api/atom_api_window.cc | 5 +++++ atom/browser/api/atom_api_window.h | 1 + atom/browser/native_window.cc | 3 +++ atom/browser/native_window.h | 1 + atom/browser/native_window_mac.h | 1 + atom/browser/native_window_mac.mm | 4 ++++ 6 files changed, 15 insertions(+) diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 84e5c53ebe65..08b5bc4f7b7a 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -488,6 +488,10 @@ bool Window::IsDocumentEdited() { return window_->IsDocumentEdited(); } +void Window::SetIgnoreMouseEvents(bool ignore) { + return window_->SetIgnoreMouseEvents(ignore); +} + void Window::CapturePage(mate::Arguments* args) { gfx::Rect rect; base::Callback callback; @@ -662,6 +666,7 @@ void Window::BuildPrototype(v8::Isolate* isolate, .SetMethod("getRepresentedFilename", &Window::GetRepresentedFilename) .SetMethod("setDocumentEdited", &Window::SetDocumentEdited) .SetMethod("isDocumentEdited", &Window::IsDocumentEdited) + .SetMethod("setIgnoreMouseEvents", &Window::SetIgnoreMouseEvents) .SetMethod("focusOnWebView", &Window::FocusOnWebView) .SetMethod("blurWebView", &Window::BlurWebView) .SetMethod("isWebViewFocused", &Window::IsWebViewFocused) diff --git a/atom/browser/api/atom_api_window.h b/atom/browser/api/atom_api_window.h index 6d5ce22f4316..3611c6e33fbc 100644 --- a/atom/browser/api/atom_api_window.h +++ b/atom/browser/api/atom_api_window.h @@ -126,6 +126,7 @@ class Window : public mate::TrackableObject, std::string GetRepresentedFilename(); void SetDocumentEdited(bool edited); bool IsDocumentEdited(); + void SetIgnoreMouseEvents(bool ignore); void CapturePage(mate::Arguments* args); void SetProgressBar(double progress); void SetOverlayIcon(const gfx::Image& overlay, diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index a3df240e4d57..787567012676 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -245,6 +245,9 @@ bool NativeWindow::IsDocumentEdited() { return false; } +void NativeWindow::SetIgnoreMouseEvents(bool ignore) { +} + void NativeWindow::SetMenu(ui::MenuModel* menu) { } diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index 0c918d92df99..3eb235b03c66 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -139,6 +139,7 @@ class NativeWindow : public base::SupportsUserData, virtual std::string GetRepresentedFilename(); virtual void SetDocumentEdited(bool edited); virtual bool IsDocumentEdited(); + virtual void SetIgnoreMouseEvents(bool ignore); virtual void SetMenu(ui::MenuModel* menu); virtual bool HasModalDialog(); virtual gfx::NativeWindow GetNativeWindow() = 0; diff --git a/atom/browser/native_window_mac.h b/atom/browser/native_window_mac.h index 08f9198e4ff1..38845140e694 100644 --- a/atom/browser/native_window_mac.h +++ b/atom/browser/native_window_mac.h @@ -62,6 +62,7 @@ class NativeWindowMac : public NativeWindow { std::string GetRepresentedFilename() override; void SetDocumentEdited(bool edited) override; bool IsDocumentEdited() override; + void SetIgnoreMouseEvents(bool ignore) override; bool HasModalDialog() override; gfx::NativeWindow GetNativeWindow() override; void SetProgressBar(double progress) override; diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 42894c107de4..049c3eefea9f 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -687,6 +687,10 @@ bool NativeWindowMac::IsDocumentEdited() { return [window_ isDocumentEdited]; } +void NativeWindowMac::SetIgnoreMouseEvents(bool ignore) { + [window_ setIgnoresMouseEvents:ignore]; +} + bool NativeWindowMac::HasModalDialog() { return [window_ attachedSheet] != nil; } From 766bbfcb056d53d809a97b67d0ed81d6c3533834 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 7 Dec 2015 15:14:31 +0800 Subject: [PATCH 24/67] Chrome 47.0.2526.73 --- script/lib/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/lib/config.py b/script/lib/config.py index 2fb841acf35c..4978302abb0f 100644 --- a/script/lib/config.py +++ b/script/lib/config.py @@ -8,7 +8,7 @@ import sys BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \ 'http://gh-contractor-zcbenz.s3.amazonaws.com/libchromiumcontent' -LIBCHROMIUMCONTENT_COMMIT = '17a4337f7948a45b5ea4b8f391df152ba8db5979' +LIBCHROMIUMCONTENT_COMMIT = 'd534691711ecdef1739878674a9ffd5f2d5ac4a2' PLATFORM = { 'cygwin': 'win32', From 73e7773d841cdb82a3460ab6b3ade1892861b396 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 7 Dec 2015 19:56:23 +0800 Subject: [PATCH 25/67] Update to API changes of Chrome 47 --- atom/app/atom_content_client.cc | 19 ++-- atom/app/atom_content_client.h | 2 +- atom/browser/api/atom_api_session.cc | 7 +- atom/browser/api/atom_api_web_contents.cc | 4 +- atom/browser/api/frame_subscriber.cc | 9 +- atom/browser/atom_browser_client.cc | 3 +- atom/browser/atom_browser_context.cc | 12 +- atom/browser/atom_browser_context.h | 4 +- atom/browser/common_web_contents_delegate.cc | 2 +- atom/browser/native_window.cc | 4 +- atom/browser/native_window_mac.mm | 43 ++++--- atom/browser/native_window_views.cc | 2 +- atom/browser/net/url_request_fetch_job.cc | 8 +- atom/browser/net/url_request_fetch_job.h | 1 + atom/browser/ui/accelerator_util.cc | 6 +- .../ui/cocoa/event_processing_window.h | 30 ----- .../ui/cocoa/event_processing_window.mm | 106 ------------------ atom/browser/ui/message_box_gtk.cc | 2 +- atom/browser/ui/message_box_win.cc | 2 +- atom/browser/ui/x/x_window_utils.cc | 2 +- atom/browser/web_contents_preferences.cc | 4 - atom/common/api/atom_api_native_image.cc | 3 +- atom/common/api/event_emitter_caller.cc | 2 +- atom/common/crash_reporter/crash_reporter.cc | 8 +- .../crash_reporter/crash_reporter_linux.cc | 2 +- .../crash_reporter/crash_reporter_linux.h | 4 +- .../crash_reporter/crash_reporter_mac.h | 4 +- .../crash_reporter/crash_reporter_mac.mm | 2 +- .../crash_reporter/crash_reporter_win.cc | 2 +- .../crash_reporter/crash_reporter_win.h | 4 +- .../native_mate_converters/blink_converter.cc | 10 +- atom/common/native_mate_converters/callback.h | 6 +- atom/common/node_bindings.cc | 2 +- atom/common/options_switches.cc | 2 - atom/common/options_switches.h | 2 - atom/renderer/atom_renderer_client.cc | 2 - .../printing/print_view_manager_base.cc | 2 +- .../chrome/browser/process_singleton_posix.cc | 2 +- .../browser/speech/tts_controller_impl.cc | 2 +- .../browser/speech/tts_controller_impl.h | 4 +- chromium_src/chrome/browser/speech/tts_mac.mm | 4 +- .../pepper/pepper_flash_renderer_host.cc | 3 +- .../printing/print_web_view_helper.cc | 1 - docs/api/browser-window.md | 3 - filenames.gypi | 2 - vendor/brightray | 2 +- 46 files changed, 113 insertions(+), 239 deletions(-) delete mode 100644 atom/browser/ui/cocoa/event_processing_window.h delete mode 100644 atom/browser/ui/cocoa/event_processing_window.mm diff --git a/atom/app/atom_content_client.cc b/atom/app/atom_content_client.cc index 0931a1b55a41..9f161ac569a6 100644 --- a/atom/app/atom_content_client.cc +++ b/atom/app/atom_content_client.cc @@ -31,8 +31,8 @@ content::PepperPluginInfo CreatePepperFlashInfo(const base::FilePath& path, plugin.path = path; plugin.permissions = ppapi::PERMISSION_ALL_BITS; - std::vector flash_version_numbers; - base::SplitString(version, '.', &flash_version_numbers); + std::vector flash_version_numbers = base::SplitString( + version, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); if (flash_version_numbers.size() < 1) flash_version_numbers.push_back("11"); // |SplitString()| puts in an empty string given an empty string. :( @@ -47,7 +47,7 @@ content::PepperPluginInfo CreatePepperFlashInfo(const base::FilePath& path, // E.g., "Shockwave Flash 10.2 r154": plugin.description = plugin.name + " " + flash_version_numbers[0] + "." + flash_version_numbers[1] + " r" + flash_version_numbers[2]; - plugin.version = JoinString(flash_version_numbers, '.'); + plugin.version = base::JoinString(flash_version_numbers, "."); content::WebPluginMimeType swf_mime_type( content::kFlashPluginSwfMimeType, content::kFlashPluginSwfExtension, @@ -81,19 +81,18 @@ std::string AtomContentClient::GetUserAgent() const { } void AtomContentClient::AddAdditionalSchemes( - std::vector* standard_schemes, + std::vector* standard_schemes, std::vector* savable_schemes) { auto command_line = base::CommandLine::ForCurrentProcess(); auto custom_schemes = command_line->GetSwitchValueASCII( switches::kRegisterStandardSchemes); if (!custom_schemes.empty()) { - std::vector schemes; - base::SplitString(custom_schemes, ',', &schemes); - standard_schemes->insert(standard_schemes->end(), - schemes.begin(), - schemes.end()); + std::vector schemes = base::SplitString( + custom_schemes, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + for (const std::string& scheme : schemes) + standard_schemes->push_back({scheme.c_str(), url::SCHEME_WITHOUT_PORT}); } - standard_schemes->push_back("chrome-extension"); + standard_schemes->push_back({"chrome-extension", url::SCHEME_WITHOUT_PORT}); } void AtomContentClient::AddPepperPlugins( diff --git a/atom/app/atom_content_client.h b/atom/app/atom_content_client.h index a6b2f73e7faa..2716b1eea400 100644 --- a/atom/app/atom_content_client.h +++ b/atom/app/atom_content_client.h @@ -22,7 +22,7 @@ class AtomContentClient : public brightray::ContentClient { std::string GetProduct() const override; std::string GetUserAgent() const override; void AddAdditionalSchemes( - std::vector* standard_schemes, + std::vector* standard_schemes, std::vector* savable_schemes) override; void AddPepperPlugins( std::vector* plugins) override; diff --git a/atom/browser/api/atom_api_session.cc b/atom/browser/api/atom_api_session.cc index f39073825c00..9cec7378b8e0 100644 --- a/atom/browser/api/atom_api_session.cc +++ b/atom/browser/api/atom_api_session.cc @@ -51,7 +51,7 @@ struct ClearStorageDataOptions { uint32 GetStorageMask(const std::vector& storage_types) { uint32 storage_mask = 0; for (const auto& it : storage_types) { - auto type = base::StringToLowerASCII(it); + auto type = base::ToLowerASCII(it); if (type == "appcache") storage_mask |= StoragePartition::REMOVE_DATA_MASK_APPCACHE; else if (type == "cookies") @@ -75,7 +75,7 @@ uint32 GetStorageMask(const std::vector& storage_types) { uint32 GetQuotaMask(const std::vector& quota_types) { uint32 quota_mask = 0; for (const auto& it : quota_types) { - auto type = base::StringToLowerASCII(it); + auto type = base::ToLowerASCII(it); if (type == "temporary") quota_mask |= StoragePartition::QUOTA_MANAGED_STORAGE_MASK_TEMPORARY; else if (type == "persistent") @@ -233,7 +233,8 @@ void SetProxyInIO(net::URLRequestContextGetter* getter, const net::ProxyConfig& config, const base::Closure& callback) { auto proxy_service = getter->GetURLRequestContext()->proxy_service(); - proxy_service->ResetConfigService(new net::ProxyConfigServiceFixed(config)); + proxy_service->ResetConfigService(make_scoped_ptr( + new net::ProxyConfigServiceFixed(config))); // Refetches and applies the new pac script if provided. proxy_service->ForceReloadProxyConfig(); RunCallbackInUI(callback); diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index b16ab8c89960..a70b6cf4e0b2 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -148,7 +148,7 @@ struct Converter { std::string key; std::string value; while (headers->EnumerateHeaderLines(&iter, &key, &value)) { - key = base::StringToLowerASCII(key); + key = base::ToLowerASCII(key); if (response_headers.HasKey(key)) { base::ListValue* values = nullptr; if (response_headers.GetList(key, &values)) @@ -171,7 +171,7 @@ struct Converter { std::string save_type; if (!ConvertFromV8(isolate, val, &save_type)) return false; - save_type = base::StringToLowerASCII(save_type); + save_type = base::ToLowerASCII(save_type); if (save_type == "htmlonly") { *out = content::SAVE_PAGE_TYPE_AS_ONLY_HTML; } else if (save_type == "htmlcomplete") { diff --git a/atom/browser/api/frame_subscriber.cc b/atom/browser/api/frame_subscriber.cc index cf0eae14a9a8..5b7241486b72 100644 --- a/atom/browser/api/frame_subscriber.cc +++ b/atom/browser/api/frame_subscriber.cc @@ -24,12 +24,11 @@ bool FrameSubscriber::ShouldCaptureFrame( base::TimeTicks present_time, scoped_refptr* storage, DeliverFrameCallback* callback) { - *storage = media::VideoFrame::CreateFrame(media::VideoFrame::YV12, size_, - gfx::Rect(size_), size_, - base::TimeDelta()); + *storage = media::VideoFrame::CreateFrame( + media::PIXEL_FORMAT_YV12, + size_, gfx::Rect(size_), size_, base::TimeDelta()); *callback = base::Bind(&FrameSubscriber::OnFrameDelivered, - base::Unretained(this), - *storage); + base::Unretained(this), *storage); return true; } diff --git a/atom/browser/atom_browser_client.cc b/atom/browser/atom_browser_client.cc index 38fdc0e19f9e..b9b186d187d0 100644 --- a/atom/browser/atom_browser_client.cc +++ b/atom/browser/atom_browser_client.cc @@ -84,7 +84,7 @@ void AtomBrowserClient::SuppressRendererProcessRestartForOnce() { void AtomBrowserClient::SetCustomSchemes( const std::vector& schemes) { - g_custom_schemes = JoinString(schemes, ','); + g_custom_schemes = base::JoinString(schemes, ","); } AtomBrowserClient::AtomBrowserClient() : delegate_(nullptr) { @@ -116,7 +116,6 @@ void AtomBrowserClient::OverrideWebkitPrefs( prefs->javascript_can_open_windows_automatically = true; prefs->plugins_enabled = true; prefs->dom_paste_enabled = true; - prefs->java_enabled = false; prefs->allow_scripts_to_close_windows = true; prefs->javascript_can_access_clipboard = true; prefs->local_storage_enabled = true; diff --git a/atom/browser/atom_browser_context.cc b/atom/browser/atom_browser_context.cc index 08c799962728..b9589d569b68 100644 --- a/atom/browser/atom_browser_context.cc +++ b/atom/browser/atom_browser_context.cc @@ -61,7 +61,7 @@ std::string RemoveWhitespace(const std::string& str) { AtomBrowserContext::AtomBrowserContext(const std::string& partition, bool in_memory) : brightray::BrowserContext(partition, in_memory), - cert_verifier_(new AtomCertVerifier), + cert_verifier_(nullptr), job_factory_(new AtomURLRequestJobFactory), allow_ntlm_everywhere_(false) { } @@ -86,7 +86,7 @@ std::string AtomBrowserContext::GetUserAgent() { return content::BuildUserAgentFromProduct(user_agent); } -net::URLRequestJobFactory* AtomBrowserContext::CreateURLRequestJobFactory( +scoped_ptr AtomBrowserContext::CreateURLRequestJobFactory( content::ProtocolHandlerMap* handlers, content::URLRequestInterceptorScopedVector* interceptors) { scoped_ptr job_factory(job_factory_); @@ -131,7 +131,7 @@ net::URLRequestJobFactory* AtomBrowserContext::CreateURLRequestJobFactory( top_job_factory.Pass(), make_scoped_ptr(*it))); interceptors->weak_clear(); - return top_job_factory.release(); + return top_job_factory.Pass(); } net::HttpCache::BackendFactory* @@ -160,8 +160,10 @@ content::BrowserPluginGuestManager* AtomBrowserContext::GetGuestManager() { return guest_manager_.get(); } -net::CertVerifier* AtomBrowserContext::CreateCertVerifier() { - return cert_verifier_; +scoped_ptr AtomBrowserContext::CreateCertVerifier() { + DCHECK(!cert_verifier_); + cert_verifier_ = new AtomCertVerifier; + return make_scoped_ptr(cert_verifier_); } net::SSLConfigService* AtomBrowserContext::CreateSSLConfigService() { diff --git a/atom/browser/atom_browser_context.h b/atom/browser/atom_browser_context.h index d3d7735c810d..564c9955d917 100644 --- a/atom/browser/atom_browser_context.h +++ b/atom/browser/atom_browser_context.h @@ -23,12 +23,12 @@ class AtomBrowserContext : public brightray::BrowserContext { // brightray::URLRequestContextGetter::Delegate: std::string GetUserAgent() override; - net::URLRequestJobFactory* CreateURLRequestJobFactory( + scoped_ptr CreateURLRequestJobFactory( content::ProtocolHandlerMap* handlers, content::URLRequestInterceptorScopedVector* interceptors) override; net::HttpCache::BackendFactory* CreateHttpCacheBackendFactory( const base::FilePath& base_path) override; - net::CertVerifier* CreateCertVerifier() override; + scoped_ptr CreateCertVerifier() override; net::SSLConfigService* CreateSSLConfigService() override; bool AllowNTLMCredentialsForDomain(const GURL& auth_origin) override; diff --git a/atom/browser/common_web_contents_delegate.cc b/atom/browser/common_web_contents_delegate.cc index 8b7a159dd7d6..72a664f8cd00 100644 --- a/atom/browser/common_web_contents_delegate.cc +++ b/atom/browser/common_web_contents_delegate.cc @@ -380,7 +380,7 @@ gfx::ImageSkia CommonWebContentsDelegate::GetDevToolsWindowIcon() { void CommonWebContentsDelegate::GetDevToolsWindowWMClass( std::string* name, std::string* class_name) { *class_name = Browser::Get()->GetName(); - *name = base::StringToLowerASCII(*class_name); + *name = base::ToLowerASCII(*class_name); } #endif diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index a3df240e4d57..666da2d6b71d 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -291,10 +291,10 @@ void NativeWindow::CapturePage(const gfx::Rect& rect, const float scale = screen->GetDisplayNearestWindow(native_view).device_scale_factor(); if (scale > 1.0f) - bitmap_size = gfx::ToCeiledSize(gfx::ScaleSize(view_size, scale)); + bitmap_size = gfx::ScaleToCeiledSize(view_size, scale); host->CopyFromBackingStore( - rect.IsEmpty() ? gfx::Rect(view_size) : rect, + gfx::Rect(view_size), bitmap_size, base::Bind(&NativeWindow::OnCapturePageDone, weak_factory_.GetWeakPtr(), diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 42894c107de4..d7ed15cf0708 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -6,7 +6,6 @@ #include -#import "atom/browser/ui/cocoa/event_processing_window.h" #include "atom/common/draggable_region.h" #include "atom/common/options_switches.h" #include "base/mac/mac_util.h" @@ -19,6 +18,7 @@ #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host_view.h" #include "native_mate/dictionary.h" +#import "ui/base/cocoa/command_dispatcher.h" #include "ui/gfx/skia_util.h" namespace { @@ -209,10 +209,11 @@ bool ScopedDisableResize::disable_resize_ = false; @end -@interface AtomNSWindow : EventProcessingWindow { +@interface AtomNSWindow : NSWindow { @private atom::NativeWindowMac* shell_; bool enable_larger_than_screen_; + base::scoped_nsobject commandDispatcher_; } @property BOOL acceptsFirstMouse; @property BOOL disableAutoHideCursor; @@ -226,12 +227,15 @@ bool ScopedDisableResize::disable_resize_ = false; - (void)setShell:(atom::NativeWindowMac*)shell { shell_ = shell; + commandDispatcher_.reset([[CommandDispatcher alloc] initWithOwner:self]); } - (void)setEnableLargerThanScreen:(bool)enable { enable_larger_than_screen_ = enable; } +// NSWindow overrides. + - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen*)screen { // Resizing is disabled. if (ScopedDisableResize::IsResizeDisabled()) @@ -272,6 +276,25 @@ bool ScopedDisableResize::disable_resize_ = false; return !self.disableKeyOrMainWindow; } +// CommandDispatchingWindow implementation. + +- (void)setCommandHandler:(id)commandHandler { +} + +- (BOOL)redispatchKeyEvent:(NSEvent*)event { + return [commandDispatcher_ redispatchKeyEvent:event]; +} + +- (BOOL)defaultPerformKeyEquivalent:(NSEvent*)event { + return [super performKeyEquivalent:event]; +} + +- (void)commandDispatch:(id)sender { +} + +- (void)commandDispatchUsingKeyModifiers:(id)sender { +} + @end @interface ControlRegionView : NSView @@ -766,20 +789,14 @@ void NativeWindowMac::HandleKeyboardEvent( event.type == content::NativeWebKeyboardEvent::Char) return; - if (event.os_event.window == window_.get()) { - EventProcessingWindow* event_window = - static_cast(window_); - DCHECK([event_window isKindOfClass:[EventProcessingWindow class]]); - [event_window redispatchKeyEvent:event.os_event]; - } else { + BOOL handled = [[NSApp mainMenu] performKeyEquivalent:event.os_event]; + if (!handled && event.os_event.window != window_.get()) { // The event comes from detached devtools view, and it has already been - // handled by the devtools itself, we now send it to application menu to - // make menu acclerators work. - BOOL handled = [[NSApp mainMenu] performKeyEquivalent:event.os_event]; - // Handle the cmd+~ shortcut. if (!handled && (event.os_event.modifierFlags & NSCommandKeyMask) && - (event.os_event.keyCode == 50 /* ~ key */)) + (event.os_event.keyCode == 50 /* ~ key */)) { + // Handle the cmd+~ shortcut. Focus(true); + } } } diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index c12ae1986c64..16faee58c5a4 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -180,7 +180,7 @@ NativeWindowViews::NativeWindowViews( // Set WM_WINDOW_ROLE. params.wm_role_name = "browser-window"; // Set WM_CLASS. - params.wm_class_name = base::StringToLowerASCII(name); + params.wm_class_name = base::ToLowerASCII(name); params.wm_class_class = name; #endif diff --git a/atom/browser/net/url_request_fetch_job.cc b/atom/browser/net/url_request_fetch_job.cc index 24a72226606e..f04ecd4060f0 100644 --- a/atom/browser/net/url_request_fetch_job.cc +++ b/atom/browser/net/url_request_fetch_job.cc @@ -14,6 +14,7 @@ #include "net/http/http_response_headers.h" #include "net/url_request/url_fetcher.h" #include "net/url_request/url_fetcher_response_writer.h" +#include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_builder.h" #include "net/url_request/url_request_status.h" @@ -23,7 +24,7 @@ namespace { // Convert string to RequestType. net::URLFetcher::RequestType GetRequestType(const std::string& raw) { - std::string method = base::StringToUpperASCII(raw); + std::string method = base::ToUpperASCII(raw); if (method.empty() || method == "GET") return net::URLFetcher::GET; else if (method == "POST") @@ -138,8 +139,9 @@ net::URLRequestContextGetter* URLRequestFetchJob::CreateRequestContext() { auto task_runner = base::ThreadTaskRunnerHandle::Get(); net::URLRequestContextBuilder builder; builder.set_proxy_service(net::ProxyService::CreateDirect()); - url_request_context_getter_ = - new net::TrivialURLRequestContextGetter(builder.Build(), task_runner); + request_context_ = builder.Build(); + url_request_context_getter_ = new net::TrivialURLRequestContextGetter( + request_context_.get(), task_runner); } return url_request_context_getter_.get(); } diff --git a/atom/browser/net/url_request_fetch_job.h b/atom/browser/net/url_request_fetch_job.h index 189cebf01b18..399f78ae3963 100644 --- a/atom/browser/net/url_request_fetch_job.h +++ b/atom/browser/net/url_request_fetch_job.h @@ -45,6 +45,7 @@ class URLRequestFetchJob : public JsAsker, // Create a independent request context. net::URLRequestContextGetter* CreateRequestContext(); + scoped_ptr request_context_; scoped_refptr url_request_context_getter_; scoped_ptr fetcher_; scoped_refptr pending_buffer_; diff --git a/atom/browser/ui/accelerator_util.cc b/atom/browser/ui/accelerator_util.cc index e25e14b7968c..a0b90e0c7e58 100644 --- a/atom/browser/ui/accelerator_util.cc +++ b/atom/browser/ui/accelerator_util.cc @@ -24,10 +24,10 @@ bool StringToAccelerator(const std::string& description, LOG(ERROR) << "The accelerator string can only contain ASCII characters"; return false; } - std::string shortcut(base::StringToLowerASCII(description)); + std::string shortcut(base::ToLowerASCII(description)); - std::vector tokens; - base::SplitString(shortcut, '+', &tokens); + std::vector tokens = base::SplitString( + shortcut, "+", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); // Now, parse it into an accelerator. int modifiers = ui::EF_NONE; diff --git a/atom/browser/ui/cocoa/event_processing_window.h b/atom/browser/ui/cocoa/event_processing_window.h deleted file mode 100644 index 88242711f8b7..000000000000 --- a/atom/browser/ui/cocoa/event_processing_window.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_COCOA_EVENT_PROCESSING_WINDOW_H_ -#define ATOM_BROWSER_UI_COCOA_EVENT_PROCESSING_WINDOW_H_ - -#import - -// Override NSWindow to access unhandled keyboard events (for command -// processing); subclassing NSWindow is the only method to do -// this. -@interface EventProcessingWindow : NSWindow { - @private - BOOL redispatchingEvent_; - BOOL eventHandled_; -} - -// Sends a key event to |NSApp sendEvent:|, but also makes sure that it's not -// short-circuited to the RWHV. This is used to send keyboard events to the menu -// and the cmd-` handler if a keyboard event comes back unhandled from the -// renderer. The event must be of type |NSKeyDown|, |NSKeyUp|, or -// |NSFlagsChanged|. -// Returns |YES| if |event| has been handled. -- (BOOL)redispatchKeyEvent:(NSEvent*)event; - -- (BOOL)performKeyEquivalent:(NSEvent*)theEvent; -@end - -#endif // ATOM_BROWSER_UI_COCOA_EVENT_PROCESSING_WINDOW_H_ diff --git a/atom/browser/ui/cocoa/event_processing_window.mm b/atom/browser/ui/cocoa/event_processing_window.mm deleted file mode 100644 index d47cdf37b508..000000000000 --- a/atom/browser/ui/cocoa/event_processing_window.mm +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#import "atom/browser/ui/cocoa/event_processing_window.h" - -#include "base/logging.h" -#import "content/public/browser/render_widget_host_view_mac_base.h" - -@interface EventProcessingWindow () -// Duplicate the given key event, but changing the associated window. -- (NSEvent*)keyEventForWindow:(NSWindow*)window fromKeyEvent:(NSEvent*)event; -@end - -@implementation EventProcessingWindow - -- (BOOL)redispatchKeyEvent:(NSEvent*)event { - DCHECK(event); - NSEventType eventType = [event type]; - if (eventType != NSKeyDown && - eventType != NSKeyUp && - eventType != NSFlagsChanged) { - NOTREACHED(); - return YES; // Pretend it's been handled in an effort to limit damage. - } - - // Ordinarily, the event's window should be this window. However, when - // switching between normal and fullscreen mode, we switch out the window, and - // the event's window might be the previous window (or even an earlier one if - // the renderer is running slowly and several mode switches occur). In this - // rare case, we synthesize a new key event so that its associate window - // (number) is our own. - if ([event window] != self) - event = [self keyEventForWindow:self fromKeyEvent:event]; - - // Redispatch the event. - eventHandled_ = YES; - redispatchingEvent_ = YES; - [NSApp sendEvent:event]; - redispatchingEvent_ = NO; - - // If the event was not handled by [NSApp sendEvent:], the sendEvent: - // method below will be called, and because |redispatchingEvent_| is YES, - // |eventHandled_| will be set to NO. - return eventHandled_; -} - -- (void)sendEvent:(NSEvent*)event { - if (!redispatchingEvent_) - [super sendEvent:event]; - else - eventHandled_ = NO; -} - -- (NSEvent*)keyEventForWindow:(NSWindow*)window fromKeyEvent:(NSEvent*)event { - NSEventType eventType = [event type]; - - // Convert the event's location from the original window's coordinates into - // our own. - NSPoint eventLoc = [event locationInWindow]; - eventLoc = [self convertRectFromScreen: - [[event window] convertRectToScreen:NSMakeRect(eventLoc.x, eventLoc.y, 0, 0)]].origin; - - // Various things *only* apply to key down/up. - BOOL eventIsARepeat = NO; - NSString* eventCharacters = nil; - NSString* eventUnmodCharacters = nil; - if (eventType == NSKeyDown || eventType == NSKeyUp) { - eventIsARepeat = [event isARepeat]; - eventCharacters = [event characters]; - eventUnmodCharacters = [event charactersIgnoringModifiers]; - } - - // This synthesis may be slightly imperfect: we provide nil for the context, - // since I (viettrungluu) am sceptical that putting in the original context - // (if one is given) is valid. - return [NSEvent keyEventWithType:eventType - location:eventLoc - modifierFlags:[event modifierFlags] - timestamp:[event timestamp] - windowNumber:[window windowNumber] - context:nil - characters:eventCharacters - charactersIgnoringModifiers:eventUnmodCharacters - isARepeat:eventIsARepeat - keyCode:[event keyCode]]; -} - - -- (BOOL)performKeyEquivalent:(NSEvent*)event { - if (redispatchingEvent_) - return NO; - - // Give the web site a chance to handle the event. If it doesn't want to - // handle it, it will call us back with one of the |handle*| methods above. - NSResponder* r = [self firstResponder]; - if ([r conformsToProtocol:@protocol(RenderWidgetHostViewMacBase)]) - return [r performKeyEquivalent:event]; - - if ([super performKeyEquivalent:event]) - return YES; - - return NO; -} - -@end // EventProcessingWindow diff --git a/atom/browser/ui/message_box_gtk.cc b/atom/browser/ui/message_box_gtk.cc index 41682190e60e..de8d994e5bca 100644 --- a/atom/browser/ui/message_box_gtk.cc +++ b/atom/browser/ui/message_box_gtk.cc @@ -92,7 +92,7 @@ class GtkMessageBox { } const char* TranslateToStock(int id, const std::string& text) { - std::string lower = base::StringToLowerASCII(text); + std::string lower = base::ToLowerASCII(text); if (lower == "cancel") return GTK_STOCK_CANCEL; else if (lower == "no") diff --git a/atom/browser/ui/message_box_win.cc b/atom/browser/ui/message_box_win.cc index 697a7ad410a2..656be9f10bb2 100644 --- a/atom/browser/ui/message_box_win.cc +++ b/atom/browser/ui/message_box_win.cc @@ -34,7 +34,7 @@ struct CommonButtonID { int id; }; CommonButtonID GetCommonID(const base::string16& button) { - base::string16 lower = base::StringToLowerASCII(button); + base::string16 lower = base::ToLowerASCII(button); if (lower == L"ok") return { TDCBF_OK_BUTTON, IDOK }; else if (lower == L"yes") diff --git a/atom/browser/ui/x/x_window_utils.cc b/atom/browser/ui/x/x_window_utils.cc index f5c3f54ec123..db83753bb376 100644 --- a/atom/browser/ui/x/x_window_utils.cc +++ b/atom/browser/ui/x/x_window_utils.cc @@ -42,7 +42,7 @@ void SetWindowType(::Window xwindow, const std::string& type) { XDisplay* xdisplay = gfx::GetXDisplay(); std::string type_prefix = "_NET_WM_WINDOW_TYPE_"; ::Atom window_type = XInternAtom( - xdisplay, (type_prefix + base::StringToUpperASCII(type)).c_str(), False); + xdisplay, (type_prefix + base::ToUpperASCII(type)).c_str(), False); XChangeProperty(xdisplay, xwindow, XInternAtom(xdisplay, "_NET_WM_WINDOW_TYPE", False), XA_ATOM, diff --git a/atom/browser/web_contents_preferences.cc b/atom/browser/web_contents_preferences.cc index 83145368c5fe..3d86df96dd76 100644 --- a/atom/browser/web_contents_preferences.cc +++ b/atom/browser/web_contents_preferences.cc @@ -36,8 +36,6 @@ FeaturePair kWebRuntimeFeatures[] = { switches::kExperimentalCanvasFeatures }, { options::kOverlayScrollbars, switches::kOverlayScrollbars }, - { options::kOverlayFullscreenVideo, - switches::kOverlayFullscreenVideo }, { options::kSharedWorker, switches::kSharedWorker }, { options::kPageVisibility, @@ -148,8 +146,6 @@ void WebContentsPreferences::OverrideWebkitPrefs( prefs->javascript_enabled = b; if (self->web_preferences_.GetBoolean("images", &b)) prefs->images_enabled = b; - if (self->web_preferences_.GetBoolean("java", &b)) - prefs->java_enabled = b; if (self->web_preferences_.GetBoolean("textAreasAreResizable", &b)) prefs->text_areas_are_resizable = b; if (self->web_preferences_.GetBoolean("webgl", &b)) diff --git a/atom/common/api/atom_api_native_image.cc b/atom/common/api/atom_api_native_image.cc index e0f0940a7420..a810069e71b9 100644 --- a/atom/common/api/atom_api_native_image.cc +++ b/atom/common/api/atom_api_native_image.cc @@ -63,7 +63,8 @@ float GetScaleFactorFromPath(const base::FilePath& path) { // We don't try to convert string to float here because it is very very // expensive. for (unsigned i = 0; i < arraysize(kScaleFactorPairs); ++i) { - if (base::EndsWith(filename, kScaleFactorPairs[i].name, true)) + if (base::EndsWith(filename, kScaleFactorPairs[i].name, + base::CompareCase::INSENSITIVE_ASCII)) return kScaleFactorPairs[i].scale; } diff --git a/atom/common/api/event_emitter_caller.cc b/atom/common/api/event_emitter_caller.cc index 94eb9ce9e79a..4b44553d3740 100644 --- a/atom/common/api/event_emitter_caller.cc +++ b/atom/common/api/event_emitter_caller.cc @@ -19,7 +19,7 @@ v8::Local CallEmitWithArgs(v8::Isolate* isolate, // Perform microtask checkpoint after running JavaScript. scoped_ptr script_scope( Locker::IsBrowserProcess() ? - nullptr : new blink::WebScopedRunV8Script(isolate)); + nullptr : new blink::WebScopedRunV8Script); // Use node::MakeCallback to call the callback, and it will also run pending // tasks in Node.js. return node::MakeCallback( diff --git a/atom/common/crash_reporter/crash_reporter.cc b/atom/common/crash_reporter/crash_reporter.cc index b87ce54acd51..f4f0ff9b7b16 100644 --- a/atom/common/crash_reporter/crash_reporter.cc +++ b/atom/common/crash_reporter/crash_reporter.cc @@ -48,11 +48,11 @@ CrashReporter::GetUploadedReports(const std::string& path) { std::vector result; if (base::ReadFileToString(base::FilePath::FromUTF8Unsafe(path), &file_content)) { - std::vector reports; - base::SplitString(file_content, '\n', &reports); + std::vector reports = base::SplitString( + file_content, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); for (const std::string& report : reports) { - std::vector report_item; - base::SplitString(report, ',', &report_item); + std::vector report_item = base::SplitString( + report, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); int report_time = 0; if (report_item.size() >= 2 && base::StringToInt(report_item[0], &report_time)) { diff --git a/atom/common/crash_reporter/crash_reporter_linux.cc b/atom/common/crash_reporter/crash_reporter_linux.cc index 8a5608dad0cb..6fe69f486956 100644 --- a/atom/common/crash_reporter/crash_reporter_linux.cc +++ b/atom/common/crash_reporter/crash_reporter_linux.cc @@ -130,7 +130,7 @@ bool CrashReporterLinux::CrashDone(const MinidumpDescriptor& minidump, // static CrashReporterLinux* CrashReporterLinux::GetInstance() { - return Singleton::get(); + return base::Singleton::get(); } // static diff --git a/atom/common/crash_reporter/crash_reporter_linux.h b/atom/common/crash_reporter/crash_reporter_linux.h index 2f7d639e9075..165c288ab2b1 100644 --- a/atom/common/crash_reporter/crash_reporter_linux.h +++ b/atom/common/crash_reporter/crash_reporter_linux.h @@ -12,7 +12,9 @@ #include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" +namespace base { template struct DefaultSingletonTraits; +} namespace google_breakpad { class ExceptionHandler; @@ -34,7 +36,7 @@ class CrashReporterLinux : public CrashReporter { void SetUploadParameters() override; private: - friend struct DefaultSingletonTraits; + friend struct base::DefaultSingletonTraits; CrashReporterLinux(); virtual ~CrashReporterLinux(); diff --git a/atom/common/crash_reporter/crash_reporter_mac.h b/atom/common/crash_reporter/crash_reporter_mac.h index cbdb3c65feb1..f03154359155 100644 --- a/atom/common/crash_reporter/crash_reporter_mac.h +++ b/atom/common/crash_reporter/crash_reporter_mac.h @@ -14,7 +14,9 @@ #include "base/strings/string_piece.h" #include "vendor/crashpad/client/simple_string_dictionary.h" +namespace base { template struct DefaultSingletonTraits; +} namespace crash_reporter { @@ -31,7 +33,7 @@ class CrashReporterMac : public CrashReporter { void SetUploadParameters() override; private: - friend struct DefaultSingletonTraits; + friend struct base::DefaultSingletonTraits; CrashReporterMac(); virtual ~CrashReporterMac(); diff --git a/atom/common/crash_reporter/crash_reporter_mac.mm b/atom/common/crash_reporter/crash_reporter_mac.mm index 00f37cc3febb..74ac70125b7d 100644 --- a/atom/common/crash_reporter/crash_reporter_mac.mm +++ b/atom/common/crash_reporter/crash_reporter_mac.mm @@ -126,7 +126,7 @@ CrashReporterMac::GetUploadedReports(const std::string& path) { // static CrashReporterMac* CrashReporterMac::GetInstance() { - return Singleton::get(); + return base::Singleton::get(); } // static diff --git a/atom/common/crash_reporter/crash_reporter_win.cc b/atom/common/crash_reporter/crash_reporter_win.cc index 240c229ca4b6..49a5ad8021ea 100644 --- a/atom/common/crash_reporter/crash_reporter_win.cc +++ b/atom/common/crash_reporter/crash_reporter_win.cc @@ -259,7 +259,7 @@ google_breakpad::CustomClientInfo* CrashReporterWin::GetCustomInfo( // static CrashReporterWin* CrashReporterWin::GetInstance() { - return Singleton::get(); + return base::Singleton::get(); } // static diff --git a/atom/common/crash_reporter/crash_reporter_win.h b/atom/common/crash_reporter/crash_reporter_win.h index 09c7ff4eaad6..181c9eabd23c 100644 --- a/atom/common/crash_reporter/crash_reporter_win.h +++ b/atom/common/crash_reporter/crash_reporter_win.h @@ -13,7 +13,9 @@ #include "base/memory/scoped_ptr.h" #include "vendor/breakpad/src/client/windows/handler/exception_handler.h" +namespace base { template struct DefaultSingletonTraits; +} namespace crash_reporter { @@ -33,7 +35,7 @@ class CrashReporterWin : public CrashReporter { int CrashForException(EXCEPTION_POINTERS* info); private: - friend struct DefaultSingletonTraits; + friend struct base::DefaultSingletonTraits; CrashReporterWin(); virtual ~CrashReporterWin(); diff --git a/atom/common/native_mate_converters/blink_converter.cc b/atom/common/native_mate_converters/blink_converter.cc index 2c871276ba26..d192018da012 100644 --- a/atom/common/native_mate_converters/blink_converter.cc +++ b/atom/common/native_mate_converters/blink_converter.cc @@ -45,7 +45,7 @@ template<> struct Converter { static bool FromV8(v8::Isolate* isolate, v8::Handle val, blink::WebInputEvent::Type* out) { - std::string type = base::StringToLowerASCII(V8ToString(val)); + std::string type = base::ToLowerASCII(V8ToString(val)); if (type == "mousedown") *out = blink::WebInputEvent::MouseDown; else if (type == "mouseup") @@ -82,7 +82,7 @@ template<> struct Converter { static bool FromV8(v8::Isolate* isolate, v8::Handle val, blink::WebMouseEvent::Button* out) { - std::string button = base::StringToLowerASCII(V8ToString(val)); + std::string button = base::ToLowerASCII(V8ToString(val)); if (button == "left") *out = blink::WebMouseEvent::Button::ButtonLeft; else if (button == "middle") @@ -97,7 +97,7 @@ template<> struct Converter { static bool FromV8(v8::Isolate* isolate, v8::Handle val, blink::WebInputEvent::Modifiers* out) { - std::string modifier = base::StringToLowerASCII(V8ToString(val)); + std::string modifier = base::ToLowerASCII(V8ToString(val)); if (modifier == "shift") *out = blink::WebInputEvent::ShiftKey; else if (modifier == "control" || modifier == "ctrl") @@ -166,7 +166,7 @@ bool Converter::FromV8( out->windowsKeyCode = atom::KeyboardCodeFromCharCode(code, &shifted); else if (dict.Get("keyCode", &identifier)) out->windowsKeyCode = atom::KeyboardCodeFromKeyIdentifier( - base::StringToLowerASCII(identifier)); + base::ToLowerASCII(identifier)); else return false; @@ -263,7 +263,7 @@ bool Converter::FromV8( std::string screen_position; if (dict.Get("screenPosition", &screen_position)) { - screen_position = base::StringToLowerASCII(screen_position); + screen_position = base::ToLowerASCII(screen_position); if (screen_position == "mobile") out->screenPosition = blink::WebDeviceEmulationParams::Mobile; else if (screen_position == "desktop") diff --git a/atom/common/native_mate_converters/callback.h b/atom/common/native_mate_converters/callback.h index 3cba2b32a820..6ef8e74c735a 100644 --- a/atom/common/native_mate_converters/callback.h +++ b/atom/common/native_mate_converters/callback.h @@ -51,7 +51,7 @@ struct V8FunctionInvoker(ArgTypes...)> { return v8::Null(isolate); scoped_ptr script_scope( Locker::IsBrowserProcess() ? - nullptr : new blink::WebScopedRunV8Script(isolate)); + nullptr : new blink::WebScopedRunV8Script); v8::Local holder = function.NewHandle(isolate); v8::Local context = holder->CreationContext(); v8::Context::Scope context_scope(context); @@ -72,7 +72,7 @@ struct V8FunctionInvoker { return; scoped_ptr script_scope( Locker::IsBrowserProcess() ? - nullptr : new blink::WebScopedRunV8Script(isolate)); + nullptr : new blink::WebScopedRunV8Script); v8::Local holder = function.NewHandle(isolate); v8::Local context = holder->CreationContext(); v8::Context::Scope context_scope(context); @@ -93,7 +93,7 @@ struct V8FunctionInvoker { return ret; scoped_ptr script_scope( Locker::IsBrowserProcess() ? - nullptr : new blink::WebScopedRunV8Script(isolate)); + nullptr : new blink::WebScopedRunV8Script); v8::Local holder = function.NewHandle(isolate); v8::Local context = holder->CreationContext(); v8::Context::Scope context_scope(context); diff --git a/atom/common/node_bindings.cc b/atom/common/node_bindings.cc index dbd0bd8d96ee..04a0c9139e28 100644 --- a/atom/common/node_bindings.cc +++ b/atom/common/node_bindings.cc @@ -227,7 +227,7 @@ void NodeBindings::UvRunOnce() { // Perform microtask checkpoint after running JavaScript. scoped_ptr script_scope( - is_browser_ ? nullptr : new blink::WebScopedRunV8Script(env->isolate())); + is_browser_ ? nullptr : new blink::WebScopedRunV8Script); // Deal with uv events. int r = uv_run(uv_loop_, UV_RUN_NOWAIT); diff --git a/atom/common/options_switches.cc b/atom/common/options_switches.cc index 1124cfba4bac..a0cb8384a340 100644 --- a/atom/common/options_switches.cc +++ b/atom/common/options_switches.cc @@ -95,7 +95,6 @@ const char kDirectWrite[] = "directWrite"; const char kExperimentalFeatures[] = "experimentalFeatures"; const char kExperimentalCanvasFeatures[] = "experimentalCanvasFeatures"; const char kOverlayScrollbars[] = "overlayScrollbars"; -const char kOverlayFullscreenVideo[] = "overlayFullscreenVideo"; const char kSharedWorker[] = "sharedWorker"; } // namespace options @@ -139,7 +138,6 @@ const char kGuestInstanceID[] = "guest-instance-id"; const char kExperimentalFeatures[] = "experimental-features"; const char kExperimentalCanvasFeatures[] = "experimental-canvas-features"; const char kOverlayScrollbars[] = "overlay-scrollbars"; -const char kOverlayFullscreenVideo[] = "overlay-fullscreen-video"; const char kSharedWorker[] = "shared-worker"; const char kPageVisibility[] = "page-visiblity"; diff --git a/atom/common/options_switches.h b/atom/common/options_switches.h index cd52c97597c9..6960db83bc10 100644 --- a/atom/common/options_switches.h +++ b/atom/common/options_switches.h @@ -50,7 +50,6 @@ extern const char kGuestInstanceID[]; extern const char kExperimentalFeatures[]; extern const char kExperimentalCanvasFeatures[]; extern const char kOverlayScrollbars[]; -extern const char kOverlayFullscreenVideo[]; extern const char kSharedWorker[]; extern const char kPageVisibility[]; @@ -79,7 +78,6 @@ extern const char kGuestInstanceID[]; extern const char kExperimentalFeatures[]; extern const char kExperimentalCanvasFeatures[]; extern const char kOverlayScrollbars[]; -extern const char kOverlayFullscreenVideo[]; extern const char kSharedWorker[]; extern const char kPageVisibility[]; diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc index 362b0b8026a7..7c04c04249a7 100644 --- a/atom/renderer/atom_renderer_client.cc +++ b/atom/renderer/atom_renderer_client.cc @@ -226,8 +226,6 @@ void AtomRendererClient::EnableWebRuntimeFeatures() { blink::WebRuntimeFeatures::enableExperimentalCanvasFeatures(true); if (IsSwitchEnabled(command_line, switches::kOverlayScrollbars)) blink::WebRuntimeFeatures::enableOverlayScrollbars(true); - if (IsSwitchEnabled(command_line, switches::kOverlayFullscreenVideo)) - blink::WebRuntimeFeatures::enableOverlayFullscreenVideo(true); if (IsSwitchEnabled(command_line, switches::kSharedWorker)) blink::WebRuntimeFeatures::enableSharedWorker(true); } diff --git a/chromium_src/chrome/browser/printing/print_view_manager_base.cc b/chromium_src/chrome/browser/printing/print_view_manager_base.cc index 35c62fbc5327..ede1d3b8ba8c 100644 --- a/chromium_src/chrome/browser/printing/print_view_manager_base.cc +++ b/chromium_src/chrome/browser/printing/print_view_manager_base.cc @@ -410,7 +410,7 @@ bool PrintViewManagerBase::RunInnerMessageLoop() { // be CPU bound, the page overly complex/large or the system just // memory-bound. static const int kPrinterSettingsTimeout = 60000; - base::OneShotTimer quit_timer; + base::OneShotTimer quit_timer; quit_timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(kPrinterSettingsTimeout), base::MessageLoop::current(), &base::MessageLoop::Quit); diff --git a/chromium_src/chrome/browser/process_singleton_posix.cc b/chromium_src/chrome/browser/process_singleton_posix.cc index b03ce431e47e..98fb948730e0 100644 --- a/chromium_src/chrome/browser/process_singleton_posix.cc +++ b/chromium_src/chrome/browser/process_singleton_posix.cc @@ -503,7 +503,7 @@ class ProcessSingleton::LinuxWatcher // reads. size_t bytes_read_; - base::OneShotTimer timer_; + base::OneShotTimer timer_; DISALLOW_COPY_AND_ASSIGN(SocketReader); }; diff --git a/chromium_src/chrome/browser/speech/tts_controller_impl.cc b/chromium_src/chrome/browser/speech/tts_controller_impl.cc index 6b66b6a61960..610ce1656759 100644 --- a/chromium_src/chrome/browser/speech/tts_controller_impl.cc +++ b/chromium_src/chrome/browser/speech/tts_controller_impl.cc @@ -111,7 +111,7 @@ TtsController* TtsController::GetInstance() { // static TtsControllerImpl* TtsControllerImpl::GetInstance() { - return Singleton::get(); + return base::Singleton::get(); } TtsControllerImpl::TtsControllerImpl() diff --git a/chromium_src/chrome/browser/speech/tts_controller_impl.h b/chromium_src/chrome/browser/speech/tts_controller_impl.h index 651f836cdf6c..6c8aa5747d20 100644 --- a/chromium_src/chrome/browser/speech/tts_controller_impl.h +++ b/chromium_src/chrome/browser/speech/tts_controller_impl.h @@ -77,7 +77,7 @@ class TtsControllerImpl : public TtsController { int GetMatchingVoice(const Utterance* utterance, std::vector& voices); - friend struct DefaultSingletonTraits; + friend struct base::DefaultSingletonTraits; // The current utterance being spoken. Utterance* current_utterance_; @@ -101,4 +101,4 @@ class TtsControllerImpl : public TtsController { DISALLOW_COPY_AND_ASSIGN(TtsControllerImpl); }; -#endif // CHROME_BROWSER_SPEECH_TTS_CONTROLLER_IMPL_H_ \ No newline at end of file +#endif // CHROME_BROWSER_SPEECH_TTS_CONTROLLER_IMPL_H_ diff --git a/chromium_src/chrome/browser/speech/tts_mac.mm b/chromium_src/chrome/browser/speech/tts_mac.mm index acfa5b58bf3b..aafbd4692515 100644 --- a/chromium_src/chrome/browser/speech/tts_mac.mm +++ b/chromium_src/chrome/browser/speech/tts_mac.mm @@ -91,7 +91,7 @@ class TtsPlatformImplMac : public TtsPlatformImpl { int last_char_index_; bool paused_; - friend struct DefaultSingletonTraits; + friend struct base::DefaultSingletonTraits; DISALLOW_COPY_AND_ASSIGN(TtsPlatformImplMac); }; @@ -291,7 +291,7 @@ TtsPlatformImplMac::~TtsPlatformImplMac() { // static TtsPlatformImplMac* TtsPlatformImplMac::GetInstance() { - return Singleton::get(); + return base::Singleton::get(); } @implementation ChromeTtsDelegate diff --git a/chromium_src/chrome/renderer/pepper/pepper_flash_renderer_host.cc b/chromium_src/chrome/renderer/pepper/pepper_flash_renderer_host.cc index fe5e28ebbeb8..66edd3f938ad 100644 --- a/chromium_src/chrome/renderer/pepper/pepper_flash_renderer_host.cc +++ b/chromium_src/chrome/renderer/pepper/pepper_flash_renderer_host.cc @@ -29,7 +29,6 @@ #include "third_party/skia/include/core/SkMatrix.h" #include "third_party/skia/include/core/SkPaint.h" #include "third_party/skia/include/core/SkPoint.h" -#include "third_party/skia/include/core/SkTemplates.h" #include "third_party/skia/include/core/SkTypeface.h" #include "ui/gfx/geometry/rect.h" #include "url/gurl.h" @@ -315,7 +314,7 @@ int32_t PepperFlashRendererHost::OnNavigate( bool rejected = false; while (header_iter.GetNext()) { std::string lower_case_header_name = - base::StringToLowerASCII(header_iter.name()); + base::ToLowerASCII(header_iter.name()); if (!IsSimpleHeader(lower_case_header_name, header_iter.values())) { rejected = true; diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper.cc b/chromium_src/chrome/renderer/printing/print_web_view_helper.cc index 20ac1fdc9b4f..3bfe719a0c92 100644 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper.cc +++ b/chromium_src/chrome/renderer/printing/print_web_view_helper.cc @@ -544,7 +544,6 @@ void PrepareFrameAndViewForPrint::CopySelection( // on the page). WebPreferences prefs = preferences; prefs.javascript_enabled = false; - prefs.java_enabled = false; blink::WebView* web_view = blink::WebView::create(this); owns_web_view_ = true; diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index a987e2924615..db02b6aa14b3 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -123,7 +123,6 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. * `allowRunningInsecureContent` Boolean - Allow a https page to run JavaScript, CSS or plugins from http URLs. Default is `false`. * `images` Boolean - Enables image support. Default is `true`. - * `java` Boolean - Enables Java support. Default is `false`. * `textAreasAreResizable` Boolean - Make TextArea elements resizable. Default is `true`. * `webgl` Boolean - Enables WebGL support. Default is `true`. @@ -135,8 +134,6 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. canvas features. Default is `false`. * `overlayScrollbars` Boolean - Enables overlay scrollbars. Default is `false`. - * `overlayFullscreenVideo` Boolean - Enables overlay fullscreen video. Default - is `false` * `sharedWorker` Boolean - Enables Shared Worker support. Default is `false`. * `directWrite` Boolean - Enables DirectWrite font rendering system on Windows. Default is `true`. diff --git a/filenames.gypi b/filenames.gypi index 151a69ff1c9e..5e44ad7d713c 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -200,8 +200,6 @@ 'atom/browser/ui/atom_menu_model.h', 'atom/browser/ui/cocoa/atom_menu_controller.h', 'atom/browser/ui/cocoa/atom_menu_controller.mm', - 'atom/browser/ui/cocoa/event_processing_window.h', - 'atom/browser/ui/cocoa/event_processing_window.mm', 'atom/browser/ui/file_dialog.h', 'atom/browser/ui/file_dialog_gtk.cc', 'atom/browser/ui/file_dialog_mac.mm', diff --git a/vendor/brightray b/vendor/brightray index 57842edb817c..fff0f0e2d398 160000 --- a/vendor/brightray +++ b/vendor/brightray @@ -1 +1 @@ -Subproject commit 57842edb817cc1ae38a02fd7f266dd6aa3afbb45 +Subproject commit fff0f0e2d39886a49fce4f78aa3b625b880b3607 From 95e7c796ec28e805a979004ba6912d1d87d8acab Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 7 Dec 2015 20:48:39 +0800 Subject: [PATCH 26/67] V8 now checks strictly when callin Neuter() --- script/lib/config.py | 2 +- vendor/node | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/script/lib/config.py b/script/lib/config.py index 4978302abb0f..159839c7f559 100644 --- a/script/lib/config.py +++ b/script/lib/config.py @@ -8,7 +8,7 @@ import sys BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \ 'http://gh-contractor-zcbenz.s3.amazonaws.com/libchromiumcontent' -LIBCHROMIUMCONTENT_COMMIT = 'd534691711ecdef1739878674a9ffd5f2d5ac4a2' +LIBCHROMIUMCONTENT_COMMIT = '451ea93cc3090f7000f8f0daa4cb84e90ad6c842' PLATFORM = { 'cygwin': 'win32', diff --git a/vendor/node b/vendor/node index 1445826ca73c..97d9298d8a43 160000 --- a/vendor/node +++ b/vendor/node @@ -1 +1 @@ -Subproject commit 1445826ca73cc79bc57d503dd11d4ffaf695625c +Subproject commit 97d9298d8a431f27e2aded918ae9f2a673c9cf6f From 647f151906dc46bc3be4b188294ccc389617b7e2 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 7 Dec 2015 21:25:19 +0800 Subject: [PATCH 27/67] Fix the failing sendSync --- atom/renderer/api/lib/remote.coffee | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/atom/renderer/api/lib/remote.coffee b/atom/renderer/api/lib/remote.coffee index 48cdd937fb07..357b88406930 100644 --- a/atom/renderer/api/lib/remote.coffee +++ b/atom/renderer/api/lib/remote.coffee @@ -119,7 +119,11 @@ metaToPlainObject = (meta) -> # Browser calls a callback in renderer. ipcRenderer.on 'ATOM_RENDERER_CALLBACK', (event, id, args) -> - callbacksRegistry.apply id, metaToValue(args) + # Delay the callback to next tick in case the browser is still in the middle + # of sending this message while the callback sends a sync message to browser, + # which can fail sometimes. + setImmediate -> + callbacksRegistry.apply id, metaToValue(args) # A callback in browser is released. ipcRenderer.on 'ATOM_RENDERER_RELEASE_CALLBACK', (event, id) -> From 27dd233820ccc7b8e1cd4a56982c9d31f3f4cd13 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 7 Dec 2015 21:28:58 +0800 Subject: [PATCH 28/67] spec: Make the "remote listeners" test more reliable --- spec/api-ipc-spec.coffee | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/spec/api-ipc-spec.coffee b/spec/api-ipc-spec.coffee index a8d2a65cdef7..1aa715c9f759 100644 --- a/spec/api-ipc-spec.coffee +++ b/spec/api-ipc-spec.coffee @@ -89,14 +89,14 @@ describe 'ipc module', -> w.loadURL 'file://' + path.join(fixtures, 'api', 'send-sync-message.html') describe 'remote listeners', -> - it 'can be added and removed correctly', -> - count = 0 - w = new BrowserWindow(show: false) - listener = () -> - count += 1 - w.removeListener 'blur', listener - w.on 'blur', listener - w.emit 'blur' - w.emit 'blur' - assert.equal count, 1 + w = null + afterEach -> w.destroy() + + it 'can be added and removed correctly', -> + w = new BrowserWindow(show: false) + listener = -> + w.on 'test', listener + assert.equal w.listenerCount('test'), 1 + w.removeListener 'test', listener + assert.equal w.listenerCount('test'), 0 From d0be6c74116e92b667213c1740ff57014aceee66 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 7 Dec 2015 22:44:35 +0800 Subject: [PATCH 29/67] Fix cppling warning --- atom/browser/atom_browser_context.cc | 3 ++- vendor/brightray | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/atom/browser/atom_browser_context.cc b/atom/browser/atom_browser_context.cc index b9589d569b68..ec123825822e 100644 --- a/atom/browser/atom_browser_context.cc +++ b/atom/browser/atom_browser_context.cc @@ -86,7 +86,8 @@ std::string AtomBrowserContext::GetUserAgent() { return content::BuildUserAgentFromProduct(user_agent); } -scoped_ptr AtomBrowserContext::CreateURLRequestJobFactory( +scoped_ptr +AtomBrowserContext::CreateURLRequestJobFactory( content::ProtocolHandlerMap* handlers, content::URLRequestInterceptorScopedVector* interceptors) { scoped_ptr job_factory(job_factory_); diff --git a/vendor/brightray b/vendor/brightray index fff0f0e2d398..878e63860b59 160000 --- a/vendor/brightray +++ b/vendor/brightray @@ -1 +1 @@ -Subproject commit fff0f0e2d39886a49fce4f78aa3b625b880b3607 +Subproject commit 878e63860b59d3443cd9f739d7533f2be1109773 From f1787877371200ea96d7507f6daca460fb53d934 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 7 Dec 2015 09:12:48 -0800 Subject: [PATCH 30/67] Add failing spec for Menu.buildFromTemplate --- spec/api-menu-spec.coffee | 7 ++++++- spec/static/main.js | 7 +++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/spec/api-menu-spec.coffee b/spec/api-menu-spec.coffee index f23face228a9..c619be7530fb 100644 --- a/spec/api-menu-spec.coffee +++ b/spec/api-menu-spec.coffee @@ -1,6 +1,6 @@ assert = require 'assert' -{remote} = require 'electron' +{remote, ipcRenderer} = require 'electron' {Menu, MenuItem} = remote.require 'electron' describe 'menu module', -> @@ -9,6 +9,11 @@ describe 'menu module', -> menu = Menu.buildFromTemplate [label: 'text', extra: 'field'] assert.equal menu.items[0].extra, 'field' + it 'does not modify the specified template', -> + template = [label: 'text', submenu: [label: 'sub']] + builtTemplate = ipcRenderer.sendSync('menu-build-from-template', template) + assert.deepStrictEqual builtTemplate, template + describe 'Menu.buildFromTemplate should reorder based on item position specifiers', -> it 'should position before existing item', -> menu = Menu.buildFromTemplate [ diff --git a/spec/static/main.js b/spec/static/main.js index be3690cd9e7d..8618237977dc 100644 --- a/spec/static/main.js +++ b/spec/static/main.js @@ -3,6 +3,7 @@ const app = electron.app; const ipcMain = electron.ipcMain; const dialog = electron.dialog; const BrowserWindow = electron.BrowserWindow; +const Menu = electron.Menu; const path = require('path'); @@ -100,4 +101,10 @@ app.on('ready', function() { }); event.returnValue = "done"; }); + + // Verify Menu.buildFromTemplate does not modify the specified template + ipcMain.on('menu-build-from-template', function(event, template) { + Menu.buildFromTemplate(template); + event.returnValue = template; + }) }); From 26ac86c95c781fffed4b2714818016de8f986daf Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 7 Dec 2015 09:28:48 -0800 Subject: [PATCH 31/67] Convert submenu when non-Menu is passed into MenuItem ctor --- atom/browser/api/lib/menu-item.coffee | 4 +++- atom/browser/api/lib/menu.coffee | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/atom/browser/api/lib/menu-item.coffee b/atom/browser/api/lib/menu-item.coffee index 57beb6ffdae3..737f9c000d2b 100644 --- a/atom/browser/api/lib/menu-item.coffee +++ b/atom/browser/api/lib/menu-item.coffee @@ -24,8 +24,10 @@ class MenuItem constructor: (options) -> {Menu} = require 'electron' - {click, @selector, @type, @role, @label, @sublabel, @accelerator, @icon, @enabled, @visible, @checked, @submenu} = options + {click, @selector, @type, @role, @label, @sublabel, @accelerator, @icon, @enabled, @visible, @checked} = options + if options.submenu? and options.submenu.constructor isnt Menu + @submenu = Menu.buildFromTemplate options.submenu @type = 'submenu' if not @type? and @submenu? throw new Error('Invalid submenu') if @type is 'submenu' and @submenu?.constructor isnt Menu diff --git a/atom/browser/api/lib/menu.coffee b/atom/browser/api/lib/menu.coffee index 26e2dc233506..eac6a607fda2 100644 --- a/atom/browser/api/lib/menu.coffee +++ b/atom/browser/api/lib/menu.coffee @@ -169,7 +169,6 @@ Menu.buildFromTemplate = (template) -> for item in positionedTemplate throw new TypeError('Invalid template for MenuItem') unless typeof item is 'object' - item.submenu = Menu.buildFromTemplate item.submenu if item.submenu? menuItem = new MenuItem(item) menuItem[key] = value for key, value of item when not menuItem[key]? menu.append menuItem From d5c740957f746b6db3376da705fc7607fbd10a92 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 7 Dec 2015 09:29:03 -0800 Subject: [PATCH 32/67] :art: --- atom/browser/api/lib/menu.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/browser/api/lib/menu.coffee b/atom/browser/api/lib/menu.coffee index eac6a607fda2..d81c345f43a0 100644 --- a/atom/browser/api/lib/menu.coffee +++ b/atom/browser/api/lib/menu.coffee @@ -170,7 +170,7 @@ Menu.buildFromTemplate = (template) -> throw new TypeError('Invalid template for MenuItem') unless typeof item is 'object' menuItem = new MenuItem(item) - menuItem[key] = value for key, value of item when not menuItem[key]? + menuItem[key] ?= value for key, value of item menu.append menuItem menu From a139a62ebf4c52ce3bc089bbd6014f693d4d11dc Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 7 Dec 2015 09:36:07 -0800 Subject: [PATCH 33/67] Mention conversion using Menu.buildFromTemplate --- docs/api/menu-item.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/api/menu-item.md b/docs/api/menu-item.md index 37079233fc0c..af945e8aca48 100644 --- a/docs/api/menu-item.md +++ b/docs/api/menu-item.md @@ -26,7 +26,9 @@ Create a new `MenuItem` with the following method: * `visible` Boolean * `checked` Boolean * `submenu` Menu - Should be specified for `submenu` type menu item, when - it's specified the `type: 'submenu'` can be omitted for the menu item + it's specified the `type: 'submenu'` can be omitted for the menu item. + If the value is not a `Menu` then it will be automatically converted to one + using `Menu.buildFromTemplate`. * `id` String - Unique within a single menu. If defined then it can be used as a reference to this item by the position attribute. * `position` String - This field allows fine-grained definition of the From e62092ebb26e487ee2ff62401db6e04e885180a1 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 7 Dec 2015 09:47:15 -0800 Subject: [PATCH 34/67] Move ipc handler to be near others --- spec/static/main.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spec/static/main.js b/spec/static/main.js index 8618237977dc..821c6ecc0c8c 100644 --- a/spec/static/main.js +++ b/spec/static/main.js @@ -43,6 +43,12 @@ ipcMain.on('echo', function(event, msg) { event.returnValue = msg; }); +// Verify Menu.buildFromTemplate does not modify the specified template +ipcMain.on('menu-build-from-template', function(event, template) { + Menu.buildFromTemplate(template); + event.returnValue = template; +}) + if (process.argv[2] == '--ci') { process.removeAllListeners('uncaughtException'); process.on('uncaughtException', function(error) { @@ -101,10 +107,4 @@ app.on('ready', function() { }); event.returnValue = "done"; }); - - // Verify Menu.buildFromTemplate does not modify the specified template - ipcMain.on('menu-build-from-template', function(event, template) { - Menu.buildFromTemplate(template); - event.returnValue = template; - }) }); From 3931ebb7ef4b38867440315b07b2796a05da411f Mon Sep 17 00:00:00 2001 From: Paul Betts Date: Mon, 7 Dec 2015 10:02:06 -0800 Subject: [PATCH 35/67] Fix up Windows build errors --- atom/browser/browser_win.cc | 2 +- atom/browser/ui/file_dialog_win.cc | 6 ++++-- atom/common/crash_reporter/crash_reporter_win.cc | 4 ++-- atom/common/crash_reporter/win/crash_service.cc | 5 ++--- atom/common/crash_reporter/win/crash_service_main.cc | 2 +- chromium_src/chrome/browser/speech/tts_win.cc | 8 ++++---- .../renderer/printing/print_web_view_helper_pdf_win.cc | 1 - .../net/test/embedded_test_server/stream_listen_socket.cc | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/atom/browser/browser_win.cc b/atom/browser/browser_win.cc index ce36d56b620c..fdf4bd8c3bbe 100644 --- a/atom/browser/browser_win.cc +++ b/atom/browser/browser_win.cc @@ -127,7 +127,7 @@ void Browser::SetUserTasks(const std::vector& tasks) { PCWSTR Browser::GetAppUserModelID() { if (app_user_model_id_.empty()) { - SetAppUserModelID(ReplaceStringPlaceholders( + SetAppUserModelID(base::ReplaceStringPlaceholders( kAppUserModelIDFormat, base::UTF8ToUTF16(GetName()), nullptr)); } diff --git a/atom/browser/ui/file_dialog_win.cc b/atom/browser/ui/file_dialog_win.cc index d218beaa27f1..f39094f9dfc5 100644 --- a/atom/browser/ui/file_dialog_win.cc +++ b/atom/browser/ui/file_dialog_win.cc @@ -51,7 +51,7 @@ void ConvertFilters(const Filters& filters, std::vector extensions(filter.second); for (size_t j = 0; j < extensions.size(); ++j) extensions[j].insert(0, "*."); - buffer->push_back(base::UTF8ToWide(JoinString(extensions, ";"))); + buffer->push_back(base::UTF8ToWide(base::JoinString(extensions, ";"))); spec.pszSpec = buffer->back().c_str(); filterspec->push_back(spec); @@ -273,7 +273,9 @@ bool ShowSaveDialog(atom::NativeWindow* parent_window, bool matched = false; for (size_t i = 0; i < filter.second.size(); ++i) { if (filter.second[i] == "*" || - base::EndsWith(file_name, filter.second[i], false)) { + base::EndsWith( + file_name, filter.second[i], + base::CompareCase::INSENSITIVE_ASCII)) { matched = true; break;; } diff --git a/atom/common/crash_reporter/crash_reporter_win.cc b/atom/common/crash_reporter/crash_reporter_win.cc index 49a5ad8021ea..939a02f090c5 100644 --- a/atom/common/crash_reporter/crash_reporter_win.cc +++ b/atom/common/crash_reporter/crash_reporter_win.cc @@ -153,9 +153,9 @@ void CrashReporterWin::InitBreakpad(const std::string& product_name, return; } - base::string16 pipe_name = ReplaceStringPlaceholders( + base::string16 pipe_name = base::ReplaceStringPlaceholders( kPipeNameFormat, base::UTF8ToUTF16(product_name), NULL); - base::string16 wait_name = ReplaceStringPlaceholders( + base::string16 wait_name = base::ReplaceStringPlaceholders( kWaitEventFormat, base::UTF8ToUTF16(product_name), NULL); // Wait until the crash service is started. diff --git a/atom/common/crash_reporter/win/crash_service.cc b/atom/common/crash_reporter/win/crash_service.cc index 9b6ba7e03a65..67e22381aef8 100644 --- a/atom/common/crash_reporter/win/crash_service.cc +++ b/atom/common/crash_reporter/win/crash_service.cc @@ -118,7 +118,7 @@ HWND g_top_window = NULL; bool CreateTopWindow(HINSTANCE instance, const base::string16& application_name, bool visible) { - base::string16 class_name = ReplaceStringPlaceholders( + base::string16 class_name = base::ReplaceStringPlaceholders( kClassNameFormat, application_name, NULL); WNDCLASSEXW wcx = {0}; @@ -309,7 +309,7 @@ bool CrashService::Initialize(const base::string16& application_name, // Create or open an event to signal the browser process that the crash // service is initialized. - base::string16 wait_name = ReplaceStringPlaceholders( + base::string16 wait_name = base::ReplaceStringPlaceholders( kWaitEventFormat, application_name, NULL); HANDLE wait_event = ::CreateEventW(NULL, TRUE, TRUE, wait_name.c_str()); ::SetEvent(wait_event); @@ -524,4 +524,3 @@ PSECURITY_DESCRIPTOR CrashService::GetSecurityDescriptorForLowIntegrity() { } } // namespace breakpad - diff --git a/atom/common/crash_reporter/win/crash_service_main.cc b/atom/common/crash_reporter/win/crash_service_main.cc index 7a5eeb10133a..56d46970b67f 100644 --- a/atom/common/crash_reporter/win/crash_service_main.cc +++ b/atom/common/crash_reporter/win/crash_service_main.cc @@ -68,7 +68,7 @@ int Main(const wchar_t* cmd) { VLOG(1) << "Session start. cmdline is [" << cmd << "]"; // Setting the crash reporter. - base::string16 pipe_name = ReplaceStringPlaceholders(kPipeNameFormat, + base::string16 pipe_name = base::ReplaceStringPlaceholders(kPipeNameFormat, application_name, NULL); cmd_line.AppendSwitch("no-window"); diff --git a/chromium_src/chrome/browser/speech/tts_win.cc b/chromium_src/chrome/browser/speech/tts_win.cc index c7b0a0ca724c..89a8f413e5dd 100644 --- a/chromium_src/chrome/browser/speech/tts_win.cc +++ b/chromium_src/chrome/browser/speech/tts_win.cc @@ -57,7 +57,7 @@ class TtsPlatformImplWin : public TtsPlatformImpl { int char_position_; bool paused_; - friend struct DefaultSingletonTraits; + friend struct base::DefaultSingletonTraits; DISALLOW_COPY_AND_ASSIGN(TtsPlatformImplWin); }; @@ -246,12 +246,12 @@ TtsPlatformImplWin::TtsPlatformImplWin() // static TtsPlatformImplWin* TtsPlatformImplWin::GetInstance() { - return Singleton >::get(); + return base::Singleton< TtsPlatformImplWin, + base::LeakySingletonTraits >::get(); } // static void TtsPlatformImplWin::SpeechEventCallback( WPARAM w_param, LPARAM l_param) { GetInstance()->OnSpeechEvent(); -} \ No newline at end of file +} diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc b/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc index dcd388fd1111..5b34ff309043 100644 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc +++ b/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc @@ -135,7 +135,6 @@ bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame, printed_page_params.page_size = page_size_in_dpi[i]; printed_page_params.content_area = content_area_in_dpi[i]; Send(new PrintHostMsg_DidPrintPage(routing_id(), printed_page_params)); - printed_page_params.metafile_data_handle = INVALID_HANDLE_VALUE; } return true; } diff --git a/chromium_src/net/test/embedded_test_server/stream_listen_socket.cc b/chromium_src/net/test/embedded_test_server/stream_listen_socket.cc index 1056983a8e2f..897b23bbd56e 100644 --- a/chromium_src/net/test/embedded_test_server/stream_listen_socket.cc +++ b/chromium_src/net/test/embedded_test_server/stream_listen_socket.cc @@ -228,7 +228,7 @@ void StreamListenSocket::CloseSocket() { void StreamListenSocket::WatchSocket(WaitState state) { #if defined(OS_WIN) WSAEventSelect(socket_, socket_event_, FD_ACCEPT | FD_CLOSE | FD_READ); - watcher_.StartWatching(socket_event_, this); + watcher_.StartWatchingOnce(socket_event_, this); #elif defined(OS_POSIX) // Implicitly calls StartWatchingFileDescriptor(). base::MessageLoopForIO::current()->WatchFileDescriptor( @@ -264,7 +264,7 @@ void StreamListenSocket::OnObjectSignaled(HANDLE object) { return; } // The object was reset by WSAEnumNetworkEvents. Watch for the next signal. - watcher_.StartWatching(object, this); + watcher_.StartWatchingOnce(object, this); if (ev.lNetworkEvents == 0) { // Occasionally the event is set even though there is no new data. From 83c69b56a4a72403c82620fe9e2d1552585dfa4c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 7 Dec 2015 11:10:57 -0800 Subject: [PATCH 36/67] Use ipc eval in spec --- spec/api-menu-spec.coffee | 9 ++++++--- spec/static/main.js | 7 ------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/spec/api-menu-spec.coffee b/spec/api-menu-spec.coffee index c619be7530fb..2f1f6465898f 100644 --- a/spec/api-menu-spec.coffee +++ b/spec/api-menu-spec.coffee @@ -10,9 +10,12 @@ describe 'menu module', -> assert.equal menu.items[0].extra, 'field' it 'does not modify the specified template', -> - template = [label: 'text', submenu: [label: 'sub']] - builtTemplate = ipcRenderer.sendSync('menu-build-from-template', template) - assert.deepStrictEqual builtTemplate, template + template = ipcRenderer.sendSync 'eval', """ + var template = [{label: 'text', submenu: [{label: 'sub'}]}]; + require('electron').Menu.buildFromTemplate(template); + template; + """ + assert.deepStrictEqual template, [label: 'text', submenu: [label: 'sub']] describe 'Menu.buildFromTemplate should reorder based on item position specifiers', -> it 'should position before existing item', -> diff --git a/spec/static/main.js b/spec/static/main.js index 821c6ecc0c8c..be3690cd9e7d 100644 --- a/spec/static/main.js +++ b/spec/static/main.js @@ -3,7 +3,6 @@ const app = electron.app; const ipcMain = electron.ipcMain; const dialog = electron.dialog; const BrowserWindow = electron.BrowserWindow; -const Menu = electron.Menu; const path = require('path'); @@ -43,12 +42,6 @@ ipcMain.on('echo', function(event, msg) { event.returnValue = msg; }); -// Verify Menu.buildFromTemplate does not modify the specified template -ipcMain.on('menu-build-from-template', function(event, template) { - Menu.buildFromTemplate(template); - event.returnValue = template; -}) - if (process.argv[2] == '--ci') { process.removeAllListeners('uncaughtException'); process.on('uncaughtException', function(error) { From 96ef09742c69a2a972981cb4b85cc9b54e8e2bac Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 7 Dec 2015 11:16:36 -0800 Subject: [PATCH 37/67] Directly assign submenu when constructor is Menu --- atom/browser/api/lib/menu-item.coffee | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/atom/browser/api/lib/menu-item.coffee b/atom/browser/api/lib/menu-item.coffee index 737f9c000d2b..86b5c190d69e 100644 --- a/atom/browser/api/lib/menu-item.coffee +++ b/atom/browser/api/lib/menu-item.coffee @@ -26,8 +26,11 @@ class MenuItem {click, @selector, @type, @role, @label, @sublabel, @accelerator, @icon, @enabled, @visible, @checked} = options - if options.submenu? and options.submenu.constructor isnt Menu - @submenu = Menu.buildFromTemplate options.submenu + if options.submenu? + if options.submenu.constructor is Menu + @submenu = options.submenu + else + @submenu = Menu.buildFromTemplate options.submenu @type = 'submenu' if not @type? and @submenu? throw new Error('Invalid submenu') if @type is 'submenu' and @submenu?.constructor isnt Menu From 68d937ed47b73cc9ea2217291e6d02fd0d5b66c7 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Mon, 7 Dec 2015 11:20:15 -0800 Subject: [PATCH 38/67] :art: --- atom/browser/api/lib/menu-item.coffee | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/atom/browser/api/lib/menu-item.coffee b/atom/browser/api/lib/menu-item.coffee index 86b5c190d69e..242a48f54d88 100644 --- a/atom/browser/api/lib/menu-item.coffee +++ b/atom/browser/api/lib/menu-item.coffee @@ -24,13 +24,10 @@ class MenuItem constructor: (options) -> {Menu} = require 'electron' - {click, @selector, @type, @role, @label, @sublabel, @accelerator, @icon, @enabled, @visible, @checked} = options + {click, @selector, @type, @role, @label, @sublabel, @accelerator, @icon, @enabled, @visible, @checked, @submenu} = options - if options.submenu? - if options.submenu.constructor is Menu - @submenu = options.submenu - else - @submenu = Menu.buildFromTemplate options.submenu + if @submenu? and @submenu.constructor isnt Menu + @submenu = Menu.buildFromTemplate @submenu @type = 'submenu' if not @type? and @submenu? throw new Error('Invalid submenu') if @type is 'submenu' and @submenu?.constructor isnt Menu From af289001898f80feddc5d8af62b6f3c0442dcaba Mon Sep 17 00:00:00 2001 From: Paul Betts Date: Mon, 7 Dec 2015 13:27:05 -0800 Subject: [PATCH 39/67] Fix up Chrome47 changes --- atom/browser/ui/file_dialog_gtk.cc | 4 +++- atom/browser/ui/views/menu_bar.cc | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/atom/browser/ui/file_dialog_gtk.cc b/atom/browser/ui/file_dialog_gtk.cc index 5885ffe3611c..ed79449655f0 100644 --- a/atom/browser/ui/file_dialog_gtk.cc +++ b/atom/browser/ui/file_dialog_gtk.cc @@ -22,7 +22,9 @@ gboolean FileFilterCaseInsensitive(const GtkFileFilterInfo* file_info, // Makes .* file extension matches all file types. if (*file_extension == ".*") return true; - return base::EndsWith(file_info->filename, *file_extension, false); + return base::EndsWith( + file_info->filename, + *file_extension, base::CompareCase::INSENSITIVE_ASCII); } // Deletes |data| when gtk_file_filter_add_custom() is done with it. diff --git a/atom/browser/ui/views/menu_bar.cc b/atom/browser/ui/views/menu_bar.cc index d3059a50a41b..b7712929d024 100644 --- a/atom/browser/ui/views/menu_bar.cc +++ b/atom/browser/ui/views/menu_bar.cc @@ -17,7 +17,6 @@ #if defined(OS_WIN) #include "ui/gfx/color_utils.h" #elif defined(USE_X11) -#include "chrome/browser/ui/libgtk2ui/owned_widget_gtk2.h" #include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h" #endif @@ -33,15 +32,16 @@ const SkColor kDefaultColor = SkColorSetARGB(255, 233, 233, 233); #if defined(USE_X11) void GetMenuBarColor(SkColor* enabled, SkColor* disabled, SkColor* highlight, SkColor* hover, SkColor* background) { - libgtk2ui::OwnedWidgetGtk fake_menu_bar; - fake_menu_bar.Own(gtk_menu_bar_new()); + GtkWidget* menu_bar = gtk_menu_bar_new(); - GtkStyle* style = gtk_rc_get_style(fake_menu_bar.get()); + GtkStyle* style = gtk_rc_get_style(menu_bar); *enabled = libgtk2ui::GdkColorToSkColor(style->fg[GTK_STATE_NORMAL]); *disabled = libgtk2ui::GdkColorToSkColor(style->fg[GTK_STATE_INSENSITIVE]); *highlight = libgtk2ui::GdkColorToSkColor(style->fg[GTK_STATE_SELECTED]); *hover = libgtk2ui::GdkColorToSkColor(style->fg[GTK_STATE_PRELIGHT]); *background = libgtk2ui::GdkColorToSkColor(style->bg[GTK_STATE_NORMAL]); + + gtk_widget_destroy(menu_bar); } #endif From 8d5c153e9bbd5e324f2cb14fc87158044890d5d6 Mon Sep 17 00:00:00 2001 From: Paul Betts Date: Mon, 7 Dec 2015 14:23:01 -0800 Subject: [PATCH 40/67] Update to Chrome 47 version of tts_win --- chromium_src/chrome/browser/speech/tts_win.cc | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/chromium_src/chrome/browser/speech/tts_win.cc b/chromium_src/chrome/browser/speech/tts_win.cc index 89a8f413e5dd..ac2582058894 100644 --- a/chromium_src/chrome/browser/speech/tts_win.cc +++ b/chromium_src/chrome/browser/speech/tts_win.cc @@ -15,26 +15,26 @@ class TtsPlatformImplWin : public TtsPlatformImpl { public: - virtual bool PlatformImplAvailable() { + bool PlatformImplAvailable() override { return true; } - virtual bool Speak( + bool Speak( int utterance_id, const std::string& utterance, const std::string& lang, const VoiceData& voice, - const UtteranceContinuousParameters& params); + const UtteranceContinuousParameters& params) override; - virtual bool StopSpeaking(); + bool StopSpeaking() override; - virtual void Pause(); + void Pause() override; - virtual void Resume(); + void Resume() override; - virtual bool IsSpeaking(); + bool IsSpeaking() override; - virtual void GetVoices(std::vector* out_voices) override; + void GetVoices(std::vector* out_voices) override; // Get the single instance of this class. static TtsPlatformImplWin* GetInstance(); @@ -43,7 +43,7 @@ class TtsPlatformImplWin : public TtsPlatformImpl { private: TtsPlatformImplWin(); - virtual ~TtsPlatformImplWin() {} + ~TtsPlatformImplWin() override {} void OnSpeechEvent(); @@ -220,6 +220,8 @@ void TtsPlatformImplWin::OnSpeechEvent() { utterance_id_, TTS_EVENT_SENTENCE, char_position_, std::string()); break; + default: + break; } } } @@ -246,8 +248,8 @@ TtsPlatformImplWin::TtsPlatformImplWin() // static TtsPlatformImplWin* TtsPlatformImplWin::GetInstance() { - return base::Singleton< TtsPlatformImplWin, - base::LeakySingletonTraits >::get(); + return base::Singleton>::get(); } // static From 4a8d58f9141610fa6986618f9d374f30bfc16d7b Mon Sep 17 00:00:00 2001 From: Paul Betts Date: Mon, 7 Dec 2015 14:25:52 -0800 Subject: [PATCH 41/67] Update to Chrome47 version of GlobalMenuBarRegistrarX11 --- .../frame/global_menu_bar_registrar_x11.cc | 28 +++++++++---------- .../frame/global_menu_bar_registrar_x11.h | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc b/chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc index 0d2a6dd73824..3913325f21ca 100644 --- a/chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc +++ b/chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc @@ -21,7 +21,7 @@ const char kAppMenuRegistrarPath[] = "/com/canonical/AppMenu/Registrar"; // static GlobalMenuBarRegistrarX11* GlobalMenuBarRegistrarX11::GetInstance() { - return Singleton::get(); + return base::Singleton::get(); } void GlobalMenuBarRegistrarX11::OnWindowMapped(unsigned long xid) { @@ -39,7 +39,7 @@ void GlobalMenuBarRegistrarX11::OnWindowUnmapped(unsigned long xid) { } GlobalMenuBarRegistrarX11::GlobalMenuBarRegistrarX11() - : registrar_proxy_(NULL) { + : registrar_proxy_(nullptr) { // libdbusmenu uses the gio version of dbus; I tried using the code in dbus/, // but it looks like that's isn't sharing the bus name with the gio version, // even when |connection_type| is set to SHARED. @@ -49,11 +49,11 @@ GlobalMenuBarRegistrarX11::GlobalMenuBarRegistrarX11() G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START), - NULL, + nullptr, kAppMenuRegistrarName, kAppMenuRegistrarPath, kAppMenuRegistrarName, - NULL, // TODO: Probalby want a real cancelable. + nullptr, // TODO: Probalby want a real cancelable. static_cast(OnProxyCreatedThunk), this); } @@ -70,7 +70,7 @@ GlobalMenuBarRegistrarX11::~GlobalMenuBarRegistrarX11() { void GlobalMenuBarRegistrarX11::RegisterXID(unsigned long xid) { DCHECK(registrar_proxy_); - std::string path = atom::GlobalMenuBarX11::GetPathForWindow(xid); + std::string path = GlobalMenuBarX11::GetPathForWindow(xid); ANNOTATE_SCOPED_MEMORY_LEAK; // http://crbug.com/314087 // TODO(erg): The mozilla implementation goes to a lot of callback trouble @@ -84,14 +84,14 @@ void GlobalMenuBarRegistrarX11::RegisterXID(unsigned long xid) { "RegisterWindow", g_variant_new("(uo)", xid, path.c_str()), G_DBUS_CALL_FLAGS_NONE, -1, - NULL, - NULL, - NULL); + nullptr, + nullptr, + nullptr); } void GlobalMenuBarRegistrarX11::UnregisterXID(unsigned long xid) { DCHECK(registrar_proxy_); - std::string path = atom::GlobalMenuBarX11::GetPathForWindow(xid); + std::string path = GlobalMenuBarX11::GetPathForWindow(xid); ANNOTATE_SCOPED_MEMORY_LEAK; // http://crbug.com/314087 // TODO(erg): The mozilla implementation goes to a lot of callback trouble @@ -105,14 +105,14 @@ void GlobalMenuBarRegistrarX11::UnregisterXID(unsigned long xid) { "UnregisterWindow", g_variant_new("(u)", xid), G_DBUS_CALL_FLAGS_NONE, -1, - NULL, - NULL, - NULL); + nullptr, + nullptr, + nullptr); } void GlobalMenuBarRegistrarX11::OnProxyCreated(GObject* source, GAsyncResult* result) { - GError* error = NULL; + GError* error = nullptr; GDBusProxy* proxy = g_dbus_proxy_new_for_bus_finish(result, &error); if (error) { g_error_free(error); @@ -128,7 +128,7 @@ void GlobalMenuBarRegistrarX11::OnProxyCreated(GObject* source, g_signal_connect(registrar_proxy_, "notify::g-name-owner", G_CALLBACK(OnNameOwnerChangedThunk), this); - OnNameOwnerChanged(NULL, NULL); + OnNameOwnerChanged(nullptr, nullptr); } void GlobalMenuBarRegistrarX11::OnNameOwnerChanged(GObject* /* ignored */, diff --git a/chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h b/chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h index e35e87c0d20c..694f776b24ef 100644 --- a/chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h +++ b/chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h @@ -28,7 +28,7 @@ class GlobalMenuBarRegistrarX11 { void OnWindowUnmapped(unsigned long xid); private: - friend struct DefaultSingletonTraits; + friend struct base::DefaultSingletonTraits; GlobalMenuBarRegistrarX11(); ~GlobalMenuBarRegistrarX11(); From fe86239a9c2f120a9ef1eafee89890b6a98d0d80 Mon Sep 17 00:00:00 2001 From: Paul Betts Date: Mon, 7 Dec 2015 14:28:42 -0800 Subject: [PATCH 42/67] Update to Chrome47 version of tts_linux --- .../chrome/browser/speech/tts_linux.cc | 46 +++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/chromium_src/chrome/browser/speech/tts_linux.cc b/chromium_src/chrome/browser/speech/tts_linux.cc index 43b28a5eade7..ba15516ce036 100644 --- a/chromium_src/chrome/browser/speech/tts_linux.cc +++ b/chromium_src/chrome/browser/speech/tts_linux.cc @@ -13,6 +13,7 @@ #include "base/synchronization/lock.h" #include "chrome/browser/speech/tts_platform.h" #include "content/public/browser/browser_thread.h" +#include "content/public/common/content_switches.h" #include "library_loaders/libspeechd.h" @@ -32,18 +33,17 @@ struct SPDChromeVoice { class TtsPlatformImplLinux : public TtsPlatformImpl { public: - virtual bool PlatformImplAvailable() override; - virtual bool Speak( - int utterance_id, - const std::string& utterance, - const std::string& lang, - const VoiceData& voice, - const UtteranceContinuousParameters& params) override; - virtual bool StopSpeaking() override; - virtual void Pause() override; - virtual void Resume() override; - virtual bool IsSpeaking() override; - virtual void GetVoices(std::vector* out_voices) override; + bool PlatformImplAvailable() override; + bool Speak(int utterance_id, + const std::string& utterance, + const std::string& lang, + const VoiceData& voice, + const UtteranceContinuousParameters& params) override; + bool StopSpeaking() override; + void Pause() override; + void Resume() override; + bool IsSpeaking() override; + void GetVoices(std::vector* out_voices) override; void OnSpeechEvent(SPDNotificationType type); @@ -52,7 +52,7 @@ class TtsPlatformImplLinux : public TtsPlatformImpl { private: TtsPlatformImplLinux(); - virtual ~TtsPlatformImplLinux(); + ~TtsPlatformImplLinux() override; // Initiate the connection with the speech dispatcher. void Initialize(); @@ -83,7 +83,7 @@ class TtsPlatformImplLinux : public TtsPlatformImpl { // uniquely identify a voice across all available modules. scoped_ptr > all_native_voices_; - friend struct DefaultSingletonTraits; + friend struct base::DefaultSingletonTraits; DISALLOW_COPY_AND_ASSIGN(TtsPlatformImplLinux); }; @@ -94,6 +94,11 @@ SPDNotificationType TtsPlatformImplLinux::current_notification_ = TtsPlatformImplLinux::TtsPlatformImplLinux() : utterance_id_(0) { + const base::CommandLine& command_line = + *base::CommandLine::ForCurrentProcess(); + if (!command_line.HasSwitch(switches::kEnableSpeechDispatcher)) + return; + BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(&TtsPlatformImplLinux::Initialize, @@ -111,7 +116,7 @@ void TtsPlatformImplLinux::Initialize() { // http://crbug.com/317360 ANNOTATE_SCOPED_MEMORY_LEAK; conn_ = libspeechd_loader_.spd_open( - "chrome", "extension_api", NULL, SPD_MODE_SINGLE); + "chrome", "extension_api", NULL, SPD_MODE_THREADED); } if (!conn_) return; @@ -146,7 +151,7 @@ void TtsPlatformImplLinux::Reset() { if (conn_) libspeechd_loader_.spd_close(conn_); conn_ = libspeechd_loader_.spd_open( - "chrome", "extension_api", NULL, SPD_MODE_SINGLE); + "chrome", "extension_api", NULL, SPD_MODE_THREADED); } bool TtsPlatformImplLinux::PlatformImplAvailable() { @@ -187,6 +192,10 @@ bool TtsPlatformImplLinux::Speak( libspeechd_loader_.spd_set_voice_rate(conn_, 100 * log10(rate) / log10(3)); libspeechd_loader_.spd_set_voice_pitch(conn_, 100 * log10(pitch) / log10(3)); + // Support languages other than the default + if (!lang.empty()) + libspeechd_loader_.spd_set_language(conn_, lang.c_str()); + utterance_ = utterance; utterance_id_ = utterance_id; @@ -337,8 +346,9 @@ void TtsPlatformImplLinux::IndexMarkCallback(size_t msg_id, // static TtsPlatformImplLinux* TtsPlatformImplLinux::GetInstance() { - return Singleton >::get(); + return base::Singleton< + TtsPlatformImplLinux, + base::LeakySingletonTraits>::get(); } // static From 9a0cecf943a0b2985ea6508539245eb911f0f1ab Mon Sep 17 00:00:00 2001 From: Paul Betts Date: Mon, 7 Dec 2015 14:29:11 -0800 Subject: [PATCH 43/67] Rig GlobalMenuBarRegistrarX11 for Atom --- .../browser/ui/views/frame/global_menu_bar_registrar_x11.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc b/chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc index 3913325f21ca..cead675a74d3 100644 --- a/chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc +++ b/chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc @@ -70,7 +70,7 @@ GlobalMenuBarRegistrarX11::~GlobalMenuBarRegistrarX11() { void GlobalMenuBarRegistrarX11::RegisterXID(unsigned long xid) { DCHECK(registrar_proxy_); - std::string path = GlobalMenuBarX11::GetPathForWindow(xid); + std::string path = atom::GlobalMenuBarX11::GetPathForWindow(xid); ANNOTATE_SCOPED_MEMORY_LEAK; // http://crbug.com/314087 // TODO(erg): The mozilla implementation goes to a lot of callback trouble @@ -91,7 +91,7 @@ void GlobalMenuBarRegistrarX11::RegisterXID(unsigned long xid) { void GlobalMenuBarRegistrarX11::UnregisterXID(unsigned long xid) { DCHECK(registrar_proxy_); - std::string path = GlobalMenuBarX11::GetPathForWindow(xid); + std::string path = atom::GlobalMenuBarX11::GetPathForWindow(xid); ANNOTATE_SCOPED_MEMORY_LEAK; // http://crbug.com/314087 // TODO(erg): The mozilla implementation goes to a lot of callback trouble From e78a02806e2a591c48e7f4ffaf678190a249012f Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 8 Dec 2015 10:07:47 +0800 Subject: [PATCH 44/67] Make it safe to use sendSync --- atom/renderer/api/lib/ipc-renderer.coffee | 8 ++++++++ atom/renderer/api/lib/remote.coffee | 6 +----- .../renderer/printing/print_web_view_helper_pdf_win.cc | 2 ++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/atom/renderer/api/lib/ipc-renderer.coffee b/atom/renderer/api/lib/ipc-renderer.coffee index 29004d212b56..92be75aa20ba 100644 --- a/atom/renderer/api/lib/ipc-renderer.coffee +++ b/atom/renderer/api/lib/ipc-renderer.coffee @@ -1,9 +1,17 @@ +{EventEmitter} = require 'events' + binding = process.atomBinding 'ipc' v8Util = process.atomBinding 'v8_util' # Created by init.coffee. ipcRenderer = v8Util.getHiddenValue global, 'ipc' +# Delay the callback to next tick in case the browser is still in the middle +# of sending a message while the callback sends a sync message to browser, +# which can fail sometimes. +ipcRenderer.emit = (args...) -> + setTimeout (-> EventEmitter::emit.call ipcRenderer, args...), 0 + ipcRenderer.send = (args...) -> binding.send 'ipc-message', [args...] diff --git a/atom/renderer/api/lib/remote.coffee b/atom/renderer/api/lib/remote.coffee index 357b88406930..48cdd937fb07 100644 --- a/atom/renderer/api/lib/remote.coffee +++ b/atom/renderer/api/lib/remote.coffee @@ -119,11 +119,7 @@ metaToPlainObject = (meta) -> # Browser calls a callback in renderer. ipcRenderer.on 'ATOM_RENDERER_CALLBACK', (event, id, args) -> - # Delay the callback to next tick in case the browser is still in the middle - # of sending this message while the callback sends a sync message to browser, - # which can fail sometimes. - setImmediate -> - callbacksRegistry.apply id, metaToValue(args) + callbacksRegistry.apply id, metaToValue(args) # A callback in browser is released. ipcRenderer.on 'ATOM_RENDERER_RELEASE_CALLBACK', (event, id) -> diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc b/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc index 5b34ff309043..0b21de46995b 100644 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc +++ b/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc @@ -135,6 +135,8 @@ bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame, printed_page_params.page_size = page_size_in_dpi[i]; printed_page_params.content_area = content_area_in_dpi[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 = base::SharedMemoryHandle(); } return true; } From c3f7f2447cbaaf60290ed21cb37c2a39dbf4618c Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 8 Dec 2015 10:26:32 +0800 Subject: [PATCH 45/67] Update the libspeechd_loader --- chromium_src/library_loaders/libspeechd.h | 1 + chromium_src/library_loaders/libspeechd_loader.cc | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/chromium_src/library_loaders/libspeechd.h b/chromium_src/library_loaders/libspeechd.h index 0d62f2c5da6e..f7b276287a41 100644 --- a/chromium_src/library_loaders/libspeechd.h +++ b/chromium_src/library_loaders/libspeechd.h @@ -33,6 +33,7 @@ class LibSpeechdLoader { decltype(&::spd_set_synthesis_voice) spd_set_synthesis_voice; decltype(&::spd_list_modules) spd_list_modules; decltype(&::spd_set_output_module) spd_set_output_module; + decltype(&::spd_set_language) spd_set_language; private: diff --git a/chromium_src/library_loaders/libspeechd_loader.cc b/chromium_src/library_loaders/libspeechd_loader.cc index 606661000528..f09ea3ae861b 100644 --- a/chromium_src/library_loaders/libspeechd_loader.cc +++ b/chromium_src/library_loaders/libspeechd_loader.cc @@ -201,6 +201,19 @@ bool LibSpeechdLoader::Load(const std::string& library_name) { return false; } +#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DLOPEN) + spd_set_language = + reinterpret_castspd_set_language)>( + dlsym(library_, "spd_set_language")); +#endif +#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DT_NEEDED) + spd_set_language = &::spd_set_language; +#endif + if (!spd_set_language) { + CleanUp(true); + return false; + } + loaded_ = true; return true; @@ -227,5 +240,6 @@ void LibSpeechdLoader::CleanUp(bool unload) { spd_set_synthesis_voice = NULL; spd_list_modules = NULL; spd_set_output_module = NULL; + spd_set_language = NULL; } From c63a8c944bef19a67a153b80ce98356645921f5f Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 8 Dec 2015 10:42:51 +0800 Subject: [PATCH 46/67] Fix release title --- script/upload.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/script/upload.py b/script/upload.py index c021d743a82e..3245d9caaa76 100755 --- a/script/upload.py +++ b/script/upload.py @@ -174,11 +174,10 @@ def create_or_get_release_draft(github, releases, tag, tag_exists): def create_release_draft(github, tag): + name = '{0} {1}'.format(PROJECT_NAME, tag) if os.environ.has_key('CI'): - name = '{0} pending draft'.format(PROJECT_NAME) body = '(placeholder)' else: - name = '{0} {1}'.format(PROJECT_NAME, tag) body = get_text_with_editor(name) if body == '': sys.stderr.write('Quit due to empty release note.\n') From 4af219089066ca515a18aedfb5603bf9248e73cd Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 8 Dec 2015 11:14:30 +0800 Subject: [PATCH 47/67] Upgrade to Node v5.1.1 --- script/bootstrap.py | 2 +- vendor/node | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/script/bootstrap.py b/script/bootstrap.py index ef48c1f8023f..6eaf635bfd86 100755 --- a/script/bootstrap.py +++ b/script/bootstrap.py @@ -196,7 +196,7 @@ def create_chrome_version_h(): def touch_config_gypi(): config_gypi = os.path.join(SOURCE_ROOT, 'vendor', 'node', 'config.gypi') with open(config_gypi, 'w+') as f: - content = '\n{}' + content = "\n{'variables':{}}" if f.read() != content: f.write(content) diff --git a/vendor/node b/vendor/node index 97d9298d8a43..38d791843463 160000 --- a/vendor/node +++ b/vendor/node @@ -1 +1 @@ -Subproject commit 97d9298d8a431f27e2aded918ae9f2a673c9cf6f +Subproject commit 38d791843463b19c623c97c1c550a4e3c5a406d4 From 0f2f9b55430675e7fb9ff9dd915554075b728515 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 8 Dec 2015 11:20:07 +0800 Subject: [PATCH 48/67] No need to use CommandDispatcher --- atom/browser/native_window_mac.mm | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index d7ed15cf0708..ef33a119e107 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -18,7 +18,6 @@ #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host_view.h" #include "native_mate/dictionary.h" -#import "ui/base/cocoa/command_dispatcher.h" #include "ui/gfx/skia_util.h" namespace { @@ -209,11 +208,10 @@ bool ScopedDisableResize::disable_resize_ = false; @end -@interface AtomNSWindow : NSWindow { +@interface AtomNSWindow : NSWindow { @private atom::NativeWindowMac* shell_; bool enable_larger_than_screen_; - base::scoped_nsobject commandDispatcher_; } @property BOOL acceptsFirstMouse; @property BOOL disableAutoHideCursor; @@ -227,7 +225,6 @@ bool ScopedDisableResize::disable_resize_ = false; - (void)setShell:(atom::NativeWindowMac*)shell { shell_ = shell; - commandDispatcher_.reset([[CommandDispatcher alloc] initWithOwner:self]); } - (void)setEnableLargerThanScreen:(bool)enable { @@ -276,25 +273,6 @@ bool ScopedDisableResize::disable_resize_ = false; return !self.disableKeyOrMainWindow; } -// CommandDispatchingWindow implementation. - -- (void)setCommandHandler:(id)commandHandler { -} - -- (BOOL)redispatchKeyEvent:(NSEvent*)event { - return [commandDispatcher_ redispatchKeyEvent:event]; -} - -- (BOOL)defaultPerformKeyEquivalent:(NSEvent*)event { - return [super performKeyEquivalent:event]; -} - -- (void)commandDispatch:(id)sender { -} - -- (void)commandDispatchUsingKeyModifiers:(id)sender { -} - @end @interface ControlRegionView : NSView From da208b5155037578a230affdb81733c72de845ae Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 8 Dec 2015 11:41:47 +0800 Subject: [PATCH 49/67] We are now on 0.36.0 --- atom.gyp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom.gyp b/atom.gyp index 9f1ffe582505..01a2c99e08d8 100644 --- a/atom.gyp +++ b/atom.gyp @@ -4,7 +4,7 @@ 'product_name%': 'Electron', 'company_name%': 'GitHub, Inc', 'company_abbr%': 'github', - 'version%': '0.35.4', + 'version%': '0.36.0', }, 'includes': [ 'filenames.gypi', From 407e88cbad1470ca312b7f7b992d3268e8eb7e41 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 8 Dec 2015 12:06:32 +0800 Subject: [PATCH 50/67] Update brightray --- atom/common/chrome_version.h | 2 +- vendor/brightray | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/atom/common/chrome_version.h b/atom/common/chrome_version.h index 250051683786..c92fee1649bd 100644 --- a/atom/common/chrome_version.h +++ b/atom/common/chrome_version.h @@ -8,7 +8,7 @@ #ifndef ATOM_COMMON_CHROME_VERSION_H_ #define ATOM_COMMON_CHROME_VERSION_H_ -#define CHROME_VERSION_STRING "45.0.2454.85" +#define CHROME_VERSION_STRING "47.0.2526.73" #define CHROME_VERSION "v" CHROME_VERSION_STRING #endif // ATOM_COMMON_CHROME_VERSION_H_ diff --git a/vendor/brightray b/vendor/brightray index 878e63860b59..9b4d052d2af7 160000 --- a/vendor/brightray +++ b/vendor/brightray @@ -1 +1 @@ -Subproject commit 878e63860b59d3443cd9f739d7533f2be1109773 +Subproject commit 9b4d052d2af716c340034ed7815d9d758cd7804d From d458b24945c4353c22543b92bdddd01bbc122f21 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 8 Dec 2015 12:44:55 +0800 Subject: [PATCH 51/67] Add desktopCapturer to electron --- atom/renderer/api/lib/exports/electron.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/atom/renderer/api/lib/exports/electron.coffee b/atom/renderer/api/lib/exports/electron.coffee index 5d7f2a57edd0..a224818e5ffa 100644 --- a/atom/renderer/api/lib/exports/electron.coffee +++ b/atom/renderer/api/lib/exports/electron.coffee @@ -3,6 +3,9 @@ module.exports = require '../../../../common/api/lib/exports/electron' Object.defineProperties module.exports, # Renderer side modules, please sort with alphabet order. + desktopCapturer: + enumerable: true + get: -> require '../desktop-capturer' ipcRenderer: enumerable: true get: -> require '../ipc-renderer' From 785bc2986b0752d40bd3b51108e6d1f1d0bc99ca Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 8 Dec 2015 12:47:07 +0800 Subject: [PATCH 52/67] Update brightray and libchromium for desktopCapturer --- script/lib/config.py | 2 +- vendor/brightray | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/script/lib/config.py b/script/lib/config.py index 159839c7f559..3e7f23536c9b 100644 --- a/script/lib/config.py +++ b/script/lib/config.py @@ -8,7 +8,7 @@ import sys BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \ 'http://gh-contractor-zcbenz.s3.amazonaws.com/libchromiumcontent' -LIBCHROMIUMCONTENT_COMMIT = '451ea93cc3090f7000f8f0daa4cb84e90ad6c842' +LIBCHROMIUMCONTENT_COMMIT = '080aeb05f3ef869acc4234dbcc8a815e73047e2b' PLATFORM = { 'cygwin': 'win32', diff --git a/vendor/brightray b/vendor/brightray index 9b4d052d2af7..8c8c3dbade86 160000 --- a/vendor/brightray +++ b/vendor/brightray @@ -1 +1 @@ -Subproject commit 9b4d052d2af716c340034ed7815d9d758cd7804d +Subproject commit 8c8c3dbade86d19de28bc750e7b3f79668a85613 From 51368952a201ab41863ec3ac1c77e63d1b518688 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 8 Dec 2015 12:58:39 +0800 Subject: [PATCH 53/67] Remove deprecated API usages --- atom/browser/lib/desktop-capturer.coffee | 12 +++++------- atom/renderer/api/lib/desktop-capturer.coffee | 12 ++++-------- .../chrome/browser/media/desktop_media_list.h | 1 + .../browser/media/native_desktop_media_list.cc | 1 + 4 files changed, 11 insertions(+), 15 deletions(-) diff --git a/atom/browser/lib/desktop-capturer.coffee b/atom/browser/lib/desktop-capturer.coffee index 29d952595cb0..8ef3389f5f1a 100644 --- a/atom/browser/lib/desktop-capturer.coffee +++ b/atom/browser/lib/desktop-capturer.coffee @@ -1,15 +1,13 @@ -ipc = require 'ipc' +{ipcMain} = require 'electron' +{desktopCapturer} = process.atomBinding 'desktop_capturer' -# The browser module manages all desktop-capturer moduels in renderer process. -desktopCapturer = process.atomBinding('desktop_capturer').desktopCapturer - -isOptionsEqual = (opt1, opt2) -> +deepEqual = (opt1, opt2) -> return JSON.stringify(opt1) is JSON.stringify(opt2) # A queue for holding all requests from renderer process. requestsQueue = [] -ipc.on 'ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', (event, options, id) -> +ipcMain.on 'ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', (event, options, id) -> request = { id: id, options: options, webContents: event.sender } requestsQueue.push request desktopCapturer.startHandling options if requestsQueue.length is 1 @@ -29,7 +27,7 @@ desktopCapturer.emit = (event_name, event, error_message, sources) -> # it for reducing redunplicated `desktopCaptuer.startHandling` calls. unhandledRequestsQueue = [] for request in requestsQueue - if isOptionsEqual handledRequest.options, request.options + if deepEqual handledRequest.options, request.options request.webContents?.send "ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_#{request.id}", error_message, result else unhandledRequestsQueue.push request diff --git a/atom/renderer/api/lib/desktop-capturer.coffee b/atom/renderer/api/lib/desktop-capturer.coffee index 95e67ff99927..fc4118f067b3 100644 --- a/atom/renderer/api/lib/desktop-capturer.coffee +++ b/atom/renderer/api/lib/desktop-capturer.coffee @@ -1,15 +1,11 @@ -ipc = require 'ipc' -NativeImage = require 'native-image' +{ipcRenderer, NativeImage} = require 'electron' nextId = 0 getNextId = -> ++nextId -getSources = (options, callback) -> +exports.getSources = (options, callback) -> id = getNextId() - ipc.send 'ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', options, id - ipc.once "ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_#{id}", (error_message, sources) -> + ipcRenderer.send 'ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', options, id + ipcRenderer.once "ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_#{id}", (error_message, sources) -> error = if error_message then Error error_message else null callback error, ({id: source.id, name: source.name, thumbnail: NativeImage.createFromDataUrl source.thumbnail} for source in sources) - -module.exports = - getSources: getSources diff --git a/chromium_src/chrome/browser/media/desktop_media_list.h b/chromium_src/chrome/browser/media/desktop_media_list.h index fa0dbd815749..44850bd69121 100644 --- a/chromium_src/chrome/browser/media/desktop_media_list.h +++ b/chromium_src/chrome/browser/media/desktop_media_list.h @@ -6,6 +6,7 @@ #define CHROME_BROWSER_MEDIA_DESKTOP_MEDIA_LIST_H_ #include "base/basictypes.h" +#include "base/strings/string16.h" #include "base/time/time.h" #include "content/public/browser/desktop_media_id.h" #include "ui/gfx/image/image_skia.h" diff --git a/chromium_src/chrome/browser/media/native_desktop_media_list.cc b/chromium_src/chrome/browser/media/native_desktop_media_list.cc index 4d15b068b7c3..2464aeca4931 100644 --- a/chromium_src/chrome/browser/media/native_desktop_media_list.cc +++ b/chromium_src/chrome/browser/media/native_desktop_media_list.cc @@ -10,6 +10,7 @@ #include "base/hash.h" #include "base/logging.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/threading/sequenced_worker_pool.h" #include "chrome/browser/media/desktop_media_list_observer.h" From b517b0c59843d6ab1c66789dcc17f01b7c6673cc Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 8 Dec 2015 13:09:36 +0800 Subject: [PATCH 54/67] docs: Improve docs of desktopCapturer --- docs/api/desktop-capturer.md | 53 +++++++++++++++--------------------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/docs/api/desktop-capturer.md b/docs/api/desktop-capturer.md index 2d805771cef0..e0ec75842841 100644 --- a/docs/api/desktop-capturer.md +++ b/docs/api/desktop-capturer.md @@ -1,11 +1,11 @@ -# desktop-capturer +# desktopCapturer -The `desktop-capturer` is a renderer module used to capture the content of -screen and individual app windows. +The `desktopCapturer` module can be used to get available sources that can be +used to be captured with `getUserMedia`. ```javascript // In the renderer process. -var desktopCapturer = require('desktop-capturer'); +var desktopCapturer = require('electron').desktopCapturer; desktopCapturer.getSources({types: ['window', 'screen']}, function(error, sources) { if (error) throw error; @@ -44,35 +44,26 @@ The `desktopCapturer` module has the following methods: ### `desktopCapturer.getSources(options, callback)` -`options` Object, properties: -* `types` Array - An array of String that enums the types of desktop sources. - * `screen` String - Screen - * `window` String - Individual window -* `thumbnailSize` Object (optional) - The suggested size that thumbnail should - be scaled. - * `width` Integer - The width of thumbnail. By default, it is 150px. - * `height` Integer - The height of thumbnail. By default, it is 150px. +* `options` Object + * `types` Array - An array of String that lists the types of desktop sources + to be captured, available types are `screen` and `window`. + * `thumbnailSize` Object (optional) - The suggested size that thumbnail should + be scaled, it is `{width: 150, height: 150}` by default. +* `callback` Function -`callback` Function - `function(error, sources) {}` - -* `error` Error -* `sources` Array - An array of Source - -Gets all desktop sources. - -**Note:** There is no garuantee that the size of `source.thumbnail` is always -the same as the `thumnbailSize` in `options`. It also depends on the scale of -the screen or window. - -## Source - -`Source` is an object represents a captured screen or individual window. It has -following properties: +Starts a request to get all desktop sources, `callback` will be called with +`callback(error, sources)` when the request is completed. +The `sources` is an array of `Source` objects, each `Source` represents a +captured screen or individual window, and has following properties: * `id` String - The id of the captured window or screen used in - `navigator.webkitGetUserMedia`. The format looks like 'window:XX' or - 'screen:XX' where XX is a random generated number. -* `name` String - The descriped name of the capturing screen or window. If the - source is a screen, the name will be 'Entire Screen' or 'Screen '; if + `navigator.webkitGetUserMedia`. The format looks like `window:XX` or + `screen:XX` where `XX` is a random generated number. +* `name` String - The described name of the capturing screen or window. If the + source is a screen, the name will be `Entire Screen` or `Screen `; if it is a window, the name will be the window's title. * `thumbnail` [NativeImage](NativeImage.md) - A thumbnail image. + +**Note:** There is no guarantee that the size of `source.thumbnail` is always +the same as the `thumnbailSize` in `options`. It also depends on the scale of +the screen or window. From 468dd9e7c8c309788c69908c1dddb0c08a3161a4 Mon Sep 17 00:00:00 2001 From: Austin Burdine Date: Mon, 7 Dec 2015 23:13:45 -0600 Subject: [PATCH 55/67] :memo: fix grammatical error in desktop notification docs [ci skip] --- docs/tutorial/desktop-environment-integration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial/desktop-environment-integration.md b/docs/tutorial/desktop-environment-integration.md index 6e570ee71f92..868dc449eeb4 100644 --- a/docs/tutorial/desktop-environment-integration.md +++ b/docs/tutorial/desktop-environment-integration.md @@ -25,7 +25,7 @@ myNotification.onclick = function () { } ``` -While code and user experience across operating systems are similar, but there +While code and user experience across operating systems are similar, there are fine differences. ### Windows From f6c9000f5f33601e333b1c0e73f136e3b3de571f Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 8 Dec 2015 13:49:11 +0800 Subject: [PATCH 56/67] spec: Add a simple test case for desktopCapturer --- spec/api-desktop-capturer.coffee | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 spec/api-desktop-capturer.coffee diff --git a/spec/api-desktop-capturer.coffee b/spec/api-desktop-capturer.coffee new file mode 100644 index 000000000000..6f1842dd145c --- /dev/null +++ b/spec/api-desktop-capturer.coffee @@ -0,0 +1,9 @@ +assert = require 'assert' +{desktopCapturer} = require 'electron' + +describe 'desktopCapturer', -> + it 'should returns something', (done) -> + desktopCapturer.getSources {types: ['window', 'screen']}, (error, sources) -> + assert.equal error, null + assert.notEqual sources.length, 0 + done() From 836a8b179460a934c5bbb75baa0ef66c83def001 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 8 Dec 2015 13:49:26 +0800 Subject: [PATCH 57/67] Simplify the desktopCapturer code --- atom/browser/api/atom_api_desktop_capturer.cc | 49 +++---------------- atom/browser/api/atom_api_desktop_capturer.h | 12 ++--- atom/browser/lib/desktop-capturer.coffee | 18 +++---- atom/renderer/api/lib/desktop-capturer.coffee | 19 +++++-- .../chrome/browser/media/desktop_media_list.h | 1 + .../media/native_desktop_media_list.cc | 4 ++ .../browser/media/native_desktop_media_list.h | 1 + 7 files changed, 38 insertions(+), 66 deletions(-) diff --git a/atom/browser/api/atom_api_desktop_capturer.cc b/atom/browser/api/atom_api_desktop_capturer.cc index 21e98fe47c21..ceb69deca452 100644 --- a/atom/browser/api/atom_api_desktop_capturer.cc +++ b/atom/browser/api/atom_api_desktop_capturer.cc @@ -10,7 +10,6 @@ #include "base/strings/utf_string_conversions.h" #include "chrome/browser/media/desktop_media_list.h" #include "native_mate/dictionary.h" -#include "native_mate/handle.h" #include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h" #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" #include "third_party/webrtc/modules/desktop_capture/window_capturer.h" @@ -38,45 +37,15 @@ namespace atom { namespace api { -namespace { -const int kThumbnailWidth = 150; -const int kThumbnailHeight = 150; - -bool GetCapturerTypes(const mate::Dictionary& args, - bool* show_windows, - bool* show_screens) { - *show_windows = false; - *show_screens = false; - std::vector sources; - if (!args.Get("types", &sources)) - return false; - for (const auto& source_type : sources) { - if (source_type == "screen") - *show_screens = true; - else if (source_type == "window") - *show_windows = true; - } - return !show_windows && !show_screens ? false : true; -} - -} // namespace - DesktopCapturer::DesktopCapturer() { } DesktopCapturer::~DesktopCapturer() { } -void DesktopCapturer::StartHandling(const mate::Dictionary& args) { - bool show_screens = false; - bool show_windows = false; - if (!GetCapturerTypes(args, &show_windows, &show_screens)) { - Emit("handling-finished", - "Invalid options.", - std::vector()); - return; - } - +void DesktopCapturer::StartHandling(bool capture_window, + bool capture_screen, + const gfx::Size& thumbnail_size) { webrtc::DesktopCaptureOptions options = webrtc::DesktopCaptureOptions::CreateDefault(); @@ -91,15 +60,12 @@ void DesktopCapturer::StartHandling(const mate::Dictionary& args) { #endif scoped_ptr screen_capturer( - show_screens ? webrtc::ScreenCapturer::Create(options) : nullptr); + capture_screen ? webrtc::ScreenCapturer::Create(options) : nullptr); scoped_ptr window_capturer( - show_windows ? webrtc::WindowCapturer::Create(options) : nullptr); + capture_window ? webrtc::WindowCapturer::Create(options) : nullptr); media_list_.reset(new NativeDesktopMediaList(screen_capturer.Pass(), window_capturer.Pass())); - gfx::Size thumbnail_size(kThumbnailWidth, kThumbnailHeight); - args.Get("thumbnailSize", &thumbnail_size); - media_list_->SetThumbnailSize(thumbnail_size); media_list_->StartUpdating(this); } @@ -120,11 +86,8 @@ void DesktopCapturer::OnSourceThumbnailChanged(int index) { } bool DesktopCapturer::OnRefreshFinished() { - std::vector sources; - for (int i = 0; i < media_list_->GetSourceCount(); ++i) - sources.push_back(media_list_->GetSource(i)); + Emit("finished", media_list_->GetSources()); media_list_.reset(); - Emit("handling-finished", "", sources); return false; } diff --git a/atom/browser/api/atom_api_desktop_capturer.h b/atom/browser/api/atom_api_desktop_capturer.h index 32687abf7367..c22c8a44835f 100644 --- a/atom/browser/api/atom_api_desktop_capturer.h +++ b/atom/browser/api/atom_api_desktop_capturer.h @@ -5,19 +5,11 @@ #ifndef ATOM_BROWSER_API_ATOM_API_DESKTOP_CAPTURER_H_ #define ATOM_BROWSER_API_ATOM_API_DESKTOP_CAPTURER_H_ -#include -#include - -#include "base/memory/scoped_ptr.h" #include "atom/browser/api/event_emitter.h" #include "chrome/browser/media/desktop_media_list_observer.h" #include "chrome/browser/media/native_desktop_media_list.h" #include "native_mate/handle.h" -namespace mate { -class Dictionary; -} - namespace atom { namespace api { @@ -27,7 +19,9 @@ class DesktopCapturer: public mate::EventEmitter, public: static mate::Handle Create(v8::Isolate* isolate); - void StartHandling(const mate::Dictionary& args); + void StartHandling(bool capture_window, + bool capture_screen, + const gfx::Size& thumbnail_size); protected: DesktopCapturer(); diff --git a/atom/browser/lib/desktop-capturer.coffee b/atom/browser/lib/desktop-capturer.coffee index 8ef3389f5f1a..a7fb29ff76ed 100644 --- a/atom/browser/lib/desktop-capturer.coffee +++ b/atom/browser/lib/desktop-capturer.coffee @@ -7,31 +7,31 @@ deepEqual = (opt1, opt2) -> # A queue for holding all requests from renderer process. requestsQueue = [] -ipcMain.on 'ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', (event, options, id) -> - request = { id: id, options: options, webContents: event.sender } +ipcMain.on 'ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', (event, captureWindow, captureScreen, thumbnailSize, id) -> + request = id: id, options: {captureWindow, captureScreen, thumbnailSize}, webContents: event.sender requestsQueue.push request - desktopCapturer.startHandling options if requestsQueue.length is 1 + desktopCapturer.startHandling captureWindow, captureScreen, thumbnailSize if requestsQueue.length is 1 # If the WebContents is destroyed before receiving result, just remove the # reference from requestsQueue to make the module not send the result to it. - event.sender.once 'destroyed', () -> + event.sender.once 'destroyed', -> request.webContents = null -desktopCapturer.emit = (event_name, event, error_message, sources) -> +desktopCapturer.emit = (event, name, sources) -> # Receiving sources result from main process, now send them back to renderer. handledRequest = requestsQueue.shift 0 - error = if error_message then Error error_message else null result = ({ id: source.id, name: source.name, thumbnail: source.thumbnail.toDataUrl() } for source in sources) - handledRequest.webContents?.send "ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_#{handledRequest.id}", error_message, result + handledRequest.webContents?.send "ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_#{handledRequest.id}", result # Check the queue to see whether there is other same request. If has, handle # it for reducing redunplicated `desktopCaptuer.startHandling` calls. unhandledRequestsQueue = [] for request in requestsQueue if deepEqual handledRequest.options, request.options - request.webContents?.send "ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_#{request.id}", error_message, result + request.webContents?.send "ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_#{request.id}", errorMessage, result else unhandledRequestsQueue.push request requestsQueue = unhandledRequestsQueue # If the requestsQueue is not empty, start a new request handling. if requestsQueue.length > 0 - desktopCapturer.startHandling requestsQueue[0].options + {captureWindow, captureScreen, thumbnailSize} = requestsQueue[0].options + desktopCapturer.startHandling captureWindow, captureScreen, thumbnailSize diff --git a/atom/renderer/api/lib/desktop-capturer.coffee b/atom/renderer/api/lib/desktop-capturer.coffee index fc4118f067b3..7c7c8982491f 100644 --- a/atom/renderer/api/lib/desktop-capturer.coffee +++ b/atom/renderer/api/lib/desktop-capturer.coffee @@ -1,11 +1,20 @@ -{ipcRenderer, NativeImage} = require 'electron' +{ipcRenderer, nativeImage} = require 'electron' nextId = 0 getNextId = -> ++nextId +# |options.type| can not be empty and has to include 'window' or 'screen'. +isValid = (options) -> + return options?.types? and Array.isArray options.types + exports.getSources = (options, callback) -> + return callback new Error('Invalid options') unless isValid options + + captureWindow = 'window' in options.types + captureScreen = 'screen' in options.types + options.thumbnailSize ?= width: 150, height: 150 + id = getNextId() - ipcRenderer.send 'ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', options, id - ipcRenderer.once "ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_#{id}", (error_message, sources) -> - error = if error_message then Error error_message else null - callback error, ({id: source.id, name: source.name, thumbnail: NativeImage.createFromDataUrl source.thumbnail} for source in sources) + ipcRenderer.send 'ATOM_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', captureWindow, captureScreen, options.thumbnailSize, id + ipcRenderer.once "ATOM_RENDERER_DESKTOP_CAPTURER_RESULT_#{id}", (event, sources) -> + callback null, ({id: source.id, name: source.name, thumbnail: nativeImage.createFromDataURL source.thumbnail} for source in sources) diff --git a/chromium_src/chrome/browser/media/desktop_media_list.h b/chromium_src/chrome/browser/media/desktop_media_list.h index 44850bd69121..7ef703e8b7b3 100644 --- a/chromium_src/chrome/browser/media/desktop_media_list.h +++ b/chromium_src/chrome/browser/media/desktop_media_list.h @@ -56,6 +56,7 @@ class DesktopMediaList { virtual int GetSourceCount() const = 0; virtual const Source& GetSource(int index) const = 0; + virtual std::vector GetSources() const = 0; }; #endif // CHROME_BROWSER_MEDIA_DESKTOP_MEDIA_LIST_H_ diff --git a/chromium_src/chrome/browser/media/native_desktop_media_list.cc b/chromium_src/chrome/browser/media/native_desktop_media_list.cc index 2464aeca4931..4a7fb58962c6 100644 --- a/chromium_src/chrome/browser/media/native_desktop_media_list.cc +++ b/chromium_src/chrome/browser/media/native_desktop_media_list.cc @@ -282,6 +282,10 @@ const DesktopMediaList::Source& NativeDesktopMediaList::GetSource( return sources_[index]; } +std::vector NativeDesktopMediaList::GetSources() const { + return sources_; +} + void NativeDesktopMediaList::Refresh() { capture_task_runner_->PostTask( FROM_HERE, base::Bind(&Worker::Refresh, base::Unretained(worker_.get()), diff --git a/chromium_src/chrome/browser/media/native_desktop_media_list.h b/chromium_src/chrome/browser/media/native_desktop_media_list.h index 81bd32152813..943d3dd32565 100644 --- a/chromium_src/chrome/browser/media/native_desktop_media_list.h +++ b/chromium_src/chrome/browser/media/native_desktop_media_list.h @@ -36,6 +36,7 @@ class NativeDesktopMediaList : public DesktopMediaList { void StartUpdating(DesktopMediaListObserver* observer) override; int GetSourceCount() const override; const Source& GetSource(int index) const override; + std::vector GetSources() const override; void SetViewDialogWindowId(content::DesktopMediaID::Id dialog_id) override; private: From 9eb56272257d63b0934e0dbf8e1d3fa4c5ed5b33 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 8 Dec 2015 14:21:23 +0800 Subject: [PATCH 58/67] Update clang to the same version with Chrome 47 --- script/update-clang.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/update-clang.sh b/script/update-clang.sh index 5f9b00da7d9a..801d60397145 100755 --- a/script/update-clang.sh +++ b/script/update-clang.sh @@ -8,7 +8,7 @@ # Do NOT CHANGE this if you don't know what you're doing -- see # https://code.google.com/p/chromium/wiki/UpdatingClang # Reverting problematic clang rolls is safe, though. -CLANG_REVISION=245965 +CLANG_REVISION=247874 # This is incremented when pushing a new build of Clang at the same revision. CLANG_SUB_REVISION=1 From 98169032fd2ed336fdd9f685fe751eff38ad3b51 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 8 Dec 2015 14:49:13 +0800 Subject: [PATCH 59/67] Update libchromiumcontent and brightray --- script/lib/config.py | 4 ++-- vendor/brightray | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/script/lib/config.py b/script/lib/config.py index 3e7f23536c9b..acb4c2e970ff 100644 --- a/script/lib/config.py +++ b/script/lib/config.py @@ -7,8 +7,8 @@ import sys BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \ - 'http://gh-contractor-zcbenz.s3.amazonaws.com/libchromiumcontent' -LIBCHROMIUMCONTENT_COMMIT = '080aeb05f3ef869acc4234dbcc8a815e73047e2b' + 'http://github-janky-artifacts.s3.amazonaws.com/libchromiumcontent' +LIBCHROMIUMCONTENT_COMMIT = 'd4b964338cb1cf81a59cd8aeec432f9e6fded802' PLATFORM = { 'cygwin': 'win32', diff --git a/vendor/brightray b/vendor/brightray index 8c8c3dbade86..476b9fc55058 160000 --- a/vendor/brightray +++ b/vendor/brightray @@ -1 +1 @@ -Subproject commit 8c8c3dbade86d19de28bc750e7b3f79668a85613 +Subproject commit 476b9fc55058a9528f6f016206f45564ee0113d9 From 640b4c3c666e27a866956ea09fd586a4343f2d6f Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 8 Dec 2015 16:56:20 +0800 Subject: [PATCH 60/67] Update brightray for various linking problems --- vendor/brightray | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/brightray b/vendor/brightray index 476b9fc55058..c5cac4882b3a 160000 --- a/vendor/brightray +++ b/vendor/brightray @@ -1 +1 @@ -Subproject commit 476b9fc55058a9528f6f016206f45564ee0113d9 +Subproject commit c5cac4882b3a5d991ad87fa410ccd754bafe5e53 From 9548a3801b0ebcda1fcee682261e571a60f7a1af Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 8 Dec 2015 17:03:10 +0800 Subject: [PATCH 61/67] Update brightray: Link a few more X libraries --- vendor/brightray | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/brightray b/vendor/brightray index c5cac4882b3a..a2a2f0b3c325 160000 --- a/vendor/brightray +++ b/vendor/brightray @@ -1 +1 @@ -Subproject commit c5cac4882b3a5d991ad87fa410ccd754bafe5e53 +Subproject commit a2a2f0b3c325c112bab86682d0e78d64d5988413 From 9daeafbace0acd7fbd02d5a9bb7feed4ffb33069 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 8 Dec 2015 17:32:42 +0800 Subject: [PATCH 62/67] Install libxtst-dev on travis ci --- script/cibuild | 1 + 1 file changed, 1 insertion(+) diff --git a/script/cibuild b/script/cibuild index 08d59385c9e0..c0798dc7e2c3 100755 --- a/script/cibuild +++ b/script/cibuild @@ -17,6 +17,7 @@ LINUX_DEPS = [ 'libgtk2.0-dev', 'libnotify-dev', 'libnss3-dev', + 'libxtst-dev', 'gcc-multilib', 'g++-multilib', ] From 505193e239428d9dc790dd0a0de9d4faccff0b6e Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 8 Dec 2015 18:15:01 +0800 Subject: [PATCH 63/67] Link with libyuv_neon.a on ARM --- script/lib/config.py | 2 +- vendor/brightray | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/script/lib/config.py b/script/lib/config.py index acb4c2e970ff..c1545e0d27d8 100644 --- a/script/lib/config.py +++ b/script/lib/config.py @@ -8,7 +8,7 @@ import sys BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \ 'http://github-janky-artifacts.s3.amazonaws.com/libchromiumcontent' -LIBCHROMIUMCONTENT_COMMIT = 'd4b964338cb1cf81a59cd8aeec432f9e6fded802' +LIBCHROMIUMCONTENT_COMMIT = 'cfbe8ec7e14af4cabd1474386f54e197db1f7ac1' PLATFORM = { 'cygwin': 'win32', diff --git a/vendor/brightray b/vendor/brightray index a2a2f0b3c325..814923b77d21 160000 --- a/vendor/brightray +++ b/vendor/brightray @@ -1 +1 @@ -Subproject commit a2a2f0b3c325c112bab86682d0e78d64d5988413 +Subproject commit 814923b77d21261a9d1780bff0bd1beb55203843 From f77bb449522da886d1cc4ca53887d82d94908b4c Mon Sep 17 00:00:00 2001 From: Robo Date: Tue, 8 Dec 2015 23:00:08 +0530 Subject: [PATCH 64/67] fix chrome app and user path conflicts --- chromium_src/chrome/common/chrome_paths.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chromium_src/chrome/common/chrome_paths.h b/chromium_src/chrome/common/chrome_paths.h index 581fdc06f7c1..3a76e3295f46 100644 --- a/chromium_src/chrome/common/chrome_paths.h +++ b/chromium_src/chrome/common/chrome_paths.h @@ -17,7 +17,7 @@ class FilePath; namespace chrome { enum { - PATH_START = 1000, + PATH_START = 2000, DIR_APP = PATH_START, // Directory where dlls and data reside. DIR_LOGS, // Directory where logs should be written. From 48d07423f9b657bdd7634e94d7d6217486d09370 Mon Sep 17 00:00:00 2001 From: Andriy Tsok Date: Wed, 2 Dec 2015 23:02:04 +0200 Subject: [PATCH 65/67] Ukrainian translation (uk-UA) --- README.md | 1 + docs-translations/uk-UA/README.md | 83 +++++++++++++++++++++++ docs-translations/uk-UA/styleguide.md | 97 +++++++++++++++++++++++++++ 3 files changed, 181 insertions(+) create mode 100644 docs-translations/uk-UA/README.md create mode 100644 docs-translations/uk-UA/styleguide.md diff --git a/README.md b/README.md index bb814b245139..edc8ebb6baaf 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ contains documents describing how to build and contribute to Electron. - [Spanish](https://github.com/atom/electron/tree/master/docs-translations/es) - [Simplified Chinese](https://github.com/atom/electron/tree/master/docs-translations/zh-CN) - [Traditional Chinese](https://github.com/atom/electron/tree/master/docs-translations/zh-TW) +- [Ukrainian](https://github.com/atom/electron/tree/master/docs-translations/uk-UA) - [Russian](https://github.com/atom/electron/tree/master/docs-translations/ru-RU) ## Quick Start diff --git a/docs-translations/uk-UA/README.md b/docs-translations/uk-UA/README.md new file mode 100644 index 000000000000..ef503a8844a3 --- /dev/null +++ b/docs-translations/uk-UA/README.md @@ -0,0 +1,83 @@ +Будь ласка, переконайтесь що ви використовуєте документацію, яка відповідає вашій версії Electron. +Номер версії повинен бути присутнім в URL адресі сторінки. Якщо це не так, Ви можливо, +використовуєте документацію із development гілки, +яка може містити зміни в API, які не сумісні з вашою версією Electron. +Якщо це так, тоді Ви можете переключитись на іншу версію документації +із списку [доступних версій](http://electron.atom.io/docs/) на atom.io, +або якщо ви використовуєте інтеррфейс GitHub, +тоді відкрийте список "Switch branches/tags" і виберіть потрібну вам +версію із списку тегів. + +## Довідник + +* [Підтримувані платформи](tutorial/supported-platforms.md) +* [Application Distribution](tutorial/application-distribution.md) +* [Mac App Store Submission Guide](tutorial/mac-app-store-submission-guide.md) +* [Упаковка додатку](tutorial/application-packaging.md) +* [Використання Native Node модулів](tutorial/using-native-node-modules.md) +* [Debugging Main Process](tutorial/debugging-main-process.md) +* [Використання Selenium and WebDriver](tutorial/using-selenium-and-webdriver.md) +* [DevTools Extension](tutorial/devtools-extension.md) +* [Використання Pepper Flash плагіну](tutorial/using-pepper-flash-plugin.md) + +## Підручники + +* [Швидкий старт](tutorial/quick-start.md) +* [Desktop Environment Integration](tutorial/desktop-environment-integration.md) +* [Online/Offline Event Detection](tutorial/online-offline-events.md) + +## API References + +* [Synopsis](api/synopsis.md) +* [Process Object](api/process.md) +* [Supported Chrome Command Line Switches](api/chrome-command-line-switches.md) +* [Environment Variables](api/environment-variables.md) + +### Користувальницькі елементи DOM + +* [`File` Object](api/file-object.md) +* [`` Tag](api/web-view-tag.md) +* [`window.open` Function](api/window-open.md) + +### Модулі для Main Process: + +* [app](api/app.md) +* [autoUpdater](api/auto-updater.md) +* [BrowserWindow](api/browser-window.md) +* [contentTracing](api/content-tracing.md) +* [dialog](api/dialog.md) +* [globalShortcut](api/global-shortcut.md) +* [ipcMain](api/ipc-main.md) +* [Menu](api/menu.md) +* [MenuItem](api/menu-item.md) +* [powerMonitor](api/power-monitor.md) +* [powerSaveBlocker](api/power-save-blocker.md) +* [protocol](api/protocol.md) +* [session](api/session.md) +* [webContents](api/web-contents.md) +* [Tray](api/tray.md) + +### Модулі для Renderer Process (Web Page): + +* [ipcRenderer](api/ipc-renderer.md) +* [remote](api/remote.md) +* [webFrame](api/web-frame.md) + +### Модулі для Both Processes: + +* [clipboard](api/clipboard.md) +* [crashReporter](api/crash-reporter.md) +* [nativeImage](api/native-image.md) +* [screen](api/screen.md) +* [shell](api/shell.md) + +## Розробка + +* [Стиль кодування](development/coding-style.md) +* [Source Code Directory Structure](development/source-code-directory-structure.md) +* [Technical Differences to NW.js (formerly node-webkit)](development/atom-shell-vs-node-webkit.md) +* [Build System Overview](development/build-system-overview.md) +* [Build Instructions (OS X)](development/build-instructions-osx.md) +* [Build Instructions (Windows)](development/build-instructions-windows.md) +* [Build Instructions (Linux)](development/build-instructions-linux.md) +* [Setting Up Symbol Server in debugger](development/setting-up-symbol-server.md) diff --git a/docs-translations/uk-UA/styleguide.md b/docs-translations/uk-UA/styleguide.md new file mode 100644 index 000000000000..041596700017 --- /dev/null +++ b/docs-translations/uk-UA/styleguide.md @@ -0,0 +1,97 @@ +# Electron Documentation Styleguide + +Find the appropriate section for your task: [reading Electron documentation](#reading-electron-documentation) +or [writing Electron documentation](#writing-electron-documentation). + +## Написання документації для Electron + +Існує кілька способів за допомогою яких ми ствоюємо документацію для Electron. + +- Maximum one `h1` title per page. +- Use `bash` instead of `cmd` in code blocks (because of syntax highlighter). +- Doc `h1` titles should match object name (i.e. `browser-window` → + `BrowserWindow`). + - Hyphen separated filenames, however, are fine. +- No headers following headers, add at least a one-sentence description. +- Methods headers are wrapped in `code` ticks. +- Event headers are wrapped in single 'quotation' marks. +- No nesting lists more than 2 levels (unfortunately because of markdown + renderer). +- Add section titles: Events, Class Methods and Instance Methods. +- Use 'will' over 'would' when describing outcomes. +- Events and methods are `h3` headers. +- Optional arguments written as `function (required[, optional])`. +- Optional arguments are denoted when called out in list. +- Line length is 80-column wrapped. +- Platform specific methods are noted in italics following method header. + - ```### `method(foo, bar)` _OS X_``` +- Prefer 'in the ___ process' over 'on' + +### Переклад документації + +Переклади документації знаходяться в дерикторії `docs-translations`. + +Щоб додати переклад (або частковий переклад) документації: + +- Create a subdirectory named by language abbreviation. +- Within that subdirectory, duplicate the `docs` directory, keeping the + names of directories and files same. +- Translate the files. +- Update the `README.md` within your language directory to link to the files + you have translated. +- Add a link to your translation directory on the main Electron [README](https://github.com/atom/electron#documentation-translations). + +## Читання документації Electron + +Кілька порад для того щоб легше зрозуміти синтаксис документації Electron. + +### Методи + +Приклад [методу](https://developer.mozilla.org/en-US/docs/Glossary/Method) +в документації: + +--- + +`methodName(required[, optional]))` + +* `require` String, **required** +* `optional` Integer + +--- + +The method name is followed by the arguments it takes. Optional arguments are +notated by brackets surrounding the optional argument as well as the comma +required if this optional argument follows another argument. + +Below the method is more detailed information on each of the arguments. The type +of argument is notated by either the common types: +[`String`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String), +[`Number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number), +[`Object`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object), +[`Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) +or a custom type like Electron's [`webContent`](api/web-content.md). + +### Події + +Приклад [події](https://developer.mozilla.org/en-US/docs/Web/API/Event) +в документації: + +--- + +Подія: 'wake-up' + +Повердає: + +* `time` Текст + +--- + +The event is a string that is used after a `.on` listener method. If it returns +a value it and its type is noted below. If you were to listen and respond to +this event it might look something like this: + +```javascript +Alarm.on('wake-up', function(time) { + console.log(time) +}) +``` From 7bb3bf0f4884998331b22c68b99d927a93945289 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 9 Dec 2015 12:05:47 +0800 Subject: [PATCH 66/67] docs: win.setIgnoreMouseEvents --- docs/api/browser-window.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index db02b6aa14b3..2fbd1544c3ef 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -747,3 +747,9 @@ Sets whether the window should be visible on all workspaces. Returns whether the window is visible on all workspaces. **Note:** This API always returns false on Windows. + +### `win.setIgnoreMouseEvents(ignore)` _OS X_ + +* `ignore` Boolean + +Ignore all moused events that happened in the window. From f7b7b3407c6d5b9a3e889ad59572e46e3c2b1b3d Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 9 Dec 2015 12:34:10 +0800 Subject: [PATCH 67/67] Update brightray for #3720 --- vendor/brightray | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/brightray b/vendor/brightray index 814923b77d21..006fdfba003f 160000 --- a/vendor/brightray +++ b/vendor/brightray @@ -1 +1 @@ -Subproject commit 814923b77d21261a9d1780bff0bd1beb55203843 +Subproject commit 006fdfba003f8350abf02446ff3868889a7b888c