mirror of
https://github.com/electron/electron.git
synced 2026-02-19 03:14:51 -05:00
Compare commits
2 Commits
try-fix-ap
...
tabs-onupd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36ce495886 | ||
|
|
42391fa4af |
@@ -107,6 +107,11 @@ The following methods of `chrome.tabs` are supported:
|
||||
- `chrome.tabs.update` (partial support)
|
||||
- supported properties: `url`, `muted`.
|
||||
|
||||
The following events of `chrome.tabs` are supported:
|
||||
|
||||
- `chrome.tabs.onUpdated`
|
||||
- `chrome.tabs.onZoomChanged`
|
||||
|
||||
> **Note:** In Chrome, passing `-1` as a tab ID signifies the "currently active
|
||||
> tab". Since Electron has no such concept, passing `-1` as a tab ID is not
|
||||
> supported and will raise an error.
|
||||
|
||||
@@ -686,6 +686,10 @@ filenames = {
|
||||
"shell/browser/extensions/api/streams_private/streams_private_api.h",
|
||||
"shell/browser/extensions/api/tabs/tabs_api.cc",
|
||||
"shell/browser/extensions/api/tabs/tabs_api.h",
|
||||
"shell/browser/extensions/api/tabs/tabs_event_router.cc",
|
||||
"shell/browser/extensions/api/tabs/tabs_event_router.h",
|
||||
"shell/browser/extensions/api/tabs/tabs_window_api.cc",
|
||||
"shell/browser/extensions/api/tabs/tabs_window_api.h",
|
||||
"shell/browser/extensions/electron_browser_context_keyed_service_factories.cc",
|
||||
"shell/browser/extensions/electron_browser_context_keyed_service_factories.h",
|
||||
"shell/browser/extensions/electron_component_extension_resource_manager.cc",
|
||||
|
||||
@@ -164,6 +164,8 @@
|
||||
#include "extensions/browser/script_executor.h"
|
||||
#include "extensions/browser/view_type_utils.h"
|
||||
#include "extensions/common/mojom/view_type.mojom.h"
|
||||
#include "shell/browser/extensions/api/tabs/tabs_event_router.h"
|
||||
#include "shell/browser/extensions/api/tabs/tabs_window_api.h"
|
||||
#include "shell/browser/extensions/electron_extension_web_contents_observer.h"
|
||||
#endif
|
||||
|
||||
@@ -893,6 +895,14 @@ void WebContents::InitZoomController(content::WebContents* web_contents,
|
||||
if (options.Get(options::kZoomFactor, &zoom_factor))
|
||||
zoom_controller_->SetDefaultZoomFactor(zoom_factor);
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
auto* tabs_window_api = extensions::TabsWindowsAPI::Get(GetBrowserContext());
|
||||
if (tabs_window_api) {
|
||||
tabs_window_api->tabs_event_router()->RegisterForTabNotifications(
|
||||
web_contents);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Nothing to do with ZoomController, but this function gets called in all
|
||||
// init cases!
|
||||
content::RenderViewHost* host = web_contents->GetRenderViewHost();
|
||||
|
||||
126
shell/browser/extensions/api/tabs/tabs_event_router.cc
Normal file
126
shell/browser/extensions/api/tabs/tabs_event_router.cc
Normal file
@@ -0,0 +1,126 @@
|
||||
// Copyright (c) 2023 Microsoft, GmbH
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/extensions/api/tabs/tabs_event_router.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/functional/bind.h"
|
||||
#include "chrome/browser/browser_process.h"
|
||||
#include "components/zoom/zoom_controller.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "extensions/common/features/feature.h"
|
||||
#include "extensions/common/mojom/event_dispatcher.mojom-forward.h"
|
||||
#include "shell/browser/api/electron_api_web_contents.h"
|
||||
#include "shell/browser/extensions/api/tabs/tabs_window_api.h"
|
||||
#include "shell/browser/web_contents_zoom_controller.h"
|
||||
#include "shell/common/extensions/api/tabs.h"
|
||||
#include "third_party/abseil-cpp/absl/types/optional.h"
|
||||
#include "third_party/blink/public/common/page/page_zoom.h"
|
||||
|
||||
using base::Value;
|
||||
using content::WebContents;
|
||||
using zoom::ZoomController;
|
||||
|
||||
using electron::WebContentsZoomController;
|
||||
|
||||
namespace extensions {
|
||||
|
||||
// namespace {
|
||||
// void ZoomModeToZoomSettings(ZoomController::ZoomMode zoom_mode,
|
||||
// api::tabs::ZoomSettings* zoom_settings) {
|
||||
// DCHECK(zoom_settings);
|
||||
// switch (zoom_mode) {
|
||||
// case ZoomController::ZOOM_MODE_DEFAULT:
|
||||
// zoom_settings->mode = api::tabs::ZOOM_SETTINGS_MODE_AUTOMATIC;
|
||||
// zoom_settings->scope = api::tabs::ZOOM_SETTINGS_SCOPE_PER_ORIGIN;
|
||||
// break;
|
||||
// case ZoomController::ZOOM_MODE_ISOLATED:
|
||||
// zoom_settings->mode = api::tabs::ZOOM_SETTINGS_MODE_AUTOMATIC;
|
||||
// zoom_settings->scope = api::tabs::ZOOM_SETTINGS_SCOPE_PER_TAB;
|
||||
// break;
|
||||
// case ZoomController::ZOOM_MODE_MANUAL:
|
||||
// zoom_settings->mode = api::tabs::ZOOM_SETTINGS_MODE_MANUAL;
|
||||
// zoom_settings->scope = api::tabs::ZOOM_SETTINGS_SCOPE_PER_TAB;
|
||||
// break;
|
||||
// case ZoomController::ZOOM_MODE_DISABLED:
|
||||
// zoom_settings->mode = api::tabs::ZOOM_SETTINGS_MODE_DISABLED;
|
||||
// zoom_settings->scope = api::tabs::ZOOM_SETTINGS_SCOPE_PER_TAB;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// } // namespace
|
||||
|
||||
TabsEventRouter::TabsEventRouter(content::BrowserContext* context)
|
||||
: context_(context) {}
|
||||
|
||||
TabsEventRouter::~TabsEventRouter() = default;
|
||||
|
||||
void TabsEventRouter::OnZoomControllerDestroyed(
|
||||
WebContentsZoomController* zoom_controller) {
|
||||
if (zoom_scoped_observations_.IsObservingSource(zoom_controller)) {
|
||||
zoom_scoped_observations_.RemoveObservation(zoom_controller);
|
||||
}
|
||||
}
|
||||
|
||||
void TabsEventRouter::OnZoomChanged(
|
||||
const electron::WebContentsZoomController::ZoomChangedEventData& data) {
|
||||
DCHECK(web_contents);
|
||||
auto* api_web_contents = electron::api::WebContents::From(data.web_contents);
|
||||
int tab_id = api_web_contents ? api_web_contents->ID() : -1;
|
||||
if (tab_id < 0)
|
||||
return;
|
||||
|
||||
// Prepare the zoom change information.
|
||||
api::tabs::OnZoomChange::ZoomChangeInfo zoom_change_info;
|
||||
zoom_change_info.tab_id = tab_id;
|
||||
zoom_change_info.old_zoom_factor =
|
||||
blink::PageZoomLevelToZoomFactor(data.old_zoom_level);
|
||||
zoom_change_info.new_zoom_factor =
|
||||
blink::PageZoomLevelToZoomFactor(data.new_zoom_level);
|
||||
// ZoomModeToZoomSettings(data.zoom_mode, &zoom_change_info.zoom_settings);
|
||||
|
||||
// Dispatch the |onZoomChange| event.
|
||||
DispatchEvent(data.web_contents->GetBrowserContext(),
|
||||
events::TABS_ON_ZOOM_CHANGE,
|
||||
api::tabs::OnZoomChange::kEventName,
|
||||
api::tabs::OnZoomChange::Create(zoom_change_info),
|
||||
EventRouter::USER_GESTURE_UNKNOWN);
|
||||
}
|
||||
|
||||
void TabsEventRouter::DispatchEvent(
|
||||
content::BrowserContext* context,
|
||||
events::HistogramValue histogram_value,
|
||||
const std::string& event_name,
|
||||
base::Value::List args,
|
||||
EventRouter::UserGestureState user_gesture) {
|
||||
EventRouter* event_router = EventRouter::Get(context);
|
||||
if (!event_router)
|
||||
return;
|
||||
|
||||
auto event = std::make_unique<Event>(histogram_value, event_name,
|
||||
std::move(args), context);
|
||||
event->user_gesture = user_gesture;
|
||||
event_router->BroadcastEvent(std::move(event));
|
||||
}
|
||||
|
||||
void TabsEventRouter::RegisterForTabNotifications(WebContents* contents) {
|
||||
zoom_scoped_observations_.AddObservation(
|
||||
WebContentsZoomController::FromWebContents(contents));
|
||||
}
|
||||
|
||||
void TabsEventRouter::UnregisterForTabNotifications(WebContents* contents) {
|
||||
if (auto* zoom_controller =
|
||||
WebContentsZoomController::FromWebContents(contents);
|
||||
zoom_scoped_observations_.IsObservingSource(zoom_controller)) {
|
||||
zoom_scoped_observations_.RemoveObservation(zoom_controller);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace extensions
|
||||
74
shell/browser/extensions/api/tabs/tabs_event_router.h
Normal file
74
shell/browser/extensions/api/tabs/tabs_event_router.h
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright 2013 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_BROWSER_EXTENSIONS_API_TABS_TABS_EVENT_ROUTER_H_
|
||||
#define SHELL_BROWSER_EXTENSIONS_API_TABS_TABS_EVENT_ROUTER_H_
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/scoped_multi_source_observation.h"
|
||||
#include "base/scoped_observation.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
#include "extensions/browser/event_router.h"
|
||||
#include "shell/browser/extensions/api/tabs/tabs_api.h"
|
||||
#include "shell/browser/web_contents_zoom_controller.h"
|
||||
#include "shell/browser/web_contents_zoom_observer.h"
|
||||
|
||||
namespace content {
|
||||
class WebContents;
|
||||
}
|
||||
|
||||
namespace extensions {
|
||||
|
||||
// The TabsEventRouter listens to tab events and routes them to listeners inside
|
||||
// extension process renderers.
|
||||
// TabsEventRouter will only route events from windows/tabs within a context to
|
||||
// extension processes in the same context.
|
||||
class TabsEventRouter : public electron::WebContentsZoomObserver {
|
||||
public:
|
||||
explicit TabsEventRouter(content::BrowserContext* context);
|
||||
|
||||
TabsEventRouter(const TabsEventRouter&) = delete;
|
||||
TabsEventRouter& operator=(const TabsEventRouter&) = delete;
|
||||
|
||||
~TabsEventRouter() override;
|
||||
|
||||
// WebContentsZoomController::Observer
|
||||
void OnZoomChanged(
|
||||
const electron::WebContentsZoomController::ZoomChangedEventData& data)
|
||||
override;
|
||||
void OnZoomControllerDestroyed(
|
||||
electron::WebContentsZoomController* controller) override;
|
||||
|
||||
// Register ourselves to receive the various notifications we are interested
|
||||
// in for a tab. Also create tab entry to observe web contents notifications.
|
||||
void RegisterForTabNotifications(content::WebContents* contents);
|
||||
|
||||
private:
|
||||
// The DispatchEvent methods forward events to the |context|'s event router.
|
||||
// The TabsEventRouter listens to events for all contexts,
|
||||
// so we avoid duplication by dropping events destined for other contexts.
|
||||
void DispatchEvent(content::BrowserContext* context,
|
||||
events::HistogramValue histogram_value,
|
||||
const std::string& event_name,
|
||||
base::Value::List args,
|
||||
EventRouter::UserGestureState user_gesture);
|
||||
|
||||
// Removes notifications and tab entry added in RegisterForTabNotifications.
|
||||
void UnregisterForTabNotifications(content::WebContents* contents);
|
||||
|
||||
// The main context that owns this event router.
|
||||
raw_ptr<content::BrowserContext> context_;
|
||||
|
||||
base::ScopedMultiSourceObservation<electron::WebContentsZoomController,
|
||||
electron::WebContentsZoomObserver>
|
||||
zoom_scoped_observations_{this};
|
||||
};
|
||||
|
||||
} // namespace extensions
|
||||
|
||||
#endif // SHELL_BROWSER_EXTENSIONS_API_TABS_TABS_EVENT_ROUTER_H_
|
||||
57
shell/browser/extensions/api/tabs/tabs_window_api.cc
Normal file
57
shell/browser/extensions/api/tabs/tabs_window_api.cc
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright 2012 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/extensions/api/tabs/tabs_window_api.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "base/lazy_instance.h"
|
||||
#include "extensions/browser/event_router.h"
|
||||
#include "extensions/browser/extension_system.h"
|
||||
#include "shell/browser/extensions/api/tabs/tabs_event_router.h"
|
||||
#include "shell/common/extensions/api/tabs.h"
|
||||
|
||||
namespace extensions {
|
||||
|
||||
TabsWindowsAPI::TabsWindowsAPI(content::BrowserContext* context)
|
||||
: browser_context_(context) {
|
||||
EventRouter* event_router = EventRouter::Get(browser_context_);
|
||||
|
||||
// Tabs API Events.
|
||||
event_router->RegisterObserver(this, api::tabs::OnZoomChange::kEventName);
|
||||
}
|
||||
|
||||
TabsWindowsAPI::~TabsWindowsAPI() = default;
|
||||
|
||||
// static
|
||||
TabsWindowsAPI* TabsWindowsAPI::Get(content::BrowserContext* context) {
|
||||
return BrowserContextKeyedAPIFactory<TabsWindowsAPI>::Get(context);
|
||||
}
|
||||
|
||||
TabsEventRouter* TabsWindowsAPI::tabs_event_router() {
|
||||
if (!tabs_event_router_.get()) {
|
||||
tabs_event_router_ = std::make_unique<TabsEventRouter>(browser_context_);
|
||||
}
|
||||
return tabs_event_router_.get();
|
||||
}
|
||||
|
||||
void TabsWindowsAPI::Shutdown() {
|
||||
EventRouter::Get(browser_context_)->UnregisterObserver(this);
|
||||
}
|
||||
|
||||
static base::LazyInstance<BrowserContextKeyedAPIFactory<TabsWindowsAPI>>::
|
||||
DestructorAtExit g_tabs_windows_api_factory = LAZY_INSTANCE_INITIALIZER;
|
||||
|
||||
BrowserContextKeyedAPIFactory<TabsWindowsAPI>*
|
||||
TabsWindowsAPI::GetFactoryInstance() {
|
||||
return g_tabs_windows_api_factory.Pointer();
|
||||
}
|
||||
|
||||
void TabsWindowsAPI::OnListenerAdded(const EventListenerInfo& details) {
|
||||
// Initialize the event routers.
|
||||
tabs_event_router();
|
||||
EventRouter::Get(browser_context_)->UnregisterObserver(this);
|
||||
}
|
||||
|
||||
} // namespace extensions
|
||||
53
shell/browser/extensions/api/tabs/tabs_window_api.h
Normal file
53
shell/browser/extensions/api/tabs/tabs_window_api.h
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright 2012 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_BROWSER_EXTENSIONS_API_TABS_TABS_WINDOWS_API_H_
|
||||
#define SHELL_BROWSER_EXTENSIONS_API_TABS_TABS_WINDOWS_API_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "components/keyed_service/core/keyed_service.h"
|
||||
#include "extensions/browser/browser_context_keyed_api_factory.h"
|
||||
#include "extensions/browser/event_router.h"
|
||||
|
||||
namespace extensions {
|
||||
class TabsEventRouter;
|
||||
|
||||
class TabsWindowsAPI : public BrowserContextKeyedAPI,
|
||||
public EventRouter::Observer {
|
||||
public:
|
||||
explicit TabsWindowsAPI(content::BrowserContext* context);
|
||||
~TabsWindowsAPI() override;
|
||||
|
||||
// Convenience method to get the TabsWindowsAPI for a BrowserContext.
|
||||
static TabsWindowsAPI* Get(content::BrowserContext* context);
|
||||
|
||||
TabsEventRouter* tabs_event_router();
|
||||
|
||||
// KeyedService implementation.
|
||||
void Shutdown() override;
|
||||
|
||||
// BrowserContextKeyedAPI implementation.
|
||||
static BrowserContextKeyedAPIFactory<TabsWindowsAPI>* GetFactoryInstance();
|
||||
|
||||
// EventRouter::Observer implementation.
|
||||
void OnListenerAdded(const extensions::EventListenerInfo& details) override;
|
||||
|
||||
private:
|
||||
friend class BrowserContextKeyedAPIFactory<TabsWindowsAPI>;
|
||||
|
||||
raw_ptr<content::BrowserContext> browser_context_;
|
||||
|
||||
// BrowserContextKeyedAPI implementation.
|
||||
static const char* service_name() {
|
||||
return "TabsWindowsAPI";
|
||||
}
|
||||
|
||||
std::unique_ptr<TabsEventRouter> tabs_event_router_;
|
||||
};
|
||||
|
||||
} // namespace extensions
|
||||
|
||||
#endif // SHELL_BROWSER_EXTENSIONS_API_TABS_TABS_WINDOWS_API_H_
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "shell/browser/extensions/electron_browser_context_keyed_service_factories.h"
|
||||
|
||||
#include "extensions/browser/updater/update_service_factory.h"
|
||||
#include "shell/browser/extensions/api/tabs/tabs_window_api.h"
|
||||
#include "shell/browser/extensions/electron_extension_system_factory.h"
|
||||
|
||||
namespace extensions::electron {
|
||||
@@ -14,6 +15,8 @@ void EnsureBrowserContextKeyedServiceFactoriesBuilt() {
|
||||
// extensions embedders (and namely chrome.)
|
||||
UpdateServiceFactory::GetInstance();
|
||||
|
||||
TabsWindowsAPI::GetFactoryInstance();
|
||||
|
||||
ElectronExtensionSystemFactory::GetInstance();
|
||||
}
|
||||
|
||||
|
||||
@@ -705,6 +705,90 @@
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
// Electron does not support tabs.create, so this event will never be fired,
|
||||
// but we have this here to prevent it from causing undefined errors.
|
||||
{
|
||||
"name": "onCreated",
|
||||
"type": "function",
|
||||
"description": "Fired when a tab is created. Note that the tab's URL and tab group membership may not be set at the time this event is fired, but you can listen to onUpdated events so as to be notified when a URL is set or the tab is added to a tab group.",
|
||||
"parameters": [
|
||||
{
|
||||
"$ref": "Tab",
|
||||
"name": "tab",
|
||||
"description": "Details of the tab that was created."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "onUpdated",
|
||||
"type": "function",
|
||||
"description": "Fired when a tab is updated.",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "tabId",
|
||||
"minimum": 0
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"name": "changeInfo",
|
||||
"description": "Lists the changes to the state of the tab that was updated.",
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string",
|
||||
"optional": true,
|
||||
"description": "The tab's URL if it has changed."
|
||||
},
|
||||
"groupId": {
|
||||
"type": "integer",
|
||||
"optional": true,
|
||||
"minimum": -1,
|
||||
"description": "The tab's new group."
|
||||
},
|
||||
"pinned": {
|
||||
"type": "boolean",
|
||||
"optional": true,
|
||||
"description": "The tab's new pinned state."
|
||||
},
|
||||
"audible": {
|
||||
"type": "boolean",
|
||||
"optional": true,
|
||||
"description": "The tab's new audible state."
|
||||
},
|
||||
"discarded": {
|
||||
"type": "boolean",
|
||||
"optional": true,
|
||||
"description": "The tab's new discarded state."
|
||||
},
|
||||
"autoDiscardable": {
|
||||
"type": "boolean",
|
||||
"optional": true,
|
||||
"description": "The tab's new auto-discardable state."
|
||||
},
|
||||
"mutedInfo": {
|
||||
"$ref": "MutedInfo",
|
||||
"optional": true,
|
||||
"description": "The tab's new muted state and the reason for the change."
|
||||
},
|
||||
"favIconUrl": {
|
||||
"type": "string",
|
||||
"optional": true,
|
||||
"description": "The tab's new favicon URL."
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"optional": true,
|
||||
"description": "The tab's new title."
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"$ref": "Tab",
|
||||
"name": "tab",
|
||||
"description": "Gives the state of the tab that was updated."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "onZoomChange",
|
||||
"type": "function",
|
||||
|
||||
@@ -878,7 +878,12 @@ describe('chrome extensions', () => {
|
||||
const [,, responseString] = await once(w.webContents, 'console-message');
|
||||
|
||||
const response = JSON.parse(responseString);
|
||||
expect(response).to.deep.equal(2);
|
||||
expect(response).to.deep.equal({
|
||||
newZoomFactor: 2,
|
||||
oldZoomFactor: 1.2,
|
||||
tabId: 1,
|
||||
zoomSettings: {}
|
||||
});
|
||||
});
|
||||
|
||||
it('getZoomSettings', async () => {
|
||||
|
||||
@@ -12,10 +12,9 @@ const handleRequest = (request, sender, sendResponse) => {
|
||||
|
||||
case 'setZoom': {
|
||||
const [zoom] = args;
|
||||
chrome.tabs.setZoom(tabId, zoom).then(async () => {
|
||||
const updatedZoom = await chrome.tabs.getZoom(tabId);
|
||||
sendResponse(updatedZoom);
|
||||
});
|
||||
|
||||
chrome.tabs.onZoomChange.addListener(sendResponse);
|
||||
chrome.tabs.setZoom(tabId, zoom);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user