@gjsify/devtools 0.22.0 → 0.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/esm/widget-tree.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import e from"@girs/gtk-4.0";function parseWidgetPath(e){let t=e.split(`/`).filter(e=>e.length>0);if(t.length===0)return null;let n=t[0].match(/^toplevel:(\d+)$/);if(!n)return null;let r=[];for(let e of t.slice(1)){let t=e.match(/^child:(\d+)$/);if(!t)return null;r.push(Number(t[1]))}return{toplevel:Number(n[1]),children:r}}function buildWidgetPath(e,t){return[`toplevel:${e}`,...t.map(e=>`child:${e}`)].join(`/`)}function widgetType(e){let t=e;return typeof t.$typeName==`string`&&t.$typeName.length>0?t.$typeName:t.constructor?.$gtype?.name??`GtkWidget`}function activateWidget(e){let t=e;
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import e from"@girs/gtk-4.0";function parseWidgetPath(e){let t=e.split(`/`).filter(e=>e.length>0);if(t.length===0)return null;let n=t[0].match(/^toplevel:(\d+)$/);if(!n)return null;let r=[];for(let e of t.slice(1)){let t=e.match(/^child:(\d+)$/);if(!t)return null;r.push(Number(t[1]))}return{toplevel:Number(n[1]),children:r}}function buildWidgetPath(e,t){return[`toplevel:${e}`,...t.map(e=>`child:${e}`)].join(`/`)}function widgetType(e){let t=e;return typeof t.$typeName==`string`&&t.$typeName.length>0?t.$typeName:t.constructor?.$gtype?.name??`GtkWidget`}function activateWidget(e){let t=e;if(typeof t.activate==`function`&&t.activate()===!0)return!0;let n=typeof t.get_parent==`function`?t.get_parent():null;if(n&&widgetType(n)===`GtkListBox`){let t=n,r=!1;return typeof t.select_row==`function`&&(t.select_row(e),r=!0),typeof t.emit==`function`&&(t.emit(`row-activated`,e),r=!0),r}return!1}function nthChild(e,t){let n=e.get_first_child(),r=0;for(;n&&r<t;)n=n.get_next_sibling(),r++;return r===t?n:null}function listToplevels(){let t=e.Window.get_toplevels(),n=t.get_n_items(),r=[];for(let e=0;e<n;e++){let n=t.get_item(e);n&&r.push({path:`toplevel:${e}`,type:widgetType(n),title:n.get_title?.()??null,mapped:n.get_mapped(),focused:n.is_active??!1})}return r}function resolveWidgetPath(t){let n=parseWidgetPath(t);if(!n)return null;let r=e.Window.get_toplevels().get_item(n.toplevel);if(!r)return null;for(let e of n.children)if(r=nthChild(r,e),!r)return null;return r}function dumpTree(e,t,n){let r={path:n,type:widgetType(e),name:e.get_name()||null,cssClasses:e.get_css_classes(),mapped:e.get_mapped(),visible:e.get_visible(),children:[]};if(t<=0)return r;let i=e.get_first_child(),a=0;for(;i;)r.children.push(dumpTree(i,t-1,`${n}/child:${a}`)),i=i.get_next_sibling(),a++;return r}function jsonSafe(e){let t=typeof e;return e==null||t===`string`||t===`number`||t===`boolean`?e??null:`[${t}]`}function getWidgetProperty(e,t){let n=e,r=t.replace(/-/g,`_`),i=t.replace(/[-_]([a-z])/g,(e,t)=>t.toUpperCase());for(let e of[t,r,i])if(e in n)return jsonSafe(n[e])}function childIndex(e,t){let n=e.get_first_child(),r=0;for(;n;){if(n===t)return r;n=n.get_next_sibling(),r++}return-1}function pathOfWidget(t){let n=[],r=t,i=r.get_parent();for(;i;){let e=childIndex(i,r);if(e<0)return null;n.unshift(e),r=i,i=r.get_parent()}let a=e.Window.get_toplevels(),o=a.get_n_items();for(let e=0;e<o;e++)if(a.get_item(e)===r)return buildWidgetPath(e,n);return null}export{activateWidget,buildWidgetPath,dumpTree,getWidgetProperty,listToplevels,parseWidgetPath,pathOfWidget,resolveWidgetPath,widgetType};
|
|
@@ -42,9 +42,12 @@ export declare class DevtoolsService {
|
|
|
42
42
|
GetProperty(path: string, prop: string): string;
|
|
43
43
|
/** `GetFocused() -> s` — JSON {path,name,type} of the focused widget, or null. */
|
|
44
44
|
GetFocused(): string;
|
|
45
|
-
/** `ActivateWidget(path) -> b` — activate the widget at `path
|
|
46
|
-
*
|
|
47
|
-
*
|
|
45
|
+
/** `ActivateWidget(path) -> b` — activate the widget at `path`: its own
|
|
46
|
+
* default activation (Button→clicked, Entry→activate, Toggle) or, for a
|
|
47
|
+
* GtkListBoxRow/AdwActionRow, a click on the owning GtkListBox (select the
|
|
48
|
+
* row + row-activated) so nav / preference rows drive. The click-drive
|
|
49
|
+
* counterpart of DumpTree/GetProperty. Throws if the path resolves to no
|
|
50
|
+
* live widget; returns whether it activated. */
|
|
48
51
|
ActivateWidget(path: string): boolean;
|
|
49
52
|
/** `DumpGSettings(schema_id) -> s` — JSON of a schema's keys + values. */
|
|
50
53
|
DumpGSettings(schemaId: string): string;
|
|
@@ -26,15 +26,28 @@ export declare function buildWidgetPath(toplevel: number, children: readonly num
|
|
|
26
26
|
*/
|
|
27
27
|
export declare function widgetType(widget: Gtk.Widget): string;
|
|
28
28
|
/**
|
|
29
|
-
* Activate a widget —
|
|
30
|
-
*
|
|
31
|
-
* `activated`, an entry emits `activate`, …). This is how external tooling
|
|
32
|
-
* click-drives a running GUI: resolve a widget by path, then activate it.
|
|
29
|
+
* Activate a widget — how external tooling click-drives a running GUI: resolve a
|
|
30
|
+
* widget by path, then activate it. Two paths, tried in order:
|
|
33
31
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
32
|
+
* 1. **`gtk_widget_activate()`** — the widget's own default-activation signal
|
|
33
|
+
* (a `Gtk.Button` emits `clicked`, a `Gtk.Entry` emits `activate`, a
|
|
34
|
+
* `Gtk.ToggleButton` toggles). Returns true when it fires.
|
|
35
|
+
* 2. **Row fallback** — a `GtkListBoxRow` / `AdwActionRow` is NOT activatable
|
|
36
|
+
* via `gtk_widget_activate()` (returns false): a row's interaction routes
|
|
37
|
+
* through the owning `GtkListBox`, not the row's own signal. So driving a
|
|
38
|
+
* sidebar nav row or a preference row over path #1 alone silently no-ops.
|
|
39
|
+
* When the widget's parent is a `GtkListBox`, reproduce what a real click on
|
|
40
|
+
* a row does — it both SELECTS the row (`select_row` → the `row-selected`
|
|
41
|
+
* signal selection-driven nav shells listen to) AND ACTIVATES it
|
|
42
|
+
* (`row-activated`, for activatable rows). Doing both drives either wiring
|
|
43
|
+
* (a GtkListBox only ever parents rows, so the parent-type check is enough
|
|
44
|
+
* to know the widget is the row to pass). `select_row` is a no-op under
|
|
45
|
+
* selection-mode `none`, so it is always safe to call.
|
|
46
|
+
*
|
|
47
|
+
* Returns true if either path activated the widget, false if neither applies
|
|
48
|
+
* (e.g. a plain container). Duck-typed on the accessors it reads for the same
|
|
49
|
+
* cross-runtime reason as {@link widgetType} (GJS vs node-gi both expose them,
|
|
50
|
+
* so the spec can feed plain mock shapes).
|
|
38
51
|
*/
|
|
39
52
|
export declare function activateWidget(widget: Gtk.Widget): boolean;
|
|
40
53
|
/** Enumerate live toplevel windows as `{ path, type, title, mapped, focused }`. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/devtools",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.1",
|
|
4
4
|
"description": "In-app DBus devtools control plane for GJS/GTK apps — inspect, screenshot, and drive a running app over org.gjsify.Devtools (gdbus or the MCP bridge)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "lib/esm/index.js",
|
|
@@ -43,11 +43,11 @@
|
|
|
43
43
|
"@girs/gobject-2.0": "^4.1.0",
|
|
44
44
|
"@girs/graphene-1.0": "^4.1.0",
|
|
45
45
|
"@girs/gtk-4.0": "^4.1.0",
|
|
46
|
-
"@gjsify/devtools-protocol": "^0.
|
|
46
|
+
"@gjsify/devtools-protocol": "^0.24.1"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@gjsify/cli": "^0.
|
|
50
|
-
"@gjsify/unit": "^0.
|
|
49
|
+
"@gjsify/cli": "^0.24.1",
|
|
50
|
+
"@gjsify/unit": "^0.24.1",
|
|
51
51
|
"@types/node": "^25.9.2",
|
|
52
52
|
"typescript": "^6.0.3"
|
|
53
53
|
},
|