mirror of
https://github.com/electron/electron.git
synced 2026-05-02 03:00:22 -04:00
perf: use GIO instead of xdg-mime for app.getApplicationNameForProtocol() (#51251)
perf: use GIO instead of xdg-mime for app.getApplicationNameForProtocol() The Linux impl of app.getApplicationNameForProtocol() now uses `g_app_info_get_default_for_uri_scheme()` + `g_app_info_get_display_name()` instead of spawning a call to the `xdg-mime` shell command. Clean up the related tests: remove the xdg-mime mock.
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
#include <gio/gio.h>
|
||||
#include <gtk/gtk.h>
|
||||
#endif
|
||||
|
||||
@@ -15,6 +16,7 @@
|
||||
#include "base/environment.h"
|
||||
#include "base/process/launch.h"
|
||||
#include "base/strings/strcat.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "electron/electron_version.h"
|
||||
#include "shell/browser/javascript_environment.h"
|
||||
#include "shell/browser/native_window.h"
|
||||
@@ -135,11 +137,15 @@ bool Browser::RemoveAsDefaultProtocolClient(const std::string& protocol,
|
||||
}
|
||||
|
||||
std::u16string Browser::GetApplicationNameForProtocol(const GURL& url) {
|
||||
const std::vector<std::string> argv = {
|
||||
"xdg-mime", "query", "default",
|
||||
base::StrCat({"x-scheme-handler/", url.scheme()})};
|
||||
const auto scheme = std::string{url.scheme()}; // gio can't use string_view
|
||||
auto* app_info = g_app_info_get_default_for_uri_scheme(scheme.c_str());
|
||||
if (!app_info)
|
||||
return {};
|
||||
|
||||
return base::ASCIIToUTF16(GetXdgAppOutput(argv).value_or(std::string()));
|
||||
const char* const name = g_app_info_get_display_name(app_info);
|
||||
const std::u16string u16name = base::UTF8ToUTF16(name);
|
||||
g_object_unref(app_info);
|
||||
return u16name;
|
||||
}
|
||||
|
||||
bool Browser::SetBadgeCount(std::optional<int> count) {
|
||||
|
||||
@@ -1530,21 +1530,17 @@ describe('app module', () => {
|
||||
ifdescribe(process.platform === 'linux')('on Linux with mocked XDG dirs', () => {
|
||||
const fixtureApp = path.join(fixturesPath, 'api', 'protocol-name');
|
||||
const desktopFileId = 'mock-browser.desktop';
|
||||
const mockDisplayName = 'Mock Browser';
|
||||
const mockScheme = 'mockproto';
|
||||
const mockMimeType = `x-scheme-handler/${mockScheme}`;
|
||||
|
||||
function spawnWithXdgMock(
|
||||
url: string,
|
||||
xdgDataHome: string,
|
||||
xdgConfigHome: string,
|
||||
xdgBinDir: string
|
||||
): Promise<string> {
|
||||
function spawnWithXdgMock(url: string, xdgDataHome: string, xdgConfigHome: string): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const child = cp.spawn(process.execPath, [fixtureApp, url], {
|
||||
env: {
|
||||
...process.env,
|
||||
PATH: [xdgBinDir, process.env.PATH].filter(Boolean).join(':'),
|
||||
XDG_DATA_HOME: xdgDataHome,
|
||||
XDG_DATA_DIRS: [xdgDataHome, process.env.XDG_DATA_DIRS].filter(Boolean).join(':'),
|
||||
XDG_DATA_DIRS: xdgDataHome,
|
||||
XDG_CONFIG_HOME: xdgConfigHome
|
||||
},
|
||||
stdio: ['ignore', 'pipe', 'pipe']
|
||||
@@ -1565,7 +1561,7 @@ describe('app module', () => {
|
||||
|
||||
try {
|
||||
const parsed = JSON.parse(stdout);
|
||||
resolve(parsed.name.trimEnd());
|
||||
resolve(parsed.name);
|
||||
} catch {
|
||||
reject(new Error(`Failed to parse output: ${stdout}\nstderr: ${stderr}`));
|
||||
}
|
||||
@@ -1577,22 +1573,42 @@ describe('app module', () => {
|
||||
let xdgDir: string;
|
||||
let xdgDataHome: string;
|
||||
let xdgConfigHome: string;
|
||||
let xdgBinDir: string;
|
||||
before(() => {
|
||||
({ xdgDir, xdgDataHome, xdgConfigHome, xdgBinDir } = makeXdgMockDirectories('electron-xdg-'));
|
||||
xdgDir = fs.mkdtempSync(path.join(os.tmpdir(), 'electron-xdg-'));
|
||||
xdgDataHome = path.join(xdgDir, 'data');
|
||||
xdgConfigHome = path.join(xdgDir, 'config');
|
||||
const appsDir = path.join(xdgDataHome, 'applications');
|
||||
fs.mkdirSync(appsDir, { recursive: true });
|
||||
fs.mkdirSync(xdgConfigHome, { recursive: true });
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(appsDir, desktopFileId),
|
||||
[
|
||||
'[Desktop Entry]',
|
||||
`Name=${mockDisplayName}`,
|
||||
'Exec=/usr/bin/true %u',
|
||||
'Type=Application',
|
||||
`MimeType=${mockMimeType};`
|
||||
].join('\n')
|
||||
);
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(xdgConfigHome, 'mimeapps.list'),
|
||||
['[Default Applications]', `${mockMimeType}=${desktopFileId}`].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
after(() => {
|
||||
fs.rmSync(xdgDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it('returns the desktop file ID for a registered protocol', async () => {
|
||||
const name = await spawnWithXdgMock(`${mockScheme}://`, xdgDataHome, xdgConfigHome, xdgBinDir);
|
||||
expect(name).to.equal(desktopFileId);
|
||||
it('returns the display name for a registered protocol', async () => {
|
||||
const name = await spawnWithXdgMock(`${mockScheme}://`, xdgDataHome, xdgConfigHome);
|
||||
expect(name).to.equal(mockDisplayName);
|
||||
});
|
||||
|
||||
it('returns an empty string for an unregistered protocol', async () => {
|
||||
const name = await spawnWithXdgMock('unregistered-proto://', xdgDataHome, xdgConfigHome, xdgBinDir);
|
||||
const name = await spawnWithXdgMock('unregistered-proto://', xdgDataHome, xdgConfigHome);
|
||||
expect(name).to.equal('');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user