Skip to content

Commit b7909f1

Browse files
3v1n0mtwebster
authored andcommitted
overrides/Gio: Add wrappers for platform-specific Gio functions
GLib will not expose anymore platform specific functions in Gio namespace as it used to do when GI Repository 1.0 was used, in order to keep retro-compatibility in gjs applications, generate wrappers for Gio platform-specific definitions that we used to provide inside the main Gio object, but warn the users of these APIs that they should migrate to GioUnix or GioWin32 instead.
1 parent 96dcd38 commit b7909f1

2 files changed

Lines changed: 123 additions & 0 deletions

File tree

installed-tests/js/testGio.js

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44

55
const {GLib, Gio, GObject} = imports.gi;
66

7+
let GioUnix;
8+
try {
9+
GioUnix = imports.gi.GioUnix;
10+
} catch {}
11+
712
const Foo = GObject.registerClass({
813
Properties: {
914
boolval: GObject.ParamSpec.boolean('boolval', '', '',
@@ -390,6 +395,89 @@ describe('Gio.FileEnumerator overrides', function () {
390395
});
391396
});
392397

398+
describe('Gio.DesktopAppInfo fallback', function () {
399+
let writerFunc;
400+
const requiredVersion =
401+
GLib.MAJOR_VERSION > 2 ||
402+
(GLib.MAJOR_VERSION === 2 && GLib.MINOR_VERSION >= 86);
403+
let keyFile;
404+
const desktopFileContent = `[Desktop Entry]
405+
Version=1.0
406+
Type=Application
407+
Name=Some Application
408+
Exec=${GLib.find_program_in_path('sh')}
409+
`;
410+
beforeAll(function () {
411+
// Set up log writer for tests to override
412+
writerFunc = jasmine.createSpy('parsed writer func');
413+
const writerFuncWrapper = jasmine.createSpy('log writer func', (level, fields) => {
414+
const decoder = new TextDecoder('utf-8');
415+
const domain = decoder.decode(fields?.GLIB_DOMAIN);
416+
const message = `${decoder.decode(fields?.MESSAGE)}`;
417+
if (level < GLib.LogLevelFlags.LEVEL_WARNING) {
418+
level |= GLib.LogLevelFlags.FLAG_RECURSION;
419+
GLib.log_default_handler(domain, level, `${message}\n`, null);
420+
}
421+
writerFunc(domain, level, message);
422+
return GLib.LogWriterOutput.HANDLED;
423+
});
424+
writerFuncWrapper.and.callThrough();
425+
GLib.log_set_writer_func(writerFuncWrapper);
426+
427+
keyFile = new GLib.KeyFile();
428+
keyFile.load_from_data(desktopFileContent, desktopFileContent.length,
429+
GLib.KeyFileFlags.NONE);
430+
});
431+
432+
afterAll(function () {
433+
GLib.log_set_writer_default();
434+
});
435+
436+
beforeEach(function () {
437+
if (!GioUnix)
438+
pending('Not supported platform');
439+
440+
writerFunc.calls.reset();
441+
});
442+
443+
it('can be created using GioUnix', function () {
444+
expect(GioUnix.DesktopAppInfo.new_from_keyfile(keyFile)).not.toBeNull();
445+
expect(writerFunc).not.toHaveBeenCalled();
446+
});
447+
448+
it('can be created using Gio wrapper', function () {
449+
expect(Gio.DesktopAppInfo.new_from_keyfile(keyFile)).not.toBeNull();
450+
expect(writerFunc).toHaveBeenCalledWith('Cjs-Console',
451+
GLib.LogLevelFlags.LEVEL_WARNING,
452+
'Gio.DesktopAppInfo is deprecated, please use GioUnix.DesktopAppInfo instead');
453+
454+
writerFunc.calls.reset();
455+
expect(Gio.DesktopAppInfo.new_from_keyfile(keyFile)).not.toBeNull();
456+
expect(writerFunc).not.toHaveBeenCalled();
457+
});
458+
459+
describe('provides platform-independent functions', function () {
460+
[Gio, GioUnix].forEach(ns => it(`when created from ${ns.__name__}`, function () {
461+
if (!requiredVersion)
462+
pending('Installed Gio is not new enough for this test');
463+
464+
const appInfo = ns.DesktopAppInfo.new_from_keyfile(keyFile);
465+
expect(appInfo.get_name()).toBe('Some Application');
466+
}));
467+
});
468+
469+
describe('provides unix-only functions', function () {
470+
[Gio, GioUnix].forEach(ns => it(`when created from ${ns.__name__}`, function () {
471+
if (!requiredVersion)
472+
pending('Installed Gio is not new enough for this test');
473+
474+
const appInfo = ns.DesktopAppInfo.new_from_keyfile(keyFile);
475+
expect(appInfo.has_key('Name')).toBeTrue();
476+
expect(appInfo.get_string('Name')).toBe('Some Application');
477+
}));
478+
});
479+
});
480+
393481
describe('Non-introspectable file attribute overrides', function () {
394482
let numExpectedWarnings, file, info;
395483
const flags = [Gio.FileQueryInfoFlags.NONE, null];

modules/core/overrides/Gio.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,9 +479,44 @@ function _warnNotIntrospectable(funcName, replacement) {
479479

480480
function _init() {
481481
Gio = this;
482+
let GioPlatform = {};
482483

483484
Gio.Application.prototype.runAsync = GLib.MainLoop.prototype.runAsync;
484485

486+
// Redefine Gio functions with platform-specific implementations to be
487+
// backward compatible with gi-repository 1.0, however when possible we
488+
// notify a deprecation warning, to ensure that the surrounding code is
489+
// updated.
490+
try {
491+
GioPlatform = imports.gi.GioUnix;
492+
} catch {
493+
try {
494+
GioPlatform = imports.gi.GioWin32;
495+
} catch {}
496+
}
497+
498+
Object.entries(Object.getOwnPropertyDescriptors(GioPlatform)).forEach(([prop, desc]) => {
499+
if (Object.hasOwn(Gio, prop)) {
500+
console.debug(`Gio already contains property ${prop}`);
501+
Gio[prop] = GioPlatform[prop];
502+
return;
503+
}
504+
505+
const newDesc = {
506+
enumerable: true,
507+
configurable: false,
508+
get() {
509+
if (!newDesc._deprecationWarningDone) {
510+
console.warn(`Gio.${prop} is deprecated, please use ` +
511+
`${GioPlatform.__name__}.${prop} instead`);
512+
newDesc._deprecationWarningDone = true;
513+
}
514+
return desc.get?.() ?? desc.value;
515+
},
516+
};
517+
Object.defineProperty(Gio, prop, newDesc);
518+
});
519+
485520
Gio.DBus = {
486521
// Namespace some functions
487522
get: Gio.bus_get,

0 commit comments

Comments
 (0)