Skip to content

Commit

Permalink
Merge pull request #219 from gjsify/add_action_entries
Browse files Browse the repository at this point in the history
fix(gio): Correct types for overridden `ActionMap.add_action_entries` method
  • Loading branch information
JumpLink authored Nov 11, 2024
2 parents ffa9e9a + ed9ede4 commit f703cc1
Show file tree
Hide file tree
Showing 6 changed files with 218 additions and 2 deletions.
93 changes: 93 additions & 0 deletions examples/gio-2-action-entries/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';

export class ExampleApplication extends Gio.Application {
static {
GObject.registerClass({
GTypeName: 'ExampleApplication'
}, this);
}

constructor() {
super({
application_id: 'org.example.ActionEntries',
flags: Gio.ApplicationFlags.FLAGS_NONE,
});
this.initActions();
}

private initActions() {
// Define multiple actions at once using ActionEntryObj type
const actions: Gio.ActionEntryObj[] = [
// Simple action without state or parameter
{
name: 'quit',
activate: () => {
console.log('Quitting application...');
this.quit();
},
},

// Action with parameter
{
name: 'greet',
parameter_type: 's', // GVariant type string for string parameter
activate: (_action, parameter) => {
if (parameter) {
const name = parameter.get_string()[0];
console.log(`Hello, ${name}!`);
}
},
},

// Stateful toggle action
{
name: 'dark-mode',
state: 'false', // Initial state as string
change_state: (_action, value) => {
if (value) {
const isDark = value.get_boolean();
console.log(`Dark mode ${isDark ? 'enabled' : 'disabled'}`);
// Get the action and set its state
const action = this.lookup_action('dark-mode') as Gio.SimpleAction;
action.set_state(value);
}
},
},

// Action with optional parameter
{
name: 'save',
parameter_type: '(sb)', // Tuple of string and boolean
activate: (_action, parameter) => {
if (parameter) {
const [filename, backup] = parameter.deep_unpack() as [string, boolean];
console.log(`Saving ${filename} (backup: ${backup})`);
} else {
console.log('Quick save');
}
},
},
];

// Add all actions at once
this.add_action_entries(actions);
}

vfunc_activate() {
// Test the actions
this.activate_action('greet', GLib.Variant.new_string('World'));

// For stateful actions, we should use change-state instead of activate
const darkModeAction = this.lookup_action('dark-mode') as Gio.SimpleAction;
darkModeAction.change_state(GLib.Variant.new_boolean(true));

this.activate_action('save', GLib.Variant.new('(sb)', ['document.txt', true]));
this.activate_action('quit', null);
}
}

// Run the application
const app = new ExampleApplication();
app.run([]);
24 changes: 24 additions & 0 deletions examples/gio-2-action-entries/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "@ts-for-gir-example/gio-2-action-entries",
"version": "4.0.0-beta.19",
"description": "Example demonstrating Gio.ActionEntry",
"type": "module",
"private": true,
"scripts": {
"build:app": "tsc",
"build": "yarn build:app",
"start:app": "gjs -m dist/main.js",
"start": "yarn build && yarn start:app",
"validate": "yarn validate:types",
"validate:types": "tsc --noEmit",
"clear": "rm -rf dist"
},
"devDependencies": {
"typescript": "^5.6.3"
},
"dependencies": {
"@girs/gio-2.0": "workspace:^",
"@girs/gjs": "workspace:^",
"@girs/glib-2.0": "workspace:^"
}
}
18 changes: 18 additions & 0 deletions examples/gio-2-action-entries/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"compilerOptions": {
"lib": ["ESNext"],
"types": ["@girs/gjs", "@girs/gjs/dom", "@girs/gio-2.0", "@girs/glib-2.0"],
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"noImplicitThis": true,
"alwaysStrict": true,
"outDir": "./dist"
},
"files": [
"main.ts"
]
}
3 changes: 2 additions & 1 deletion examples/gio-2-async/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
},
"dependencies": {
"@girs/gio-2.0": "workspace:^",
"@girs/gjs": "workspace:^"
"@girs/gjs": "workspace:^",
"@girs/glib-2.0": "workspace:^"
}
}
70 changes: 69 additions & 1 deletion packages/lib/src/injections/gio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ import {
Uint8ArrayType,
BooleanType,
TypeIdentifier,
ThisType
ThisType,
IntrospectedAlias
} from "../gir.js";
import { GirDirection } from "@gi.ts/parser";
import { IntrospectedField, JSField } from "../gir/property.js";
Expand Down Expand Up @@ -630,5 +631,72 @@ export default {
})
);
}

