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>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#if BUILDFLAG(IS_LINUX)
|
#if BUILDFLAG(IS_LINUX)
|
||||||
|
#include <gio/gio.h>
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -15,6 +16,7 @@
|
|||||||
#include "base/environment.h"
|
#include "base/environment.h"
|
||||||
#include "base/process/launch.h"
|
#include "base/process/launch.h"
|
||||||
#include "base/strings/strcat.h"
|
#include "base/strings/strcat.h"
|
||||||
|
#include "base/strings/utf_string_conversions.h"
|
||||||
#include "electron/electron_version.h"
|
#include "electron/electron_version.h"
|
||||||
#include "shell/browser/javascript_environment.h"
|
#include "shell/browser/javascript_environment.h"
|
||||||
#include "shell/browser/native_window.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) {
|
std::u16string Browser::GetApplicationNameForProtocol(const GURL& url) {
|
||||||
const std::vector<std::string> argv = {
|
const auto scheme = std::string{url.scheme()}; // gio can't use string_view
|
||||||
"xdg-mime", "query", "default",
|
auto* app_info = g_app_info_get_default_for_uri_scheme(scheme.c_str());
|
||||||
base::StrCat({"x-scheme-handler/", url.scheme()})};
|
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) {
|
bool Browser::SetBadgeCount(std::optional<int> count) {
|
||||||
|
|||||||
@@ -1530,21 +1530,17 @@ describe('app module', () => {
|
|||||||
ifdescribe(process.platform === 'linux')('on Linux with mocked XDG dirs', () => {
|
ifdescribe(process.platform === 'linux')('on Linux with mocked XDG dirs', () => {
|
||||||
const fixtureApp = path.join(fixturesPath, 'api', 'protocol-name');
|
const fixtureApp = path.join(fixturesPath, 'api', 'protocol-name');
|
||||||
const desktopFileId = 'mock-browser.desktop';
|
const desktopFileId = 'mock-browser.desktop';
|
||||||
|
const mockDisplayName = 'Mock Browser';
|
||||||
const mockScheme = 'mockproto';
|
const mockScheme = 'mockproto';
|
||||||
|
const mockMimeType = `x-scheme-handler/${mockScheme}`;
|
||||||
|
|
||||||
function spawnWithXdgMock(
|
function spawnWithXdgMock(url: string, xdgDataHome: string, xdgConfigHome: string): Promise<string> {
|
||||||
url: string,
|
|
||||||
xdgDataHome: string,
|
|
||||||
xdgConfigHome: string,
|
|
||||||
xdgBinDir: string
|
|
||||||
): Promise<string> {
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const child = cp.spawn(process.execPath, [fixtureApp, url], {
|
const child = cp.spawn(process.execPath, [fixtureApp, url], {
|
||||||
env: {
|
env: {
|
||||||
...process.env,
|
...process.env,
|
||||||
PATH: [xdgBinDir, process.env.PATH].filter(Boolean).join(':'),
|
|
||||||
XDG_DATA_HOME: xdgDataHome,
|
XDG_DATA_HOME: xdgDataHome,
|
||||||
XDG_DATA_DIRS: [xdgDataHome, process.env.XDG_DATA_DIRS].filter(Boolean).join(':'),
|
XDG_DATA_DIRS: xdgDataHome,
|
||||||
XDG_CONFIG_HOME: xdgConfigHome
|
XDG_CONFIG_HOME: xdgConfigHome
|
||||||
},
|
},
|
||||||
stdio: ['ignore', 'pipe', 'pipe']
|
stdio: ['ignore', 'pipe', 'pipe']
|
||||||
@@ -1565,7 +1561,7 @@ describe('app module', () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const parsed = JSON.parse(stdout);
|
const parsed = JSON.parse(stdout);
|
||||||
resolve(parsed.name.trimEnd());
|
resolve(parsed.name);
|
||||||
} catch {
|
} catch {
|
||||||
reject(new Error(`Failed to parse output: ${stdout}\nstderr: ${stderr}`));
|
reject(new Error(`Failed to parse output: ${stdout}\nstderr: ${stderr}`));
|
||||||
}
|
}
|
||||||
@@ -1577,22 +1573,42 @@ describe('app module', () => {
|
|||||||
let xdgDir: string;
|
let xdgDir: string;
|
||||||
let xdgDataHome: string;
|
let xdgDataHome: string;
|
||||||
let xdgConfigHome: string;
|
let xdgConfigHome: string;
|
||||||
let xdgBinDir: string;
|
|
||||||
before(() => {
|
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(() => {
|
after(() => {
|
||||||
fs.rmSync(xdgDir, { recursive: true, force: true });
|
fs.rmSync(xdgDir, { recursive: true, force: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns the desktop file ID for a registered protocol', async () => {
|
it('returns the display name for a registered protocol', async () => {
|
||||||
const name = await spawnWithXdgMock(`${mockScheme}://`, xdgDataHome, xdgConfigHome, xdgBinDir);
|
const name = await spawnWithXdgMock(`${mockScheme}://`, xdgDataHome, xdgConfigHome);
|
||||||
expect(name).to.equal(desktopFileId);
|
expect(name).to.equal(mockDisplayName);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns an empty string for an unregistered protocol', async () => {
|
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('');
|
expect(name).to.equal('');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user