@gjsify/devtools 0.44.0 → 0.46.0
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/README.md +2 -2
- package/lib/esm/css.js +1 -1
- package/lib/esm/devtools-service.js +1 -1
- package/lib/esm/gsettings.js +1 -1
- package/lib/esm/gvariant.js +1 -1
- package/lib/esm/install.js +1 -1
- package/lib/esm/peer-transport.js +1 -1
- package/lib/esm/screenshot.js +1 -1
- package/lib/esm/widget-tree.js +1 -1
- package/lib/types/actions.d.ts +1 -1
- package/lib/types/devtools-service.d.ts +2 -2
- package/lib/types/extension.d.ts +1 -1
- package/lib/types/gvariant.d.ts +1 -1
- package/lib/types/install.d.ts +1 -1
- package/lib/types/screenshot.d.ts +1 -1
- package/lib/types/widget-tree.d.ts +1 -1
- package/package.json +16 -13
package/README.md
CHANGED
|
@@ -9,8 +9,8 @@ It implements the toolkit-neutral [`@gjsify/devtools-protocol`](../devtools-prot
|
|
|
9
9
|
`installDevtools` is a no-op unless `GJSIFY_DEVTOOLS=1` (or `enabled: true`). Call it from `onStartup`/`vfunc_startup`, after the actions and the active window exist.
|
|
10
10
|
|
|
11
11
|
```ts
|
|
12
|
-
import Adw from '
|
|
13
|
-
import GObject from '
|
|
12
|
+
import Adw from 'gi://Adw?version=1';
|
|
13
|
+
import GObject from 'gi://GObject?version=2.0';
|
|
14
14
|
import { installDevtools } from '@gjsify/devtools';
|
|
15
15
|
|
|
16
16
|
export class MyApplication extends Adw.Application {
|
package/lib/esm/css.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import e from"
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import e from"gi://Gdk?version=4.0";import t from"gi://Gtk?version=4.0";const n=new Map;function swapCss(r,i){let a=e.Display.get_default();if(!a)return!1;let o=n.get(r);return o||(o=new t.CssProvider,t.StyleContext.add_provider_for_display(a,o,t.STYLE_PROVIDER_PRIORITY_USER+1),n.set(r,o)),o.load_from_string(i),!0}function removeCss(r){let i=n.get(r);if(!i)return!1;let a=e.Display.get_default();return a&&t.StyleContext.remove_provider_for_display(a,i),n.delete(r),!0}function dumpCss(){return{providers:[...n.keys()]}}export{dumpCss,removeCss,swapCss};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{activateAction as e,changeActionState as t,describeActions as n}from"./actions.js";import{dumpCss as r,swapCss as i}from"./css.js";import{buildDevtoolsIfaceXml as a}from"./devtools-iface.js";import{removeDevtoolsAddressFile as o}from"./peer-transport.js";import{captureWidgetPng as s}from"./screenshot.js";import{dumpGSettings as c}from"./gsettings.js";import{activateWidget as l,dumpTree as u,findWidgetPath as d,getWidgetProperty as f,listToplevels as p,parseWidgetSelector as m,pathOfWidget as h,resolveWidgetPath as g,sendKeyToWidget as _,widgetType as v}from"./widget-tree.js";import y from"
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{activateAction as e,changeActionState as t,describeActions as n}from"./actions.js";import{dumpCss as r,swapCss as i}from"./css.js";import{buildDevtoolsIfaceXml as a}from"./devtools-iface.js";import{removeDevtoolsAddressFile as o}from"./peer-transport.js";import{captureWidgetPng as s}from"./screenshot.js";import{dumpGSettings as c}from"./gsettings.js";import{activateWidget as l,dumpTree as u,findWidgetPath as d,getWidgetProperty as f,listToplevels as p,parseWidgetSelector as m,pathOfWidget as h,resolveWidgetPath as g,sendKeyToWidget as _,widgetType as v}from"./widget-tree.js";import y from"gi://GLib?version=2.0";import b from"gi://Gtk?version=4.0";import{GENERIC_METHODS as x,formatDbusErrorMessage as S}from"@gjsify/devtools-protocol";import C from"gi://Gio?version=2.0";function isActiveWindowScope(e){return!e||e===`window`||e===`active`}function frameDelay(e){return new Promise(t=>{y.timeout_add(y.PRIORITY_DEFAULT,e,()=>(t(),y.SOURCE_REMOVE))})}async function captureWidgetWhenRenderable(e,t=12,n=50){for(let r=0;r<t;r++){let t=s(e);if(t)return t;await frameDelay(n)}return s(e)}var DevtoolsService=class{constructor(e,t){this._app=e,this._options=t,this._exported=new Map,this._peer=null,this._addressFile=null,this._kinds=new Map,this._extensions=t.extend??[];for(let[e,t]of Object.entries(x))this._kinds.set(e,t);for(let e of this._extensions){for(let[t,n]of Object.entries(e.methodKinds))this._kinds.set(t,n);for(let[t,n]of Object.entries(e.handlers)){let e=n;this[t]=(...n)=>(this._guard(t),e(...n))}}}export(e,t){if(this._exported.has(e))return;let n=a(this._extensions.flatMap(e=>e.methodsXml??[])),r=C.DBusExportedObject.wrapJSObject(n,this);r.export(e,t),this._exported.set(e,r)}unexport(e){if(e){this._exported.get(e)?.unexport(),this._exported.delete(e);return}for(let e of this._exported.values())e.unexport();this._exported.clear(),this._peer?.stop(),this._peer=null,this._addressFile&&=(o(this._addressFile),null)}attachPeerServer(e,t){this._peer=e,this._addressFile=t??null}get peerAddress(){return this._peer?.address??null}get addressFile(){return this._addressFile}GetStatus(){let e=this._app.get_active_window(),t={appId:this._app.get_application_id()??`unknown`,instance:this._options.instance??`default`,activeWindow:e?{id:e.get_name()||`window`,title:e.get_title()??``,mapped:e.get_mapped()}:null,toplevelCount:b.Window.get_toplevels().get_n_items(),focusedWidget:null,paused:this._isPaused()};for(let e of this._extensions){let n=e.contributeStatus?.();n&&Object.assign(t,n)}return JSON.stringify(t)}async ScreenshotAsync(e,t){try{let n=typeof e?.[0]==`string`?e[0]:``,r=await this._captureScopePng(n);t.return_value(new y.Variant(`(ay)`,[r]))}catch(e){t.return_dbus_error(`org.gjsify.Devtools.Error.Screenshot`,e instanceof Error?e.message:String(e))}}async _captureScopePng(e){let t=this._resolveRootWidget(e);if(!t){if(isActiveWindowScope(e))return new Uint8Array;throw Error(S(`not-found`,`no widget at '${e}'`))}let n=s(t.widget);if(!n){let e=t.widget.get_root();e instanceof b.Window&&e.present(),n=await captureWidgetWhenRenderable(t.widget)}return n??new Uint8Array}ListActions(){let e={app:n(this._actionGroup(`app`)),win:n(this._actionGroup(`win`))};return JSON.stringify(e)}ActivateAction(t,n,r){this._guard(`ActivateAction`);let i=this._scope(t);e(this._requireGroup(i,n),n,this._parseValue(r))}ChangeActionState(e,n,r){this._guard(`ChangeActionState`);let i=this._scope(e);t(this._requireGroup(i,n),n,this._parseValue(r))}PresentWindow(){this._app.get_active_window()?.present()}ResizeWindow(e,t){this._guard(`ResizeWindow`);let n=this._app.get_active_window();if(!n)throw Error(S(`unavailable`,`no active window to resize`));let r=Math.max(1,Math.round(e)),i=Math.max(1,Math.round(t));return n.is_maximized()&&n.unmaximize(),n.is_fullscreen()&&n.unfullscreen(),n.set_default_size(r,i),[r,i]}ListToplevels(){return JSON.stringify(p())}DumpTree(e,t){let n=this._resolveRootWidget(e);if(!n)throw Error(S(`not-found`,`no widget at '${e||`active window`}'`));return JSON.stringify(u(n.widget,t>0?t:8,n.path))}GetProperty(e,t){let n=this._resolveRootWidget(e);if(!n)throw Error(S(`not-found`,`no widget at '${e}'`));let r=f(n.widget,t);if(r===void 0)throw Error(S(`not-found`,`widget has no property '${t}'`));return JSON.stringify(r)}GetFocused(){let e=this._app.get_active_window(),t=e?e.get_focus():null;return JSON.stringify(t?{path:h(t),name:t.get_name()||null,type:v(t)}:null)}ActivateWidget(e){this._guard(`ActivateWidget`);let t=this._resolveRootWidget(e);if(!t)throw Error(S(`not-found`,`no widget at '${e}'`));return l(t.widget)}FindWidget(e){let t=m(e);if(!t)throw Error(S(`invalid-params`,`empty selector '${e}'`));let n=this._resolveRootWidget(``);return n?d(n.widget,t,n.path)??``:``}SendKey(e,t){this._guard(`SendKey`);let[n,r,i]=b.accelerator_parse(e);if(!n)throw Error(S(`invalid-params`,`cannot parse accelerator '${e}'`));let a;if(a=t?this._resolveRootWidget(t)?.widget??null:this._app.get_active_window()?.get_focus()??null,!a)throw Error(S(`not-found`,`no widget at '${t||`focus`}'`));return _(a,r,i??0)}DumpGSettings(e){return JSON.stringify(c(e))}DumpCss(){return JSON.stringify(r())}SwapCss(e,t){return this._guard(`SwapCss`),i(e,t)}_resolveRootWidget(e){if(isActiveWindowScope(e)){let e=this._app.get_active_window();return e?{widget:e,path:h(e)??`toplevel:0`}:null}let t=g(e);return t?{widget:t,path:e}:null}_isPaused(){return this._options.paused?.()??!1}_guard(e){let t=this._kinds.get(e);if(!t)throw Error(S(`internal`,`unclassified devtools method '${e}'`));if(t===`mutating`&&this._isPaused())throw Error(S(`paused`,`${e} rejected — external control is paused. Read-only methods keep working.`))}_scope(e){return e===`app`?`app`:`win`}_actionGroup(e){if(e===`app`)return this._app;if(this._options.winActionGroup)return this._options.winActionGroup;let t=this._app.get_active_window();return t instanceof b.ApplicationWindow?t:null}_requireGroup(e,t){let n=this._actionGroup(e);if(!n)throw Error(S(`unavailable`,`no '${e}' action group`));if(!n.has_action(t))throw Error(S(`not-found`,`unknown action ${e}.${t}`));return n}_parseValue(e){if(!e||e===`null`)return null;try{return JSON.parse(e)}catch{throw Error(S(`invalid-params`,`value_json is not valid JSON: ${e}`))}}};export{DevtoolsService};
|
package/lib/esm/gsettings.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{formatDbusErrorMessage as e}from"@gjsify/devtools-protocol";import t from"
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{formatDbusErrorMessage as e}from"@gjsify/devtools-protocol";import t from"gi://Gio?version=2.0";function dumpGSettings(n){let r=t.SettingsSchemaSource.get_default()?.lookup(n,!0);if(!r)throw Error(e(`not-found`,`GSettings schema '${n}' is not installed`));let i=new t.Settings({settings_schema:r}),a={};for(let e of r.list_keys())a[e]=i.get_value(e).recursiveUnpack();return a}export{dumpGSettings};
|
package/lib/esm/gvariant.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import e from"
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import e from"gi://GLib?version=2.0";function variantKindFor(e,t){switch(e){case`s`:case`b`:case`i`:case`u`:case`d`:return e}if(typeof t==`string`)return`s`;if(typeof t==`boolean`)return`b`;if(typeof t==`number`)return Number.isInteger(t)?`i`:`d`;throw Error(`Cannot build a GLib.Variant from ${typeof t}`)}function buildVariant(t,n){switch(variantKindFor(t?.dup_string()??null,n)){case`s`:return e.Variant.new_string(String(n));case`b`:return e.Variant.new_boolean(!!n);case`i`:return e.Variant.new_int32(Number(n));case`u`:return e.Variant.new_uint32(Number(n));case`d`:return e.Variant.new_double(Number(n))}}export{buildVariant,variantKindFor};
|
package/lib/esm/install.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{DevtoolsPeerServerError as e,removeDevtoolsAddressFile as t,startDevtoolsPeerServer as n,writeDevtoolsAddressFile as r}from"./peer-transport.js";import{DevtoolsService as i}from"./devtools-service.js";import a from"
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{DevtoolsPeerServerError as e,removeDevtoolsAddressFile as t,startDevtoolsPeerServer as n,writeDevtoolsAddressFile as r}from"./peer-transport.js";import{DevtoolsService as i}from"./devtools-service.js";import a from"gi://GLib?version=2.0";import{DEVTOOLS_ADDRESS_ENV as o,DEVTOOLS_ENABLE_ENV as s,DEVTOOLS_INSTANCE_ENV as c,DEVTOOLS_INTERFACE as l,appIdToObjectPath as u,devtoolsAddressFilePath as d,isDevtoolsEnabledValue as f}from"@gjsify/devtools-protocol";import p from"gi://Gio?version=2.0";const m=`DBUS_SESSION_BUS_ADDRESS`,h=new Set;function envEnabled(){return f(a.getenv(s))}function envValue(e){let t=a.getenv(e);return t&&t!==``?t:null}function sessionBusUsable(){if(!envValue(m))return!1;try{return p.bus_get_sync(p.BusType.SESSION,null),!0}catch{return!1}}function chooseDevtoolsTransport(e){return e.requestedAddress?{kind:`peer`,address:e.requestedAddress,reason:`requested`}:e.hasAppConnection?{kind:`session-bus`}:e.sessionBusUsable?{kind:`unregistered`}:{kind:`peer`,address:null,reason:`no-session-bus`}}function describeMissingConnection(e,t){return e?t?`[gjsify-devtools] the session bus answers but this application is not registered on it yet — call installDevtools() from the GtkApplication "startup" handler (the bus connection and object path exist only after registration).`:`[gjsify-devtools] ${m} is set (${e}) but no bus answers there — using the bus-less peer transport instead. On macOS this is the usual state: Homebrew's dbus listens on launchd, so the advertised address only works while that socket is live.`:`[gjsify-devtools] this machine has no session bus (${m} is unset) — using the bus-less peer transport instead. Point the bridge at the address below, or set ${o} on both the app and \`gjsify debug\` to pin it yourself.`}function installDevtools(e,t={}){if(!(t.enabled??envEnabled()))return null;let n=t.instance??envValue(c)??void 0,r=new i(e,{...t,instance:n});try{return exportDevtools(e,r,t,n)}catch(e){return r.unexport(),console.error(`[gjsify-devtools] devtools stayed OFF, the app is unaffected — ${describeInstallFailure(e)}`),null}}function describeInstallFailure(t){return t instanceof e||t instanceof Error?t.message:String(t)}function exportDevtools(e,i,s,c){let f=e.get_is_registered(),p=f?e.get_dbus_connection():null,g=f?e.get_dbus_object_path():null,_=envValue(m),v=!!(p&&g),y=v||sessionBusUsable(),b=chooseDevtoolsTransport({requestedAddress:s.address??envValue(o),hasAppConnection:v,sessionBusUsable:y}),x=e.get_application_id()??`unknown`,S=`${g??u(x)}/devtools`;if((b.kind===`unregistered`||b.kind===`peer`&&b.reason===`no-session-bus`)&&console.error(describeMissingConnection(_,y)),b.kind===`session-bus`&&p)i.export(p,S),console.log(`[gjsify-devtools] exported ${l} at ${S} (dest ${x})`);else if(b.kind===`peer`){let o=n(i,S,b.address??void 0),s=r(d(a.get_user_runtime_dir(),x,c),o.address);i.attachPeerServer(o,s),console.log(`[gjsify-devtools] exported ${l} at ${S} (peer address ${o.address}${s?`, published to ${s}`:``})`),s&&e.connect(`shutdown`,()=>t(s))}return h.add(i),i}function uninstallDevtools(e){e.unexport(),h.delete(e)}export{chooseDevtoolsTransport,describeMissingConnection,installDevtools,uninstallDevtools};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import e from"
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import e from"gi://GLib?version=2.0";import{DEVTOOLS_ADDRESS_ENV as t}from"@gjsify/devtools-protocol";import n from"gi://Gio?version=2.0";function isWin32(){return e.DIR_SEPARATOR===92}function defaultListenAddress(){return isWin32()?`nonce-tcp:host=127.0.0.1`:`unix:tmpdir=${e.get_tmp_dir()}`}var DevtoolsPeerServerError=class extends Error{constructor(e,t,n,r){super(e),this.address=t,this.reason=n,this.name=`DevtoolsPeerServerError`,this.cause=r}};function isAddressInUse(t){return t instanceof e.Error&&t.matches(n.io_error_quark(),n.IOErrorEnum.ADDRESS_IN_USE)}function unixSocketPath(e){if(!e.startsWith(`unix:`))return null;for(let t of e.slice(5).split(`,`)){let e=t.indexOf(`=`);if(!(e<0||t.slice(0,e)!==`path`))try{return decodeURIComponent(t.slice(e+1))}catch{return null}}return null}function inspectExistingSocket(e){try{if((n.File.new_for_path(e).query_info(`unix::mode`,n.FileQueryInfoFlags.NONE,null).get_attribute_uint32(`unix::mode`)&61440)!=49152)return`not-a-socket`}catch{return`not-a-socket`}let t=new n.SocketClient;t.set_timeout(2);let r;try{r=t.connect(n.UnixSocketAddress.new(e),null)}catch{return`dead`}return r.close(null),`live`}function clearReclaimableSocket(r){let i=unixSocketPath(r);if(!i||!e.file_test(i,e.FileTest.EXISTS))return;let a=inspectExistingSocket(i);if(a===`live`)throw new DevtoolsPeerServerError(`cannot listen on ${r}: another process is already listening there. Stop it, or point ${t} (or options.address) at a different socket — GJSIFY_DEVTOOLS_INSTANCE=<label> lets two devtools-enabled apps run side by side.`,r,`address-in-use`);if(a===`not-a-socket`)throw new DevtoolsPeerServerError(`cannot listen on ${r}: ${i} already exists and is not a socket, so it will NOT be removed. Point ${t} (or options.address) at a free path.`,r,`occupied-by-other-file`);try{n.File.new_for_path(i).delete(null)}catch(e){throw new DevtoolsPeerServerError(`cannot listen on ${r}: ${i} is a socket nothing listens on, but removing it failed (${e}). Delete it by hand, or point ${t} at a free path.`,r,`address-in-use`,e)}console.log(`[gjsify-devtools] reclaimed the stale socket ${i}: nothing was listening on it (an abnormal exit — Ctrl-C, SIGKILL, a crash — leaves the inode behind).`)}function flagsForAddress(e){return e.startsWith(`tcp:`)||e.startsWith(`nonce-tcp:`)?n.DBusServerFlags.NONE:n.DBusServerFlags.AUTHENTICATION_REQUIRE_SAME_USER}function startDevtoolsPeerServer(e,r,i){let a=i&&i!==``?i:defaultListenAddress();clearReclaimableSocket(a);let o;try{o=n.DBusServer.new_sync(a,flagsForAddress(a),n.dbus_generate_guid(),null,null)}catch(e){let n=isAddressInUse(e);throw new DevtoolsPeerServerError(n?`cannot listen on ${a}: the address is already in use (${e}). Stop whatever holds it, or point ${t} (or options.address) at a different address.`:`cannot listen on ${a}: ${e}. Check the address form — \`unix:path=/tmp/app.sock\`, \`unix:tmpdir=/tmp\` or \`nonce-tcp:host=127.0.0.1\`.`,a,n?`address-in-use`:`listen-failed`,e)}let s=new Set;o.connect(`new-connection`,(t,n)=>(s.add(n),n.connect(`closed`,()=>{e.unexport(n),s.delete(n)}),e.export(n,r),!0)),o.start();let c=!1;return{address:o.get_client_address(),objectPath:r,get connectionCount(){return s.size},stop(){if(!c){c=!0,o.stop();for(let t of s)e.unexport(t),!t.is_closed()&&t.close(null,(e,t)=>{try{e.close_finish(t)}catch{}});s.clear()}}}}function writeDevtoolsAddressFile(t,r){try{if(e.mkdir_with_parents(e.path_get_dirname(t),448),!e.file_set_contents(t,`${r}\n`))return null}catch(e){return console.error(`[gjsify-devtools] could not publish the peer address to ${t}: ${e}`),null}try{n.File.new_for_path(t).set_attribute_uint32(`unix::mode`,384,n.FileQueryInfoFlags.NONE,null)}catch(e){console.error(`[gjsify-devtools] could not restrict ${t} to the current user: ${e}`)}return t}function removeDevtoolsAddressFile(e){try{n.File.new_for_path(e).delete(null)}catch{}}export{DevtoolsPeerServerError,removeDevtoolsAddressFile,startDevtoolsPeerServer,writeDevtoolsAddressFile};
|
package/lib/esm/screenshot.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import e from"
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import e from"gi://Gtk?version=4.0";import t from"gi://Graphene?version=1.0";function captureWidgetPng(n){let r=n.get_native()?.get_renderer();if(!r)return null;let i=n.get_width(),a=n.get_height();if(i<=0||a<=0)return null;let o=e.WidgetPaintable.new(n),s=e.Snapshot.new();o.snapshot(s,i,a);let c=s.to_node();if(!c)return null;let l=new t.Rect;l.init(0,0,i,a);let u=r.render_texture(c,l).save_to_png_bytes().get_data();return u?new Uint8Array(u):null}export{captureWidgetPng};
|
package/lib/esm/widget-tree.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import e from"
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import e from"gi://Gtk?version=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){return gtypeName(e)??`GtkWidget`}function gtypeName(e){let t=e;return typeof t?.$typeName==`string`&&t.$typeName.length>0?t.$typeName:t?.constructor?.$gtype?.name??null}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 sendKeyToWidget(e,t,n){let r=e.observe_controllers(),i=!1;for(let e=0;e<r.get_n_items();e++){let a=r.get_item(e);gtypeName(a)===`GtkEventControllerKey`&&(a.emit(`key-pressed`,t,0,n),i=!0)}return i}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 parseWidgetSelector(e){let t=e.indexOf(`:`),n=(t<0?e:e.slice(0,t)).trim(),r=(t<0?``:e.slice(t+1)).trim();return!n&&!r?null:{type:n,cssClass:r}}function findWidgetPath(e,t,n){if(!e.get_visible()||!e.get_mapped())return null;let r=!t.type||widgetType(e)===t.type,i=!t.cssClass||e.get_css_classes().includes(t.cssClass);if(r&&i)return n;let a=e.get_first_child(),o=0;for(;a;){let e=findWidgetPath(a,t,`${n}/child:${o}`);if(e)return e;a=a.get_next_sibling(),o++}return null}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,findWidgetPath,getWidgetProperty,listToplevels,parseWidgetPath,parseWidgetSelector,pathOfWidget,resolveWidgetPath,sendKeyToWidget,widgetType};
|
package/lib/types/actions.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type Gio from '
|
|
1
|
+
import type Gio from 'gi://Gio?version=2.0';
|
|
2
2
|
import type { ActionDescriptor } from '@gjsify/devtools-protocol';
|
|
3
3
|
/** Describe every action in a group (name, enabled, parameter/state types), sorted by name. */
|
|
4
4
|
export declare function describeActions(group: Gio.ActionGroup | null): ActionDescriptor[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import Gio from '
|
|
2
|
-
import Gtk from '
|
|
1
|
+
import Gio from 'gi://Gio?version=2.0';
|
|
2
|
+
import Gtk from 'gi://Gtk?version=4.0';
|
|
3
3
|
import type { InstallDevtoolsOptions } from './extension.js';
|
|
4
4
|
import { type DevtoolsPeerServer } from './peer-transport.js';
|
|
5
5
|
/**
|
package/lib/types/extension.d.ts
CHANGED
package/lib/types/gvariant.d.ts
CHANGED
package/lib/types/install.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type Gtk from '
|
|
1
|
+
import type Gtk from 'gi://Gtk?version=4.0';
|
|
2
2
|
import { DevtoolsService } from './devtools-service.js';
|
|
3
3
|
import type { InstallDevtoolsOptions } from './extension.js';
|
|
4
4
|
/** Which transport `installDevtools` uses. See {@link chooseDevtoolsTransport}. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/devtools",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.46.0",
|
|
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",
|
|
@@ -22,8 +22,10 @@
|
|
|
22
22
|
"build:types": "gjsify tsc",
|
|
23
23
|
"build:test": "gjsify run build:test:gjs",
|
|
24
24
|
"build:test:gjs": "gjsify build src/test.mts --app gjs --outfile test.gjs.mjs",
|
|
25
|
+
"build:test:node": "gjsify build src/test.mts --app node --outfile dist/test.node.mjs",
|
|
25
26
|
"test": "gjsify run build:gjsify && gjsify run build:test && gjsify run test:gjs",
|
|
26
|
-
"test:gjs": "gjsify run test.gjs.mjs"
|
|
27
|
+
"test:gjs": "gjsify run test.gjs.mjs",
|
|
28
|
+
"test:gjs-on-node": "gjsify run build:gjsify && gjsify run build:test:node && node dist/test.node.mjs"
|
|
27
29
|
},
|
|
28
30
|
"keywords": [
|
|
29
31
|
"gjs",
|
|
@@ -35,19 +37,20 @@
|
|
|
35
37
|
"mcp"
|
|
36
38
|
],
|
|
37
39
|
"dependencies": {
|
|
38
|
-
"@girs/adw-1": "
|
|
39
|
-
"@girs/gdk-4.0": "
|
|
40
|
-
"@girs/gio-2.0": "
|
|
41
|
-
"@girs/gjs": "
|
|
42
|
-
"@girs/glib-2.0": "
|
|
43
|
-
"@girs/gobject-2.0": "
|
|
44
|
-
"@girs/graphene-1.0": "
|
|
45
|
-
"@girs/gtk-4.0": "
|
|
46
|
-
"@gjsify/devtools-protocol": "^0.
|
|
40
|
+
"@girs/adw-1": "4.6.0",
|
|
41
|
+
"@girs/gdk-4.0": "4.6.0",
|
|
42
|
+
"@girs/gio-2.0": "4.6.0",
|
|
43
|
+
"@girs/gjs": "4.6.0",
|
|
44
|
+
"@girs/glib-2.0": "4.6.0",
|
|
45
|
+
"@girs/gobject-2.0": "4.6.0",
|
|
46
|
+
"@girs/graphene-1.0": "4.6.0",
|
|
47
|
+
"@girs/gtk-4.0": "4.6.0",
|
|
48
|
+
"@gjsify/devtools-protocol": "^0.46.0"
|
|
47
49
|
},
|
|
48
50
|
"devDependencies": {
|
|
49
|
-
"@gjsify/cli": "^0.
|
|
50
|
-
"@gjsify/
|
|
51
|
+
"@gjsify/cli": "^0.46.0",
|
|
52
|
+
"@gjsify/node-gi": "file:../../node-gi/node-gi",
|
|
53
|
+
"@gjsify/unit": "^0.46.0",
|
|
51
54
|
"@types/node": "^25.9.2",
|
|
52
55
|
"typescript": "^6.0.3"
|
|
53
56
|
},
|