// Add ActionEntry type
const SimpleAction = namespace.assertClass("SimpleAction");
const GLib = namespace.assertInstalledImport("GLib");
const Variant = GLib.assertClass("Variant");

/**
* Type for action entries used in {@link ActionMap.add_action_entries}
*
* This type definition matches the GJS override implementation at:
* @see https://gitlab.gnome.org/GNOME/gjs/-/blob/master/modules/core/overrides/Gio.js#L827
*
* The add_action_entries method is overridden by GJS to provide a more convenient API
* for adding multiple actions at once. This type definition provides proper TypeScript
* typing for that override.
*
* @see https://gitlab.gnome.org/GNOME/gjs/-/issues/407 for the original discussion
* @see https://github.com/gjsify/ts-for-gir/issues/153 for the related issue in ts-for-gir
*/
const ActionEntryObj = new IntrospectedAlias({
name: "ActionEntryObj",
namespace,
type: new NativeType(`{
/** The name of the action */
name: string;
/** The type of the parameter that must match the parameter_type specified in the entry */
parameter_type?: string;
/** The initial state of the action */
state?: string;
/** The callback to connect to the "activate" signal of the action */
activate?: (_source: ${SimpleAction.name}, parameter: ${Variant.namespace.namespace}.${Variant.name} | null) => void;
/** The callback to connect to the "change-state" signal of the action */
change_state?: (_source: ${SimpleAction.name}, value: ${Variant.namespace.namespace}.${Variant.name} | null) => void;
}`),
doc: "Type for action entries used in the overridden {@link ActionMap.add_action_entries}"
});

namespace.members.set("ActionEntryObj", ActionEntryObj);

// Create new method with updated signature
const ActionMap = namespace.assertClass("ActionMap") as IntrospectedInterface;
const newMethod = new IntrospectedClassFunction({
name: "add_action_entries",
parent: ActionMap,
parameters: [
new IntrospectedFunctionParameter({
name: "entries",
type: new ArrayType(new TypeIdentifier("ActionEntryObj", "Gio")),
direction: GirDirection.In,
doc: "Array of action entries to add"
}),
],
return_type: VoidType,
doc: "A convenience function for creating multiple simple actions. \nSee Gio.ActionEntryObj for the structure of the action entry."
});

// Find and replace the existing method
const existingMethodIndex = ActionMap.members.findIndex(
member => member.name === "add_action_entries"
);

if (existingMethodIndex !== -1) {
ActionMap.members[existingMethodIndex] = newMethod;
} else {
console.warn("Could not find existing add_action_entries method to override");
ActionMap.members.push(newMethod);
}
}
};
12 changes: 12 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -12723,12 +12723,24 @@ __metadata:
languageName: unknown
linkType: soft

"@ts-for-gir-example/gio-2-action-entries@workspace:examples/gio-2-action-entries":
version: 0.0.0-use.local
resolution: "@ts-for-gir-example/gio-2-action-entries@workspace:examples/gio-2-action-entries"
dependencies:
"@girs/gio-2.0": "workspace:^"
"@girs/gjs": "workspace:^"
"@girs/glib-2.0": "workspace:^"
typescript: "npm:^5.6.3"
languageName: unknown
linkType: soft

"@ts-for-gir-example/gio-2-async@workspace:examples/gio-2-async":
version: 0.0.0-use.local
resolution: "@ts-for-gir-example/gio-2-async@workspace:examples/gio-2-async"
dependencies:
"@girs/gio-2.0": "workspace:^"
"@girs/gjs": "workspace:^"
"@girs/glib-2.0": "workspace:^"
typescript: "npm:^5.6.3"
languageName: unknown
linkType: soft
Expand Down

0 comments on commit f703cc1

Please sign in to comment.