mirror of
https://github.com/electron/electron.git
synced 2026-02-19 03:14:51 -05:00
* chore: bump chromium in DEPS to 145.0.7562.0 * fix(patch-conflict): update code cache patch for PersistentCache refactor Upstream refactored code cache to use PersistentCache with new class-based implementation (NoopCodeCacheHost, LocalCodeCacheHost, CodeCacheWithPersistentCacheHost). Updated patch to integrate custom scheme support into the new structure while preserving ProcessLockURLIsCodeCacheScheme checks for embedder-registered schemes. Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7044986 Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com> * fix(patch-conflict): update dialog patch for RequestXdgDesktopPortal API Upstream changed from SetSystemdScopeUnitNameForXdgPortal to RequestXdgDesktopPortal API pattern. Updated OnServiceStarted signature and kept OnSystemdUnitStarted callback that calls Electron's file_dialog::StartPortalAvailabilityTestInBackground(). Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7204285 Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com> * fix(patch-conflict): remove reference to deleted AbortByPlaceholderLayout flag Upstream removed the AbortByPlaceholderLayout runtime flag from runtime_enabled_features.json5. Updated patch to only add ElectronCSSCornerSmoothing without the removed flag reference. Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7226494 Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com> * chore: update patch hunk headers Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com> * fix(build): guard media_file_system_registry for ChromeOS only Upstream CL https://chromium-review.googlesource.com/c/chromium/src/+/7100719 moved media_file_system_registry to be ChromeOS-only since Media Galleries is a Chrome Apps API and Chrome Apps are only available on Chrome OS now. Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com> * fix(build): update VideoPixelFormat API for SharedImageFormat Upstream CL https://chromium-review.googlesource.com/c/chromium/src/+/7207153 removed VideoPixelFormatToGfxBufferFormat as part of migration to SharedImageFormat. Update to use VideoPixelFormatToSharedImageFormat which directly returns the SharedImageFormat. Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com> * fix(build): extend profile methods patch for ShouldEnableXfaForms The ShouldEnableXfaForms function uses Profile::FromBrowserContext() which is not available in Electron. Wrap the profile-dependent code in #if 0 to fall through to the feature flag default. Co-Authored-By: Claude <noreply@anthropic.com> * chore: bump chromium in DEPS to 145.0.7563.0 * chore: bump chromium in DEPS to 145.0.7565.0 * chore: bump chromium in DEPS to 145.0.7567.0 * chore: bump chromium in DEPS to 145.0.7568.0 * fix(patch-conflict): update content_main_delegate.h context for IsInitFeatureListEarly Upstream added a new IsInitFeatureListEarly() virtual method to ContentMainDelegate just before where our GetBrowserV8SnapshotFilename() method is added. Updated patch context to account for this new method. Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7092856 Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com> * chore: update patch hunk headers Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com> * fix(patch-update): include v8-cppgc.h for CppHeap complete type The std::unique_ptr<v8::CppHeap> default argument in node.h requires the complete CppHeap type definition for the destructor. Added the v8-cppgc.h include to provide the full type definition. Ref: Unable to locate CL - libc++ unique_ptr requires complete type for destructor Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com> * chore: update patch hunk headers Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com> * fix(build): move NativeAppWindowFrameViewMacClient before constructor The std::unique_ptr<NativeAppWindowFrameViewMacClient> member requires the complete type definition to be visible at the point of the constructor because the unique_ptr destructor may be instantiated during exception handling. Moved the class definition before the NativeWindowMac constructor. Ref: Unable to locate CL - libc++ unique_ptr requires complete type for destructor Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com> * fix(patch-conflict): update create_browser_v8_snapshot_file_name_fuse context for IsInitFeatureListEarly The upstream added IsInitFeatureListEarly() virtual method declaration to ContentMainDelegate class. Updated the patch context to account for this new function being present before the GetBrowserV8SnapshotFilename() declaration we add. Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7092856 Co-Authored-By: Claude <noreply@anthropic.com> * chore: update patch hunk headers Co-Authored-By: Claude <noreply@anthropic.com> * fix(patch-update): remove reverted IsInitFeatureListEarly from v8 snapshot patch The upstream added IsInitFeatureListEarly() was reverted, so the patch should not include this declaration. Only GetBrowserV8SnapshotFilename() should be added by the create_browser_v8_snapshot_file_name_fuse patch. Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7230430 Co-Authored-By: Claude <noreply@anthropic.com> * 6171655: include single_thread_task_runner.h for complete type Added include for base/task/single_thread_task_runner.h in osr_converter.cc to resolve incomplete type error when using base::SingleThreadTaskRunner::GetCurrentDefault(). Ref: https://chromium-review.googlesource.com/c/chromium/src/+/6171655 Co-Authored-By: Claude <noreply@anthropic.com> * 7224136: use CHROMIUM_GIT_REVISION directly instead of removed function Upstream removed GetChromiumGitRevision() function from embedder_support. Updated to use CHROMIUM_GIT_REVISION macro directly via build/util/chromium_git_revision.h as recommended in the Chromium CL. Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7224136 Co-Authored-By: Claude <noreply@anthropic.com> * fixup! 7224136: use CHROMIUM_GIT_REVISION directly instead of removed function * fix(build): add missing include `components/dbus/xdg/systemd.h` for `void OnSystemdUnitStarted(dbus_xdg::SystemdUnitStatus)` in the same patch. * fix(build): adapt to string-view-ification change in windows jump_list.cc 7186922: Fix unsafe buffer usage in base/win/win_util.cc https://chromium-review.googlesource.com/c/chromium/src/+/7186922 * chore: update libc++ filenames * fixup! fix(build): add missing include * fixup! fix(build): extend profile methods patch for ShouldEnableXfaForms * fixup! fix(build): guard media_file_system_registry for ChromeOS only * fixup! fixup! fix(build): extend profile methods patch for ShouldEnableXfaForms --------- Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com> Co-authored-by: Keeley Hammond <khammond@slack-corp.com> Co-authored-by: Claude <svc-devxp-claude@slack-corp.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: clavin <clavin@electronjs.org>
364 lines
12 KiB
C++
364 lines
12 KiB
C++
// Copyright (c) 2016 GitHub, Inc.
|
|
// Use of this source code is governed by the MIT license that can be
|
|
// found in the LICENSE file.
|
|
|
|
// FIXME(samuelmaddock): refactor this class to use modern
|
|
// Microsoft::WRL::ComPtr must come before other includes. fixes bad #defines
|
|
// from <shlwapi.h>.
|
|
#include "base/win/shlwapi.h" // NOLINT(build/include_order)
|
|
|
|
#include "shell/browser/ui/win/jump_list.h"
|
|
|
|
#include <propkey.h> // for PKEY_* constants
|
|
|
|
#include "base/logging.h"
|
|
#include "base/win/scoped_co_mem.h"
|
|
#include "base/win/scoped_propvariant.h"
|
|
#include "base/win/win_util.h"
|
|
|
|
namespace {
|
|
|
|
using electron::JumpListCategory;
|
|
using electron::JumpListItem;
|
|
using electron::JumpListResult;
|
|
|
|
bool AppendTask(const JumpListItem& item, IObjectCollection* collection) {
|
|
DCHECK(collection);
|
|
|
|
CComPtr<IShellLink> link;
|
|
if (FAILED(link.CoCreateInstance(CLSID_ShellLink)) ||
|
|
FAILED(link->SetPath(item.path.value().c_str())) ||
|
|
FAILED(link->SetArguments(item.arguments.c_str())) ||
|
|
FAILED(link->SetWorkingDirectory(item.working_dir.value().c_str())) ||
|
|
FAILED(link->SetDescription(item.description.c_str())))
|
|
return false;
|
|
|
|
// SetDescription limits the size of the parameter to INFOTIPSIZE (1024),
|
|
// which suggests rejection when exceeding that limit, but experimentation
|
|
// has shown that descriptions longer than 260 characters cause a silent
|
|
// failure, despite SetDescription returning the success code S_OK.
|
|
if (item.description.size() > 260)
|
|
return false;
|
|
|
|
if (!item.icon_path.empty() &&
|
|
FAILED(link->SetIconLocation(item.icon_path.value().c_str(),
|
|
item.icon_index)))
|
|
return false;
|
|
|
|
CComQIPtr<IPropertyStore> property_store(link);
|
|
if (!base::win::SetStringValueForPropertyStore(property_store, PKEY_Title,
|
|
item.title))
|
|
return false;
|
|
|
|
return SUCCEEDED(collection->AddObject(link));
|
|
}
|
|
|
|
bool AppendSeparator(IObjectCollection* collection) {
|
|
DCHECK(collection);
|
|
|
|
CComPtr<IShellLink> shell_link;
|
|
if (SUCCEEDED(shell_link.CoCreateInstance(CLSID_ShellLink))) {
|
|
CComQIPtr<IPropertyStore> property_store(shell_link);
|
|
if (base::win::SetBooleanValueForPropertyStore(
|
|
property_store, PKEY_AppUserModel_IsDestListSeparator, true))
|
|
return SUCCEEDED(collection->AddObject(shell_link));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool AppendFile(const JumpListItem& item, IObjectCollection* collection) {
|
|
DCHECK(collection);
|
|
|
|
CComPtr<IShellItem> file;
|
|
if (SUCCEEDED(SHCreateItemFromParsingName(item.path.value().c_str(), nullptr,
|
|
IID_PPV_ARGS(&file))))
|
|
return SUCCEEDED(collection->AddObject(file));
|
|
|
|
return false;
|
|
}
|
|
|
|
bool GetShellItemFileName(IShellItem* shell_item, base::FilePath* file_name) {
|
|
DCHECK(shell_item);
|
|
DCHECK(file_name);
|
|
|
|
base::win::ScopedCoMem<wchar_t> file_name_buffer;
|
|
if (SUCCEEDED(
|
|
shell_item->GetDisplayName(SIGDN_FILESYSPATH, &file_name_buffer))) {
|
|
*file_name = base::FilePath(file_name_buffer.get());
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ConvertShellLinkToJumpListItem(IShellLink* shell_link,
|
|
JumpListItem* item) {
|
|
DCHECK(shell_link);
|
|
DCHECK(item);
|
|
|
|
item->type = JumpListItem::Type::kTask;
|
|
wchar_t path[MAX_PATH];
|
|
if (FAILED(shell_link->GetPath(path, std::size(path), nullptr, 0)))
|
|
return false;
|
|
|
|
item->path = base::FilePath(path);
|
|
|
|
CComQIPtr<IPropertyStore> property_store = shell_link;
|
|
base::win::ScopedPropVariant prop;
|
|
if (SUCCEEDED(
|
|
property_store->GetValue(PKEY_Link_Arguments, prop.Receive())) &&
|
|
(prop.get().vt == VT_LPWSTR)) {
|
|
item->arguments = prop.get().pwszVal;
|
|
}
|
|
|
|
if (SUCCEEDED(property_store->GetValue(PKEY_Title, prop.Receive())) &&
|
|
(prop.get().vt == VT_LPWSTR)) {
|
|
item->title = prop.get().pwszVal;
|
|
}
|
|
|
|
if (SUCCEEDED(shell_link->GetWorkingDirectory(path, std::size(path))))
|
|
item->working_dir = base::FilePath(path);
|
|
|
|
int icon_index;
|
|
if (SUCCEEDED(
|
|
shell_link->GetIconLocation(path, std::size(path), &icon_index))) {
|
|
item->icon_path = base::FilePath(path);
|
|
item->icon_index = icon_index;
|
|
}
|
|
|
|
wchar_t item_desc[INFOTIPSIZE];
|
|
if (SUCCEEDED(shell_link->GetDescription(item_desc, std::size(item_desc))))
|
|
item->description = item_desc;
|
|
|
|
return true;
|
|
}
|
|
|
|
// Convert IObjectArray of IShellLink & IShellItem to std::vector.
|
|
void ConvertRemovedJumpListItems(IObjectArray* in,
|
|
std::vector<JumpListItem>* out) {
|
|
DCHECK(in);
|
|
DCHECK(out);
|
|
|
|
UINT removed_count;
|
|
if (SUCCEEDED(in->GetCount(&removed_count) && (removed_count > 0))) {
|
|
out->reserve(removed_count);
|
|
JumpListItem item;
|
|
IShellItem* shell_item;
|
|
IShellLink* shell_link;
|
|
for (UINT i = 0; i < removed_count; ++i) {
|
|
if (SUCCEEDED(in->GetAt(i, IID_PPV_ARGS(&shell_item)))) {
|
|
item.type = JumpListItem::Type::kFile;
|
|
GetShellItemFileName(shell_item, &item.path);
|
|
out->push_back(item);
|
|
shell_item->Release();
|
|
} else if (SUCCEEDED(in->GetAt(i, IID_PPV_ARGS(&shell_link)))) {
|
|
if (ConvertShellLinkToJumpListItem(shell_link, &item))
|
|
out->push_back(item);
|
|
shell_link->Release();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
namespace electron {
|
|
|
|
JumpListItem::JumpListItem() = default;
|
|
JumpListItem::JumpListItem(const JumpListItem&) = default;
|
|
JumpListItem::~JumpListItem() = default;
|
|
JumpListCategory::JumpListCategory() = default;
|
|
JumpListCategory::JumpListCategory(const JumpListCategory&) = default;
|
|
JumpListCategory::~JumpListCategory() = default;
|
|
|
|
JumpList::JumpList(const std::wstring& app_id) : app_id_(app_id) {
|
|
destinations_.CoCreateInstance(CLSID_DestinationList);
|
|
}
|
|
|
|
JumpList::~JumpList() = default;
|
|
|
|
bool JumpList::Begin(int* min_items, std::vector<JumpListItem>* removed_items) {
|
|
DCHECK(destinations_);
|
|
if (!destinations_)
|
|
return false;
|
|
|
|
if (FAILED(destinations_->SetAppID(app_id_.c_str())))
|
|
return false;
|
|
|
|
UINT min_slots;
|
|
CComPtr<IObjectArray> removed;
|
|
if (FAILED(destinations_->BeginList(&min_slots, IID_PPV_ARGS(&removed))))
|
|
return false;
|
|
|
|
if (min_items)
|
|
*min_items = min_slots;
|
|
|
|
if (removed_items)
|
|
ConvertRemovedJumpListItems(removed, removed_items);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool JumpList::Abort() {
|
|
DCHECK(destinations_);
|
|
if (!destinations_)
|
|
return false;
|
|
|
|
return SUCCEEDED(destinations_->AbortList());
|
|
}
|
|
|
|
bool JumpList::Commit() {
|
|
DCHECK(destinations_);
|
|
if (!destinations_)
|
|
return false;
|
|
|
|
return SUCCEEDED(destinations_->CommitList());
|
|
}
|
|
|
|
bool JumpList::Delete() {
|
|
DCHECK(destinations_);
|
|
if (!destinations_)
|
|
return false;
|
|
|
|
return SUCCEEDED(destinations_->DeleteList(app_id_.c_str()));
|
|
}
|
|
|
|
// This method will attempt to append as many items to the Jump List as
|
|
// possible, and will return a single error code even if multiple things
|
|
// went wrong in the process. To get detailed information about what went
|
|
// wrong enable runtime logging.
|
|
JumpListResult JumpList::AppendCategory(const JumpListCategory& category) {
|
|
DCHECK(destinations_);
|
|
if (!destinations_)
|
|
return JumpListResult::kGenericError;
|
|
|
|
if (category.items.empty())
|
|
return JumpListResult::kSuccess;
|
|
|
|
CComPtr<IObjectCollection> collection;
|
|
if (FAILED(collection.CoCreateInstance(CLSID_EnumerableObjectCollection))) {
|
|
return JumpListResult::kGenericError;
|
|
}
|
|
|
|
auto result = JumpListResult::kSuccess;
|
|
// Keep track of how many items were actually appended to the category.
|
|
int appended_count = 0;
|
|
for (const auto& item : category.items) {
|
|
switch (item.type) {
|
|
case JumpListItem::Type::kTask:
|
|
if (AppendTask(item, collection))
|
|
++appended_count;
|
|
else
|
|
LOG(ERROR) << "Failed to append task '" << item.title
|
|
<< "' "
|
|
"to Jump List.";
|
|
break;
|
|
|
|
case JumpListItem::Type::kSeparator:
|
|
if (category.type == JumpListCategory::Type::kTasks) {
|
|
if (AppendSeparator(collection))
|
|
++appended_count;
|
|
} else {
|
|
LOG(ERROR) << "Can't append separator to Jump List category " << "'"
|
|
<< category.name << "'. "
|
|
<< "Separators are only allowed in the standard 'Tasks' "
|
|
"Jump List category.";
|
|
result = JumpListResult::kCustomCategorySeparatorError;
|
|
}
|
|
break;
|
|
|
|
case JumpListItem::Type::kFile:
|
|
if (AppendFile(item, collection))
|
|
++appended_count;
|
|
else
|
|
LOG(ERROR) << "Failed to append '" << item.path.value()
|
|
<< "' "
|
|
"to Jump List.";
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (appended_count == 0)
|
|
return result;
|
|
|
|
if ((static_cast<size_t>(appended_count) < category.items.size()) &&
|
|
(result == JumpListResult::kSuccess)) {
|
|
result = JumpListResult::kGenericError;
|
|
}
|
|
|
|
CComQIPtr<IObjectArray> items(collection);
|
|
|
|
if (category.type == JumpListCategory::Type::kTasks) {
|
|
if (FAILED(destinations_->AddUserTasks(items))) {
|
|
LOG(ERROR) << "Failed to append items to the standard Tasks category.";
|
|
if (result == JumpListResult::kSuccess)
|
|
result = JumpListResult::kGenericError;
|
|
}
|
|
} else {
|
|
HRESULT hr = destinations_->AppendCategory(category.name.c_str(), items);
|
|
if (FAILED(hr)) {
|
|
if (hr == static_cast<HRESULT>(0x80040F03)) {
|
|
LOG(ERROR) << "Failed to append custom category " << "'"
|
|
<< category.name << "' "
|
|
<< "to Jump List due to missing file type registration.";
|
|
result = JumpListResult::kMissingFileTypeRegistrationError;
|
|
} else if (hr == E_ACCESSDENIED) {
|
|
LOG(ERROR) << "Failed to append custom category " << "'"
|
|
<< category.name << "' "
|
|
<< "to Jump List due to system privacy settings.";
|
|
result = JumpListResult::kCustomCategoryAccessDeniedError;
|
|
} else {
|
|
LOG(ERROR) << "Failed to append custom category " << "'"
|
|
<< category.name << "' to Jump List.";
|
|
if (result == JumpListResult::kSuccess)
|
|
result = JumpListResult::kGenericError;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// This method will attempt to append as many categories to the Jump List
|
|
// as possible, and will return a single error code even if multiple things
|
|
// went wrong in the process. To get detailed information about what went
|
|
// wrong enable runtime logging.
|
|
JumpListResult JumpList::AppendCategories(
|
|
const std::vector<JumpListCategory>& categories) {
|
|
DCHECK(destinations_);
|
|
if (!destinations_)
|
|
return JumpListResult::kGenericError;
|
|
|
|
auto result = JumpListResult::kSuccess;
|
|
for (const auto& category : categories) {
|
|
auto latestResult = JumpListResult::kSuccess;
|
|
switch (category.type) {
|
|
case JumpListCategory::Type::kTasks:
|
|
case JumpListCategory::Type::kCustom:
|
|
latestResult = AppendCategory(category);
|
|
break;
|
|
|
|
case JumpListCategory::Type::kRecent:
|
|
if (FAILED(destinations_->AppendKnownCategory(KDC_RECENT))) {
|
|
LOG(ERROR) << "Failed to append Recent category to Jump List.";
|
|
latestResult = JumpListResult::kGenericError;
|
|
}
|
|
break;
|
|
|
|
case JumpListCategory::Type::kFrequent:
|
|
if (FAILED(destinations_->AppendKnownCategory(KDC_FREQUENT))) {
|
|
LOG(ERROR) << "Failed to append Frequent category to Jump List.";
|
|
latestResult = JumpListResult::kGenericError;
|
|
}
|
|
break;
|
|
}
|
|
// Keep the first non-generic error code as only one can be returned from
|
|
// the function (so try to make it the most useful one).
|
|
if (((result == JumpListResult::kSuccess) ||
|
|
(result == JumpListResult::kGenericError)) &&
|
|
(latestResult != JumpListResult::kSuccess))
|
|
result = latestResult;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
} // namespace electron
|