@gtkx/testing 1.6.0 → 2.0.0-beta.10

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.
Files changed (132) hide show
  1. package/README.md +47 -44
  2. package/dist/accessible-native.d.ts +1 -1
  3. package/dist/accessible-native.d.ts.map +1 -1
  4. package/dist/accessible-native.js +29 -8
  5. package/dist/accessible-native.js.map +1 -1
  6. package/dist/build-queries.d.ts +9 -9
  7. package/dist/build-queries.d.ts.map +1 -1
  8. package/dist/build-queries.js +2 -1
  9. package/dist/build-queries.js.map +1 -1
  10. package/dist/config.d.ts.map +1 -1
  11. package/dist/config.js +1 -3
  12. package/dist/config.js.map +1 -1
  13. package/dist/fire-event.d.ts +3 -3
  14. package/dist/fire-event.d.ts.map +1 -1
  15. package/dist/fire-event.js +14 -4
  16. package/dist/fire-event.js.map +1 -1
  17. package/dist/matchers.d.ts +52 -56
  18. package/dist/matchers.d.ts.map +1 -1
  19. package/dist/matchers.js +4 -16
  20. package/dist/matchers.js.map +1 -1
  21. package/dist/queries.d.ts +37 -133
  22. package/dist/queries.d.ts.map +1 -1
  23. package/dist/queries.js +48 -136
  24. package/dist/queries.js.map +1 -1
  25. package/dist/query-helpers.d.ts +2 -2
  26. package/dist/query-helpers.d.ts.map +1 -1
  27. package/dist/query-helpers.js +10 -3
  28. package/dist/query-helpers.js.map +1 -1
  29. package/dist/render.d.ts.map +1 -1
  30. package/dist/render.js +4 -0
  31. package/dist/render.js.map +1 -1
  32. package/dist/role-helpers.d.ts +1 -1
  33. package/dist/role-helpers.d.ts.map +1 -1
  34. package/dist/role-helpers.js +2 -1
  35. package/dist/role-helpers.js.map +1 -1
  36. package/dist/screenshot.d.ts +1 -1
  37. package/dist/screenshot.d.ts.map +1 -1
  38. package/dist/screenshot.js +26 -8
  39. package/dist/screenshot.js.map +1 -1
  40. package/dist/suggestions.d.ts +1 -1
  41. package/dist/suggestions.d.ts.map +1 -1
  42. package/dist/suggestions.js +3 -1
  43. package/dist/suggestions.js.map +1 -1
  44. package/dist/traversal.d.ts +4 -4
  45. package/dist/traversal.d.ts.map +1 -1
  46. package/dist/traversal.js +25 -7
  47. package/dist/traversal.js.map +1 -1
  48. package/dist/types.d.ts +10 -10
  49. package/dist/types.d.ts.map +1 -1
  50. package/dist/types.js.map +1 -1
  51. package/dist/user-event/adjustment.d.ts +2 -14
  52. package/dist/user-event/adjustment.d.ts.map +1 -1
  53. package/dist/user-event/adjustment.js +2 -14
  54. package/dist/user-event/adjustment.js.map +1 -1
  55. package/dist/user-event/click.d.ts +20 -45
  56. package/dist/user-event/click.d.ts.map +1 -1
  57. package/dist/user-event/click.js +31 -50
  58. package/dist/user-event/click.js.map +1 -1
  59. package/dist/user-event/controller.d.ts +5 -5
  60. package/dist/user-event/controller.d.ts.map +1 -1
  61. package/dist/user-event/controller.js +5 -2
  62. package/dist/user-event/controller.js.map +1 -1
  63. package/dist/user-event/gesture.d.ts +9 -43
  64. package/dist/user-event/gesture.d.ts.map +1 -1
  65. package/dist/user-event/gesture.js +9 -43
  66. package/dist/user-event/gesture.js.map +1 -1
  67. package/dist/user-event/index.d.ts +38 -107
  68. package/dist/user-event/index.d.ts.map +1 -1
  69. package/dist/user-event/index.js +29 -30
  70. package/dist/user-event/index.js.map +1 -1
  71. package/dist/user-event/keyboard.d.ts +1 -1
  72. package/dist/user-event/keyboard.d.ts.map +1 -1
  73. package/dist/user-event/keyboard.js +24 -3
  74. package/dist/user-event/keyboard.js.map +1 -1
  75. package/dist/user-event/list-row-click.d.ts +1 -1
  76. package/dist/user-event/list-row-click.d.ts.map +1 -1
  77. package/dist/user-event/list-row-click.js +2 -1
  78. package/dist/user-event/list-row-click.js.map +1 -1
  79. package/dist/user-event/pointer.d.ts.map +1 -1
  80. package/dist/user-event/pointer.js +9 -11
  81. package/dist/user-event/pointer.js.map +1 -1
  82. package/dist/user-event/selection.d.ts +4 -20
  83. package/dist/user-event/selection.d.ts.map +1 -1
  84. package/dist/user-event/selection.js +11 -23
  85. package/dist/user-event/selection.js.map +1 -1
  86. package/dist/user-event/text.d.ts +5 -34
  87. package/dist/user-event/text.d.ts.map +1 -1
  88. package/dist/user-event/text.js +5 -34
  89. package/dist/user-event/text.js.map +1 -1
  90. package/dist/wait-for.d.ts +2 -2
  91. package/dist/wait-for.d.ts.map +1 -1
  92. package/dist/wait-for.js +6 -4
  93. package/dist/wait-for.js.map +1 -1
  94. package/dist/widget-accessible-properties.d.ts +4 -3
  95. package/dist/widget-accessible-properties.d.ts.map +1 -1
  96. package/dist/widget-accessible-properties.js +38 -51
  97. package/dist/widget-accessible-properties.js.map +1 -1
  98. package/dist/widget-getters.d.ts +7 -9
  99. package/dist/widget-getters.d.ts.map +1 -1
  100. package/dist/widget-getters.js.map +1 -1
  101. package/dist/widget-target.d.ts +4 -0
  102. package/dist/widget-target.d.ts.map +1 -0
  103. package/dist/widget-target.js +9 -0
  104. package/dist/widget-target.js.map +1 -0
  105. package/package.json +17 -10
  106. package/src/accessible-native.ts +45 -9
  107. package/src/build-queries.ts +60 -30
  108. package/src/config.ts +1 -3
  109. package/src/fire-event.ts +32 -8
  110. package/src/matchers.ts +63 -85
  111. package/src/queries.ts +94 -156
  112. package/src/query-helpers.ts +17 -9
  113. package/src/render.tsx +7 -2
  114. package/src/role-helpers.ts +3 -1
  115. package/src/screenshot.ts +49 -8
  116. package/src/suggestions.ts +3 -1
  117. package/src/traversal.ts +35 -11
  118. package/src/types.ts +14 -10
  119. package/src/user-event/adjustment.ts +2 -14
  120. package/src/user-event/click.ts +40 -58
  121. package/src/user-event/controller.ts +8 -5
  122. package/src/user-event/gesture.ts +9 -43
  123. package/src/user-event/index.ts +149 -132
  124. package/src/user-event/keyboard.ts +33 -4
  125. package/src/user-event/list-row-click.ts +2 -2
  126. package/src/user-event/pointer.ts +11 -15
  127. package/src/user-event/selection.ts +15 -25
  128. package/src/user-event/text.ts +5 -34
  129. package/src/wait-for.ts +9 -6
  130. package/src/widget-accessible-properties.ts +61 -69
  131. package/src/widget-getters.ts +11 -13
  132. package/src/widget-target.ts +11 -0
@@ -1 +1 @@
1
- {"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.tsx"],"names":[],"mappings":"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","sourcesContent":["import type { RootElement } from \"@gtkx/react\";\nimport * as Gtk from \"@gtkx/gi/gtk\";\nimport {\n createReconcilerRoot,\n isRootElement,\n type ReconcilerRoot,\n setReconcilerErrorHandler,\n settleAccessible,\n} from \"@gtkx/react/internal\";\nimport { type ErrorInfo, type ReactNode, StrictMode } from \"react\";\nimport type { RenderResult } from \"./bound-queries.js\";\nimport type { QueryMap, RenderOptions, ScreenshotOptions } from \"./types.js\";\nimport { runInAct, runWithActEnvironment } from \"./act.js\";\nimport { addToCleanupQueue, runCleanup } from \"./cleanup-registry.js\";\nimport { getConfig } from \"./config.js\";\nimport { scheduleWhenWindowReady } from \"./frame-sync.js\";\nimport { createHarnessWindow, presentHarnessWindow } from \"./harness-window.js\";\nimport { logWidget, type PrettyWidgetOptions } from \"./pretty-widget.js\";\nimport { logRoles } from \"./role-helpers.js\";\nimport { clearScreen, setScreen } from \"./screen.js\";\nimport { captureScreen } from \"./screenshot.js\";\nimport { type Container, roots, TOPLEVELS } from \"./traversal.js\";\nimport { resetClipboard } from \"./user-event/index.js\";\nimport { findPresentedWindowFailure, findRenderedWindowFailure, mappedToplevels } from \"./window-state.js\";\nimport { within } from \"./within.js\";\n\n/** A mounted render tracked so cleanup can unmount it. */\ntype ActiveRender = {\n /** Root that rerenders drive and that cleanup tears the tree down through. */\n root: ReconcilerRoot;\n /** Harness window created for the render, null when it renders into a container the caller supplied. */\n window: Gtk.Window | null;\n};\n\ntype ResolvedContainer = {\n containerInfo: Gtk.Widget | RootElement;\n window: Gtk.Window | null;\n};\n\ntype ReconcilerErrorState = {\n lastError: Error | null;\n isHandlerInstalled: boolean;\n};\n\ntype WindowFailureReporter = (window: Gtk.Window) => string | null;\ntype SettleAction = \"render\" | \"rerender\";\n\nconst reconcilerErrors: ReconcilerErrorState = { lastError: null, isHandlerInstalled: false };\nconst activeRenders: Set<ActiveRender> = new Set();\n\nconst settleWindow = async (\n window: Gtk.Window | null,\n findFailure: WindowFailureReporter,\n action: SettleAction,\n): Promise<void> => {\n const timeout = getConfig().windowActivationTimeout;\n\n await runWithActEnvironment(\n false,\n () =>\n new Promise<void>((resolve) => {\n scheduleWhenWindowReady(window, (target) => findFailure(target) === null, timeout, resolve);\n }),\n );\n\n settleAccessible();\n const failure = window === null ? null : findFailure(window);\n\n if (failure !== null) {\n throw new Error(\n `${action} timed out after ${String(timeout)}ms waiting for the window it rendered into: ${failure}. ` +\n \"Platform state such as focus is only readable once that window is allocated and active.\",\n );\n }\n};\n\nconst update = async (element: ReactNode, root: ReconcilerRoot): Promise<void> => {\n await runInAct(() => {\n root.update(element);\n });\n\n if (reconcilerErrors.lastError) {\n const captured = reconcilerErrors.lastError;\n reconcilerErrors.lastError = null;\n throw captured;\n }\n};\n\nconst disposeActiveRender = async (active: ActiveRender): Promise<void> => {\n if (!activeRenders.delete(active)) {\n return;\n }\n\n await active.root.unmount(async (root) => {\n await update(null, root);\n active.window?.destroy();\n });\n};\n\nconst disposeAllActiveRenders = async (): Promise<void> => {\n for (const active of activeRenders) {\n await disposeActiveRender(active);\n }\n};\n\nconst handleError = (error: unknown): void => {\n reconcilerErrors.lastError = error instanceof Error ? error : new Error(String(error));\n};\n\nconst installErrorHandler = (): void => {\n if (reconcilerErrors.isHandlerInstalled) {\n return;\n }\n\n setReconcilerErrorHandler(handleError);\n reconcilerErrors.isHandlerInstalled = true;\n};\n\nconst resolveContainer = (container: RenderOptions[\"container\"]): ResolvedContainer => {\n if (isRootElement(container)) {\n return { containerInfo: container, window: null };\n }\n\n if (container instanceof Gtk.Widget) {\n return { containerInfo: container, window: null };\n }\n\n const window = createHarnessWindow();\n window.setDecorated(false);\n\n return { containerInfo: window, window };\n};\n\nconst firstToplevelWidget = (baseElement: Container): Gtk.Widget => {\n if (baseElement instanceof Gtk.Widget) {\n return baseElement;\n }\n\n const [first] = roots(baseElement);\n\n if (first) {\n return first;\n }\n\n throw new Error(\"render() produced no widgets: ensure the element renders visible content\");\n};\n\nconst resolveResultContainer = (\n resolved: ResolvedContainer,\n container: RenderOptions[\"container\"],\n baseElement: Container,\n): Gtk.Widget => {\n if (resolved.window) {\n return resolved.window;\n }\n\n if (container instanceof Gtk.Widget) {\n return container;\n }\n\n return firstToplevelWidget(baseElement);\n};\n\nconst realizedWindow = (root: Gtk.Root | null): Gtk.Window | null =>\n root instanceof Gtk.Window && root.getFrameClock() !== null ? root : null;\n\nconst settleTarget = (resolved: ResolvedContainer, container: RenderOptions[\"container\"]): Gtk.Window | null => {\n if (resolved.window) {\n return realizedWindow(resolved.window);\n }\n\n if (container instanceof Gtk.Widget) {\n return realizedWindow(container.getRoot());\n }\n\n return realizedWindow(mappedToplevels()[0] ?? null);\n};\n\nconst settleRender = async (\n resolved: ResolvedContainer,\n container: RenderOptions[\"container\"],\n action: SettleAction,\n): Promise<void> => {\n const isPresentedNow = action === \"render\" && resolved.window !== null;\n const findFailure = isPresentedNow ? findPresentedWindowFailure : findRenderedWindowFailure;\n await settleWindow(settleTarget(resolved, container), findFailure, action);\n};\n\nconst renderErrorHandlers = <Q extends QueryMap>(options: RenderOptions<Q> | undefined) => ({\n onUncaughtError: handleError,\n onCaughtError: (error: unknown, errorInfo: ErrorInfo): void => {\n handleError(error);\n options?.onCaughtError?.(error, errorInfo);\n },\n onRecoverableError: (error: unknown, errorInfo: ErrorInfo): void => {\n options?.onRecoverableError?.(error, errorInfo);\n },\n});\n\nconst applyEnableAnimations = (areAnimationsEnabled: boolean): void => {\n const settings = Gtk.Settings.getDefault();\n\n if (settings) {\n settings.gtkEnableAnimations = areAnimationsEnabled;\n }\n};\n\n/**\n * Renders a React element into a GTK4 widget tree and returns queries\n * scoped to it along with controls for rerendering and unmounting. When no\n * container is supplied, a harness window is created and presented, and the editable it hands the\n * focus to keeps its text unselected, with its caret at the end. The returned promise settles once\n * the window the tree is shown in has been laid out and activation has arrived, so platform state\n * such as focus is already readable when it resolves. A presented harness window is waited on until\n * it is itself active; a window the caller or the tree owns is waited on until the application holds\n * activation, since only a present can claim it. Rendering into a container that is not shown waits\n * for nothing, and a window that never becomes readable within `windowActivationTimeout` throws an\n * error naming the condition that failed rather than resolving with unreadable platform state. A\n * tree mounted into a container that sits outside every toplevel, or inside a window that is not\n * visible, is out of reach of a pointer and a keyboard, so every `userEvent` helper aimed at it\n * rejects after `actionabilityTimeout` naming that condition, and `fireEvent` drives it instead.\n *\n * @param element The React element to render.\n * @param options Optional container, wrapper, custom queries, and other render settings.\n * @returns A render result with bound queries, debug helpers, and lifecycle controls.\n * @throws When the window the tree is shown in is not laid out and activated in time.\n */\nconst render = async <Q extends QueryMap = Record<never, never>>(\n element: ReactNode,\n options?: RenderOptions<Q>,\n): Promise<RenderResult<Q>> => {\n installErrorHandler();\n applyEnableAnimations(options?.areAnimationsEnabled === true);\n const baseElement: Container = options?.baseElement ?? TOPLEVELS;\n const Wrapper = options?.wrapper;\n const resolved = resolveContainer(options?.container);\n\n const root = createReconcilerRoot({\n containerInfo: resolved.containerInfo,\n ...renderErrorHandlers(options),\n });\n\n const active: ActiveRender = { root, window: resolved.window };\n activeRenders.add(active);\n addToCleanupQueue(disposeAllActiveRenders);\n addToCleanupQueue(clearScreen);\n addToCleanupQueue(resetClipboard);\n\n const wrap = (node: ReactNode): ReactNode => {\n const wrapped = Wrapper ? <Wrapper>{node}</Wrapper> : node;\n\n return options?.isReactStrictMode ? <StrictMode>{wrapped}</StrictMode> : wrapped;\n };\n\n await update(wrap(element), root);\n presentHarnessWindow(resolved.window);\n await settleRender(resolved, options?.container, \"render\");\n const container = resolveResultContainer(resolved, options?.container, baseElement);\n\n const result: RenderResult<Q> = {\n ...within(baseElement, options?.queries),\n container,\n baseElement,\n unmount: async () => {\n await disposeActiveRender(active);\n },\n rerender: async (newElement: ReactNode) => {\n await update(wrap(newElement), root);\n await settleRender(resolved, options?.container, \"rerender\");\n },\n debug: (element: Container | Container[] = baseElement, debugOptions?: PrettyWidgetOptions) => {\n logWidget(element, debugOptions);\n },\n logRoles: () => {\n logRoles(baseElement);\n },\n screenshot: (screenshotOptions?: ScreenshotOptions) => captureScreen(screenshotOptions),\n };\n\n setScreen(result);\n\n return result;\n};\n\n/**\n * Unmounts every active render and runs all registered cleanup callbacks,\n * resetting the screen and clipboard. Called automatically after each test.\n */\nconst cleanup = async (): Promise<void> => {\n await runCleanup();\n};\n\nexport { render, cleanup };\n"]}
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.tsx"],"names":[],"mappings":"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","sourcesContent":["import type { CaughtErrorInfo, RootElement } from \"@gtkx/react\";\nimport * as Gtk from \"@gtkx/gi/gtk\";\nimport {\n createReconcilerRoot,\n isRootElement,\n type ReconcilerRoot,\n setReconcilerErrorHandler,\n settleAccessible,\n} from \"@gtkx/react/internal\";\nimport { type ErrorInfo, type ReactNode, StrictMode } from \"react\";\nimport type { RenderResult } from \"./bound-queries.js\";\nimport type { QueryMap, RenderOptions, ScreenshotOptions } from \"./types.js\";\nimport { runInAct, runWithActEnvironment } from \"./act.js\";\nimport { addToCleanupQueue, runCleanup } from \"./cleanup-registry.js\";\nimport { getConfig } from \"./config.js\";\nimport { scheduleWhenWindowReady } from \"./frame-sync.js\";\nimport { createHarnessWindow, presentHarnessWindow } from \"./harness-window.js\";\nimport { logWidget, type PrettyWidgetOptions } from \"./pretty-widget.js\";\nimport { logRoles } from \"./role-helpers.js\";\nimport { clearScreen, setScreen } from \"./screen.js\";\nimport { captureScreen } from \"./screenshot.js\";\nimport { type Container, roots, TOPLEVELS } from \"./traversal.js\";\nimport { resetClipboard } from \"./user-event/index.js\";\nimport { requireWidget } from \"./widget-target.js\";\nimport { findPresentedWindowFailure, findRenderedWindowFailure, mappedToplevels } from \"./window-state.js\";\nimport { within } from \"./within.js\";\n\n/** A mounted render tracked so cleanup can unmount it. */\ntype ActiveRender = {\n /** Root that rerenders drive and that cleanup tears the tree down through. */\n root: ReconcilerRoot;\n /** Harness window created for the render, null when it renders into a container the caller supplied. */\n window: Gtk.Window | null;\n};\n\ntype ResolvedContainer = {\n containerInfo: Gtk.Widget | RootElement;\n window: Gtk.Window | null;\n};\n\ntype ReconcilerErrorState = {\n lastError: Error | null;\n isHandlerInstalled: boolean;\n};\n\ntype WindowFailureReporter = (window: Gtk.Window) => string | null;\ntype SettleAction = \"render\" | \"rerender\";\n\nconst reconcilerErrors: ReconcilerErrorState = { lastError: null, isHandlerInstalled: false };\nconst activeRenders: Set<ActiveRender> = new Set();\n\nconst settleWindow = async (\n window: Gtk.Window | null,\n findFailure: WindowFailureReporter,\n action: SettleAction,\n): Promise<void> => {\n const timeout = getConfig().windowActivationTimeout;\n\n await runWithActEnvironment(\n false,\n () =>\n new Promise<void>((resolve) => {\n scheduleWhenWindowReady(window, (target) => findFailure(target) === null, timeout, resolve);\n }),\n );\n\n settleAccessible();\n const failure = window === null ? null : findFailure(window);\n\n if (failure !== null) {\n throw new Error(\n `${action} timed out after ${String(timeout)}ms waiting for the window it rendered into: ${failure}. ` +\n \"Platform state such as focus is only readable once that window is allocated and active.\",\n );\n }\n};\n\nconst update = async (element: ReactNode, root: ReconcilerRoot): Promise<void> => {\n await runInAct(() => {\n root.update(element);\n });\n\n if (reconcilerErrors.lastError) {\n const captured = reconcilerErrors.lastError;\n reconcilerErrors.lastError = null;\n throw captured;\n }\n};\n\nconst disposeActiveRender = async (active: ActiveRender): Promise<void> => {\n if (!activeRenders.delete(active)) {\n return;\n }\n\n await active.root.unmount(async (root) => {\n await update(null, root);\n active.window?.destroy();\n });\n};\n\nconst disposeAllActiveRenders = async (): Promise<void> => {\n for (const active of activeRenders) {\n await disposeActiveRender(active);\n }\n};\n\nconst handleError = (error: unknown): void => {\n reconcilerErrors.lastError = error instanceof Error ? error : new Error(String(error));\n};\n\nconst installErrorHandler = (): void => {\n if (reconcilerErrors.isHandlerInstalled) {\n return;\n }\n\n setReconcilerErrorHandler(handleError);\n reconcilerErrors.isHandlerInstalled = true;\n};\n\nconst resolveContainer = (container: RenderOptions[\"container\"]): ResolvedContainer => {\n if (isRootElement(container)) {\n return { containerInfo: container, window: null };\n }\n\n if (container instanceof Gtk.Widget) {\n return { containerInfo: container, window: null };\n }\n\n if (container !== undefined) {\n requireWidget(container);\n }\n\n const window = createHarnessWindow();\n window.setDecorated(false);\n\n return { containerInfo: window, window };\n};\n\nconst firstToplevelWidget = (baseElement: Container): Gtk.Widget => {\n if (baseElement instanceof Gtk.Widget) {\n return baseElement;\n }\n\n const [first] = roots(baseElement);\n\n if (first) {\n return first;\n }\n\n throw new Error(\"render() produced no widgets: ensure the element renders visible content\");\n};\n\nconst resolveResultContainer = (\n resolved: ResolvedContainer,\n container: RenderOptions[\"container\"],\n baseElement: Container,\n): Gtk.Widget => {\n if (resolved.window) {\n return resolved.window;\n }\n\n if (container instanceof Gtk.Widget) {\n return container;\n }\n\n return firstToplevelWidget(baseElement);\n};\n\nconst realizedWindow = (root: Gtk.Root | null): Gtk.Window | null =>\n root instanceof Gtk.Window && root.getFrameClock() !== null ? root : null;\n\nconst settleTarget = (resolved: ResolvedContainer, container: RenderOptions[\"container\"]): Gtk.Window | null => {\n if (resolved.window) {\n return realizedWindow(resolved.window);\n }\n\n if (container instanceof Gtk.Widget) {\n return realizedWindow(container.getRoot());\n }\n\n return realizedWindow(mappedToplevels()[0] ?? null);\n};\n\nconst settleRender = async (\n resolved: ResolvedContainer,\n container: RenderOptions[\"container\"],\n action: SettleAction,\n): Promise<void> => {\n const isPresentedNow = action === \"render\" && resolved.window !== null;\n const findFailure = isPresentedNow ? findPresentedWindowFailure : findRenderedWindowFailure;\n await settleWindow(settleTarget(resolved, container), findFailure, action);\n};\n\nconst renderErrorHandlers = <Q extends QueryMap>(options: RenderOptions<Q> | undefined) => ({\n onUncaughtError: handleError,\n onCaughtError: (error: unknown, errorInfo: CaughtErrorInfo): void => {\n handleError(error);\n options?.onCaughtError?.(error, errorInfo);\n },\n onRecoverableError: (error: unknown, errorInfo: ErrorInfo): void => {\n options?.onRecoverableError?.(error, errorInfo);\n },\n});\n\nconst applyEnableAnimations = (areAnimationsEnabled: boolean): void => {\n const settings = Gtk.Settings.getDefault();\n\n if (settings) {\n settings.gtkEnableAnimations = areAnimationsEnabled;\n }\n};\n\n/**\n * Renders a React element into a GTK4 widget tree and returns queries\n * scoped to it along with controls for rerendering and unmounting. When no\n * container is supplied, a harness window is created and presented, and the editable it hands the\n * focus to keeps its text unselected, with its caret at the end. The returned promise settles once\n * the window the tree is shown in has been laid out and activation has arrived, so platform state\n * such as focus is already readable when it resolves. A presented harness window is waited on until\n * it is itself active; a window the caller or the tree owns is waited on until the application holds\n * activation, since only a present can claim it. Rendering into a container that is not shown waits\n * for nothing, and a window that never becomes readable within `windowActivationTimeout` throws an\n * error naming the condition that failed rather than resolving with unreadable platform state. A\n * tree mounted into a container that sits outside every toplevel, or inside a window that is not\n * visible, is out of reach of a pointer and a keyboard, so every `userEvent` helper aimed at it\n * rejects after `actionabilityTimeout` naming that condition, and `fireEvent` drives it instead.\n *\n * @param element The React element to render.\n * @param options Optional container, wrapper, custom queries, and other render settings.\n * @returns A render result with bound queries, debug helpers, and lifecycle controls.\n * @throws When the window the tree is shown in is not laid out and activated in time.\n */\nconst render = async <Q extends QueryMap = Record<never, never>>(\n element: ReactNode,\n options?: RenderOptions<Q>,\n): Promise<RenderResult<Q>> => {\n installErrorHandler();\n applyEnableAnimations(options?.areAnimationsEnabled === true);\n const baseElement: Container = options?.baseElement ?? TOPLEVELS;\n const Wrapper = options?.wrapper;\n const resolved = resolveContainer(options?.container);\n\n const root = createReconcilerRoot({\n containerInfo: resolved.containerInfo,\n ...renderErrorHandlers(options),\n });\n\n const active: ActiveRender = { root, window: resolved.window };\n activeRenders.add(active);\n addToCleanupQueue(disposeAllActiveRenders);\n addToCleanupQueue(clearScreen);\n addToCleanupQueue(resetClipboard);\n\n const wrap = (node: ReactNode): ReactNode => {\n const wrapped = Wrapper ? <Wrapper>{node}</Wrapper> : node;\n\n return options?.isReactStrictMode ? <StrictMode>{wrapped}</StrictMode> : wrapped;\n };\n\n await update(wrap(element), root);\n presentHarnessWindow(resolved.window);\n await settleRender(resolved, options?.container, \"render\");\n const container = resolveResultContainer(resolved, options?.container, baseElement);\n\n const result: RenderResult<Q> = {\n ...within(baseElement, options?.queries),\n container,\n baseElement,\n unmount: async () => {\n await disposeActiveRender(active);\n },\n rerender: async (newElement: ReactNode) => {\n await update(wrap(newElement), root);\n await settleRender(resolved, options?.container, \"rerender\");\n },\n debug: (element: Container | Container[] = baseElement, debugOptions?: PrettyWidgetOptions) => {\n logWidget(element, debugOptions);\n },\n logRoles: () => {\n logRoles(baseElement);\n },\n screenshot: (screenshotOptions?: ScreenshotOptions) => captureScreen(screenshotOptions),\n };\n\n setScreen(result);\n\n return result;\n};\n\n/**\n * Unmounts every active render and runs all registered cleanup callbacks,\n * resetting the screen and clipboard. Called automatically after each test.\n */\nconst cleanup = async (): Promise<void> => {\n await runCleanup();\n};\n\nexport { render, cleanup };\n"]}
@@ -37,6 +37,6 @@ declare const logRoles: (container: Container) => void;
37
37
  *
38
38
  * @param widget The widget to read the level from.
39
39
  */
40
- declare const computeHeadingLevel: (widget: Gtk.Widget) => number | undefined;
40
+ declare const computeHeadingLevel: (widget: Gtk.Accessible) => number | undefined;
41
41
  export { computeHeadingLevel, formatRole, formatRoleList, getRoles, prettyRoles, logRoles };
42
42
  //# sourceMappingURL=role-helpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"role-helpers.d.ts","sourceRoot":"","sources":["../src/role-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AAEpC,OAAO,EAAE,KAAK,SAAS,EAAY,MAAM,gBAAgB,CAAC;AAc1D;;;;;GAKG;AACH,QAAA,MAAM,UAAU,GAAI,MAAM,GAAG,CAAC,cAAc,KAAG,MAQ9C,CAAC;AAEF,QAAA,MAAM,cAAc,GAAI,OAAO,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,KAAG,MAe7D,CAAC;AAEF;;;;;;GAMG;AACH,QAAA,MAAM,QAAQ,GAAI,WAAW,SAAS,KAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAehE,CAAC;AAUF;;;;;;GAMG;AACH,QAAA,MAAM,WAAW,GAAI,WAAW,SAAS,KAAG,MAqB3C,CAAC;AAEF;;;;;GAKG;AACH,QAAA,MAAM,QAAQ,GAAI,WAAW,SAAS,KAAG,IAExC,CAAC;AAEF;;;;;GAKG;AACH,QAAA,MAAM,mBAAmB,GAAI,QAAQ,GAAG,CAAC,MAAM,KAAG,MAAM,GAAG,SAAgD,CAAC;AAE5G,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,cAAc,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC"}
1
+ {"version":3,"file":"role-helpers.d.ts","sourceRoot":"","sources":["../src/role-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AAEpC,OAAO,EAAE,KAAK,SAAS,EAAY,MAAM,gBAAgB,CAAC;AAe1D;;;;;GAKG;AACH,QAAA,MAAM,UAAU,GAAI,MAAM,GAAG,CAAC,cAAc,KAAG,MAQ9C,CAAC;AAEF,QAAA,MAAM,cAAc,GAAI,OAAO,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,KAAG,MAe7D,CAAC;AAEF;;;;;;GAMG;AACH,QAAA,MAAM,QAAQ,GAAI,WAAW,SAAS,KAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAehE,CAAC;AAUF;;;;;;GAMG;AACH,QAAA,MAAM,WAAW,GAAI,WAAW,SAAS,KAAG,MAqB3C,CAAC;AAEF;;;;;GAKG;AACH,QAAA,MAAM,QAAQ,GAAI,WAAW,SAAS,KAAG,IAExC,CAAC;AAEF;;;;;GAKG;AACH,QAAA,MAAM,mBAAmB,GAAI,QAAQ,GAAG,CAAC,UAAU,KAAG,MAAM,GAAG,SACT,CAAC;AAEvD,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,cAAc,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC"}
@@ -3,6 +3,7 @@ import { sortStringsBy } from "@gtkx/utils";
3
3
  import { traverse } from "./traversal.js";
4
4
  import { getWidgetAccessibleName, getWidgetLevel } from "./widget-accessible-properties.js";
5
5
  import { getTypeTag } from "./widget-getters.js";
6
+ import { requireWidget } from "./widget-target.js";
6
7
  const ROLE_NAMES_BY_VALUE = enumNamesByValue(Gtk.AccessibleRole);
7
8
  function enumNamesByValue(enumObject) {
8
9
  return new Map(Object.entries(enumObject)
@@ -99,6 +100,6 @@ const logRoles = (container) => {
99
100
  *
100
101
  * @param widget The widget to read the level from.
101
102
  */
102
- const computeHeadingLevel = (widget) => getWidgetLevel(widget) ?? undefined;
103
+ const computeHeadingLevel = (widget) => getWidgetLevel(requireWidget(widget)) ?? undefined;
103
104
  export { computeHeadingLevel, formatRole, formatRoleList, getRoles, prettyRoles, logRoles };
104
105
  //# sourceMappingURL=role-helpers.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"role-helpers.js","sourceRoot":"","sources":["../src/role-helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import * as Gtk from \"@gtkx/gi/gtk\";\nimport { sortStringsBy } from \"@gtkx/utils\";\nimport { type Container, traverse } from \"./traversal.js\";\nimport { getWidgetAccessibleName, getWidgetLevel } from \"./widget-accessible-properties.js\";\nimport { getTypeTag } from \"./widget-getters.js\";\n\nconst ROLE_NAMES_BY_VALUE = enumNamesByValue(Gtk.AccessibleRole);\n\nfunction enumNamesByValue(enumObject: Record<string, string | number>): Map<number, string> {\n return new Map<number, string>(\n Object.entries(enumObject)\n .filter((entry): entry is [string, number] => typeof entry[1] === \"number\")\n .map(([name, value]) => [value, name]),\n );\n}\n\n/**\n * Converts an accessible role enum value into its lowercase name, falling back\n * to the numeric value when the role is unknown.\n *\n * @param role The accessible role to format.\n */\nconst formatRole = (role: Gtk.AccessibleRole): string => {\n const name = ROLE_NAMES_BY_VALUE.get(role);\n\n if (!name) {\n return String(role);\n }\n\n return name.toLowerCase();\n};\n\nconst formatRoleList = (roles: Iterable<Gtk.AccessibleRole>): string => {\n const names = [...roles].map((role) => formatRole(role).toUpperCase());\n\n if (names.length <= 1) {\n return names.join(\"\");\n }\n\n if (names.length === 2) {\n return names.join(\" or \");\n }\n\n const head = names.slice(0, -1);\n const last = names.at(-1) ?? \"\";\n\n return `${head.join(\", \")}, or ${last}`;\n};\n\n/**\n * Groups every mapped widget in a container's tree by its accessible role name. Widgets that are not\n * mapped are left out.\n *\n * @param container The scope to traverse.\n * @returns A map from role name to the mapped widgets that have that role.\n */\nconst getRoles = (container: Container): Map<string, Gtk.Widget[]> => {\n const roles: Map<string, Gtk.Widget[]> = new Map();\n\n for (const widget of traverse(container)) {\n const roleName = formatRole(widget.getAccessibleRole());\n const existing = roles.get(roleName);\n\n if (existing) {\n existing.push(widget);\n } else {\n roles.set(roleName, [widget]);\n }\n }\n\n return roles;\n};\n\nconst formatWidgetPreview = (widget: Gtk.Widget, name: string | null): string => {\n const tagName = getTypeTag(widget);\n const roleAttr = formatRole(widget.getAccessibleRole());\n const nameDisplay = name ? `Name \"${name}\"` : 'Name \"\"';\n\n return `${nameDisplay}: <${tagName} role=\"${roleAttr}\">${name ?? \"\"}</${tagName}>`;\n};\n\n/**\n * Formats the accessible roles in a container's tree as a readable string,\n * listing each role together with its widgets and their accessible names.\n * Widgets that are not mapped are left out.\n *\n * @param container The scope to inspect.\n */\nconst prettyRoles = (container: Container): string => {\n const roles = getRoles(container);\n\n if (roles.size === 0) {\n return \"No accessible roles found in the widget tree.\";\n }\n\n const lines: string[] = [];\n const sortedRoles = sortStringsBy([...roles], ([roleName]) => roleName);\n\n for (const [roleName, widgets] of sortedRoles) {\n lines.push(`${roleName}:`);\n\n for (const widget of widgets) {\n lines.push(` ${formatWidgetPreview(widget, getWidgetAccessibleName(widget))}`);\n }\n\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\").trimEnd();\n};\n\n/**\n * Prints the accessible roles in a container's tree to the console using\n * {@link prettyRoles}.\n *\n * @param container The scope to inspect.\n */\nconst logRoles = (container: Container): void => {\n console.log(prettyRoles(container));\n};\n\n/**\n * Returns the heading or hierarchy level GTK reports for a widget, or undefined when it declares\n * none.\n *\n * @param widget The widget to read the level from.\n */\nconst computeHeadingLevel = (widget: Gtk.Widget): number | undefined => getWidgetLevel(widget) ?? undefined;\n\nexport { computeHeadingLevel, formatRole, formatRoleList, getRoles, prettyRoles, logRoles };\n"]}
1
+ {"version":3,"file":"role-helpers.js","sourceRoot":"","sources":["../src/role-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAkB,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,uBAAuB,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAC5F,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,MAAM,mBAAmB,GAAG,gBAAgB,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;AAEjE,SAAS,gBAAgB,CAAC,UAA2C;IACjE,OAAO,IAAI,GAAG,CACV,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC;SACrB,MAAM,CAAC,CAAC,KAAK,EAA6B,EAAE,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC;SAC1E,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAC7C,CAAC;AACN,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,GAAG,CAAC,IAAwB,EAAU,EAAE;IACpD,MAAM,IAAI,GAAG,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAE3C,IAAI,CAAC,IAAI,EAAE,CAAC;QACR,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IAED,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC;AAC9B,CAAC,CAAC;AAEF,MAAM,cAAc,GAAG,CAAC,KAAmC,EAAU,EAAE;IACnE,MAAM,KAAK,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IAEvE,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QACpB,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1B,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IAED,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAChC,MAAM,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAEhC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;AAC5C,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,QAAQ,GAAG,CAAC,SAAoB,EAA6B,EAAE;IACjE,MAAM,KAAK,GAA8B,IAAI,GAAG,EAAE,CAAC;IAEnD,KAAK,MAAM,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACvC,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAC;QACxD,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAErC,IAAI,QAAQ,EAAE,CAAC;YACX,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1B,CAAC;aAAM,CAAC;YACJ,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;QAClC,CAAC;IACL,CAAC;IAED,OAAO,KAAK,CAAC;AACjB,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAAC,MAAkB,EAAE,IAAmB,EAAU,EAAE;IAC5E,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IACnC,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACxD,MAAM,WAAW,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;IAExD,OAAO,GAAG,WAAW,MAAM,OAAO,UAAU,QAAQ,KAAK,IAAI,IAAI,EAAE,KAAK,OAAO,GAAG,CAAC;AACvF,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,GAAG,CAAC,SAAoB,EAAU,EAAE;IACjD,MAAM,KAAK,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;IAElC,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACnB,OAAO,+CAA+C,CAAC;IAC3D,CAAC;IAED,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,WAAW,GAAG,aAAa,CAAC,CAAC,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC;IAExE,KAAK,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,WAAW,EAAE,CAAC;QAC5C,KAAK,CAAC,IAAI,CAAC,GAAG,QAAQ,GAAG,CAAC,CAAC;QAE3B,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC3B,KAAK,CAAC,IAAI,CAAC,KAAK,mBAAmB,CAAC,MAAM,EAAE,uBAAuB,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;QACpF,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACnB,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;AACtC,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,QAAQ,GAAG,CAAC,SAAoB,EAAQ,EAAE;IAC5C,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC;AACxC,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,mBAAmB,GAAG,CAAC,MAAsB,EAAsB,EAAE,CACvE,cAAc,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,IAAI,SAAS,CAAC;AAEvD,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,cAAc,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC","sourcesContent":["import * as Gtk from \"@gtkx/gi/gtk\";\nimport { sortStringsBy } from \"@gtkx/utils\";\nimport { type Container, traverse } from \"./traversal.js\";\nimport { getWidgetAccessibleName, getWidgetLevel } from \"./widget-accessible-properties.js\";\nimport { getTypeTag } from \"./widget-getters.js\";\nimport { requireWidget } from \"./widget-target.js\";\n\nconst ROLE_NAMES_BY_VALUE = enumNamesByValue(Gtk.AccessibleRole);\n\nfunction enumNamesByValue(enumObject: Record<string, string | number>): Map<number, string> {\n return new Map<number, string>(\n Object.entries(enumObject)\n .filter((entry): entry is [string, number] => typeof entry[1] === \"number\")\n .map(([name, value]) => [value, name]),\n );\n}\n\n/**\n * Converts an accessible role enum value into its lowercase name, falling back\n * to the numeric value when the role is unknown.\n *\n * @param role The accessible role to format.\n */\nconst formatRole = (role: Gtk.AccessibleRole): string => {\n const name = ROLE_NAMES_BY_VALUE.get(role);\n\n if (!name) {\n return String(role);\n }\n\n return name.toLowerCase();\n};\n\nconst formatRoleList = (roles: Iterable<Gtk.AccessibleRole>): string => {\n const names = [...roles].map((role) => formatRole(role).toUpperCase());\n\n if (names.length <= 1) {\n return names.join(\"\");\n }\n\n if (names.length === 2) {\n return names.join(\" or \");\n }\n\n const head = names.slice(0, -1);\n const last = names.at(-1) ?? \"\";\n\n return `${head.join(\", \")}, or ${last}`;\n};\n\n/**\n * Groups every mapped widget in a container's tree by its accessible role name. Widgets that are not\n * mapped are left out.\n *\n * @param container The scope to traverse.\n * @returns A map from role name to the mapped widgets that have that role.\n */\nconst getRoles = (container: Container): Map<string, Gtk.Widget[]> => {\n const roles: Map<string, Gtk.Widget[]> = new Map();\n\n for (const widget of traverse(container)) {\n const roleName = formatRole(widget.getAccessibleRole());\n const existing = roles.get(roleName);\n\n if (existing) {\n existing.push(widget);\n } else {\n roles.set(roleName, [widget]);\n }\n }\n\n return roles;\n};\n\nconst formatWidgetPreview = (widget: Gtk.Widget, name: string | null): string => {\n const tagName = getTypeTag(widget);\n const roleAttr = formatRole(widget.getAccessibleRole());\n const nameDisplay = name ? `Name \"${name}\"` : 'Name \"\"';\n\n return `${nameDisplay}: <${tagName} role=\"${roleAttr}\">${name ?? \"\"}</${tagName}>`;\n};\n\n/**\n * Formats the accessible roles in a container's tree as a readable string,\n * listing each role together with its widgets and their accessible names.\n * Widgets that are not mapped are left out.\n *\n * @param container The scope to inspect.\n */\nconst prettyRoles = (container: Container): string => {\n const roles = getRoles(container);\n\n if (roles.size === 0) {\n return \"No accessible roles found in the widget tree.\";\n }\n\n const lines: string[] = [];\n const sortedRoles = sortStringsBy([...roles], ([roleName]) => roleName);\n\n for (const [roleName, widgets] of sortedRoles) {\n lines.push(`${roleName}:`);\n\n for (const widget of widgets) {\n lines.push(` ${formatWidgetPreview(widget, getWidgetAccessibleName(widget))}`);\n }\n\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\").trimEnd();\n};\n\n/**\n * Prints the accessible roles in a container's tree to the console using\n * {@link prettyRoles}.\n *\n * @param container The scope to inspect.\n */\nconst logRoles = (container: Container): void => {\n console.log(prettyRoles(container));\n};\n\n/**\n * Returns the heading or hierarchy level GTK reports for a widget, or undefined when it declares\n * none.\n *\n * @param widget The widget to read the level from.\n */\nconst computeHeadingLevel = (widget: Gtk.Accessible): number | undefined =>\n getWidgetLevel(requireWidget(widget)) ?? undefined;\n\nexport { computeHeadingLevel, formatRole, formatRoleList, getRoles, prettyRoles, logRoles };\n"]}
@@ -14,7 +14,7 @@ import type { ScreenshotOptions, ScreenshotResult } from "./types.js";
14
14
  * @param options Optional scale, timeout, retry interval, and output path.
15
15
  * @returns The base64-encoded PNG data along with its mime type and dimensions.
16
16
  */
17
- declare const screenshot: (widget: Gtk.Widget, options?: ScreenshotOptions) => Promise<ScreenshotResult>;
17
+ declare const screenshot: (target: Gtk.Accessible, options?: ScreenshotOptions) => Promise<ScreenshotResult>;
18
18
  declare const captureScreen: (options?: ScreenshotOptions) => Promise<ScreenshotResult>;
19
19
  export { captureScreen, screenshot };
20
20
  //# sourceMappingURL=screenshot.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"screenshot.d.ts","sourceRoot":"","sources":["../src/screenshot.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AAGpC,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA6RtE;;;;;;;;;;;;;GAaG;AACH,QAAA,MAAM,UAAU,GAAU,QAAQ,GAAG,CAAC,MAAM,EAAE,UAAU,iBAAiB,KAAG,OAAO,CAAC,gBAAgB,CAkBnG,CAAC;AAYF,QAAA,MAAM,aAAa,GAAU,UAAU,iBAAiB,KAAG,OAAO,CAAC,gBAAgB,CAC5C,CAAC;AAExC,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC"}
1
+ {"version":3,"file":"screenshot.d.ts","sourceRoot":"","sources":["../src/screenshot.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AAGpC,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAqUtE;;;;;;;;;;;;;GAaG;AACH,QAAA,MAAM,UAAU,GAAU,QAAQ,GAAG,CAAC,UAAU,EAAE,UAAU,iBAAiB,KAAG,OAAO,CAAC,gBAAgB,CAmBvG,CAAC;AAYF,QAAA,MAAM,aAAa,GAAU,UAAU,iBAAiB,KAAG,OAAO,CAAC,gBAAgB,CAC5C,CAAC;AAExC,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC"}
@@ -8,6 +8,7 @@ import { getConfig } from "./config.js";
8
8
  import { now } from "./timers.js";
9
9
  import { descendants } from "./traversal.js";
10
10
  import { waitFor } from "./wait-for.js";
11
+ import { requireWidget } from "./widget-target.js";
11
12
  import { activeToplevel, mappedToplevels } from "./window-state.js";
12
13
  const DEFAULT_SCREENSHOT_INTERVAL = 10;
13
14
  const PRESENTATION_PROBE_MS = 250;
@@ -17,9 +18,7 @@ const NOT_PRESENTING_MESSAGE = "Screenshot failed: the display is not presenting
17
18
  const EMPTY_WIDGET_HINT = "The display is presenting frames to this window, so the widget itself is empty: it painted nothing.";
18
19
  const OTHER_FAILURE_HINT = "The display is presenting frames to this window, so the capture failed for another reason.";
19
20
  const NOTHING_ON_SCREEN_MESSAGE = "Nothing is on screen to capture: no toplevel window is mapped";
20
- const bytesToBase64 = (bytes) => {
21
- return Buffer.from(bytes).toString("base64");
22
- };
21
+ const bytesToBase64 = (bytes) => Buffer.from(bytes).toString("base64");
23
22
  const describeWidgetState = (widget) => `realized=${String(widget.getRealized())} mapped=${String(widget.getMapped())} ` +
24
23
  `visible=${String(widget.getVisible())}`;
25
24
  const getMappedPopovers = (widget) => {
@@ -110,13 +109,31 @@ const getChildrenNode = (widget, scale) => {
110
109
  appendPopovers(snapshot, widget);
111
110
  return snapshot.toNode();
112
111
  };
112
+ const addWindowBackground = (widget, node, { scale, width, height }) => {
113
+ if (!(widget instanceof Gtk.Window)) {
114
+ return node;
115
+ }
116
+ const snapshot = new Gtk.Snapshot();
117
+ const backgroundSnapshot = snapshot;
118
+ const styledWidget = widget;
119
+ snapshot.save();
120
+ snapshot.scale(scale, scale);
121
+ backgroundSnapshot.renderBackground(styledWidget.getStyleContext(), 0, 0, width, height);
122
+ snapshot.restore();
123
+ snapshot.appendNode(node);
124
+ return snapshot.toNode() ?? node;
125
+ };
126
+ const getFallbackNode = (widget, size) => {
127
+ const content = getChildrenNode(widget, size.scale);
128
+ return content === null ? null : addWindowBackground(widget, content, size);
129
+ };
113
130
  const getRenderNode = (widget, scale, width, height) => {
114
- const presented = getPaintableNode(widget, scale, width, height);
115
- if (presented) {
116
- return presented;
131
+ const content = getPaintableNode(widget, scale, width, height);
132
+ if (content) {
133
+ return content;
117
134
  }
118
135
  allocateRoot(widget);
119
- return getPaintableNode(widget, scale, width, height) ?? getChildrenNode(widget, scale);
136
+ return getPaintableNode(widget, scale, width, height) ?? getFallbackNode(widget, { scale, width, height });
120
137
  };
121
138
  const renderToPng = (widget, node, width, height) => {
122
139
  const renderer = new Gsk.CairoRenderer();
@@ -195,7 +212,8 @@ const captureUntilPaintable = (widget, scale, options) => {
195
212
  * @param options Optional scale, timeout, retry interval, and output path.
196
213
  * @returns The base64-encoded PNG data along with its mime type and dimensions.
197
214
  */
198
- const screenshot = async (widget, options) => {
215
+ const screenshot = async (target, options) => {
216
+ const widget = requireWidget(target);
199
217
  const scale = options?.scale ?? 1;
200
218
  if (!Number.isFinite(scale) || scale <= 0) {
201
219
  throw new Error(`Screenshot scale must be a positive number, got ${String(scale)}`);
@@ -1 +1 @@
1
- {"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../src/screenshot.ts"],"names":[],"mappings":"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","sourcesContent":["import * as Gdk from \"@gtkx/gi/gdk\";\nimport * as Graphene from \"@gtkx/gi/graphene\";\nimport * as Gsk from \"@gtkx/gi/gsk\";\nimport * as Gtk from \"@gtkx/gi/gtk\";\nimport { mkdirSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport type { ScreenshotOptions, ScreenshotResult } from \"./types.js\";\nimport { getConfig } from \"./config.js\";\nimport { now } from \"./timers.js\";\nimport { descendants } from \"./traversal.js\";\nimport { waitFor } from \"./wait-for.js\";\nimport { activeToplevel, mappedToplevels } from \"./window-state.js\";\n\ntype FrameProbe = {\n counter: bigint | null;\n startedAt: number;\n};\n\ntype CaptureFailure = \"no-size\" | \"no-content\";\n\ntype CaptureState = {\n probe: FrameProbe;\n failure: CaptureFailure | null;\n};\n\ntype CaptureResult =\n { status: \"captured\"; result: ScreenshotResult } |\n { status: \"failed\"; failure: CaptureFailure };\n\ntype CaptureOutcome =\n { status: \"captured\"; result: ScreenshotResult } |\n { status: \"stalled\"; failure: CaptureFailure };\n\nconst DEFAULT_SCREENSHOT_INTERVAL = 10;\nconst PRESENTATION_PROBE_MS = 250;\n\nconst NOT_PRESENTING_MESSAGE =\n \"Screenshot failed: the display is not presenting frames to this window, so GTK has no rendered \" +\n \"content to capture. The window is hidden, minimized, or its compositor is not presenting it; this \" +\n \"is a display problem, not a widget problem.\";\n\nconst EMPTY_WIDGET_HINT =\n \"The display is presenting frames to this window, so the widget itself is empty: it painted nothing.\";\n\nconst OTHER_FAILURE_HINT =\n \"The display is presenting frames to this window, so the capture failed for another reason.\";\n\nconst NOTHING_ON_SCREEN_MESSAGE = \"Nothing is on screen to capture: no toplevel window is mapped\";\n\nconst bytesToBase64 = (bytes: Uint8Array | number[]): string => {\n return Buffer.from(bytes).toString(\"base64\");\n};\n\nconst describeWidgetState = (widget: Gtk.Widget): string =>\n `realized=${String(widget.getRealized())} mapped=${String(widget.getMapped())} ` +\n `visible=${String(widget.getVisible())}`;\n\nconst getMappedPopovers = (widget: Gtk.Widget): Gtk.Popover[] => {\n const popovers: Gtk.Popover[] = [];\n\n for (const descendant of descendants(widget)) {\n if (descendant instanceof Gtk.Popover && descendant.getMapped()) {\n popovers.push(descendant);\n }\n }\n\n return popovers;\n};\n\nconst appendPopover = (snapshot: Gtk.Snapshot, target: Gtk.Widget, popover: Gtk.Popover): void => {\n const [hasBounds, bounds] = popover.computeBounds(target);\n const paintable = new Gtk.WidgetPaintable({ widget: popover });\n const width = paintable.getIntrinsicWidth();\n const height = paintable.getIntrinsicHeight();\n\n if (!hasBounds || width <= 0 || height <= 0) {\n return;\n }\n\n snapshot.save();\n snapshot.translate(new Graphene.Point({ x: bounds.origin.x, y: bounds.origin.y }));\n paintable.snapshot(snapshot, width, height);\n snapshot.restore();\n};\n\nconst appendPopovers = (snapshot: Gtk.Snapshot, target: Gtk.Widget): void => {\n for (const popover of getMappedPopovers(target)) {\n appendPopover(snapshot, target, popover);\n }\n};\n\nconst getSurface = (widget: Gtk.Widget): Gdk.Surface | null => widget.getNative()?.getSurface() ?? null;\nconst isSurfaceOnScreen = (widget: Gtk.Widget): boolean => getSurface(widget)?.getMapped() ?? false;\n\nconst getFrameClock = (widget: Gtk.Widget): Gdk.FrameClock | null =>\n widget.getRoot()?.getFrameClock() ?? widget.getFrameClock();\n\nconst getFrameCounter = (widget: Gtk.Widget): bigint | null => getFrameClock(widget)?.getFrameCounter() ?? null;\n\nconst describePresentation = (widget: Gtk.Widget): string =>\n `${describeWidgetState(widget)} surfaceMapped=${String(isSurfaceOnScreen(widget))} ` +\n `frameCounter=${String(getFrameCounter(widget))}`;\n\nconst requestFrame = (widget: Gtk.Widget): void => {\n getFrameClock(widget)?.requestPhase(Gdk.FrameClockPhase.UPDATE);\n};\n\nconst startFrameProbe = (widget: Gtk.Widget): FrameProbe => {\n requestFrame(widget);\n\n return { counter: getFrameCounter(widget), startedAt: now() };\n};\n\nconst updateFrameProbe = (widget: Gtk.Widget, probe: FrameProbe): void => {\n requestFrame(widget);\n\n if (probe.counter !== null) {\n return;\n }\n\n const counter = getFrameCounter(widget);\n\n if (counter !== null) {\n probe.counter = counter;\n probe.startedAt = now();\n }\n};\n\nconst hasFrameAdvanced = (widget: Gtk.Widget, probe: FrameProbe): boolean => {\n const counter = getFrameCounter(widget);\n\n return counter !== null && probe.counter !== null && counter > probe.counter;\n};\n\nconst isPresenting = (widget: Gtk.Widget, probe: FrameProbe): boolean =>\n isSurfaceOnScreen(widget) && hasFrameAdvanced(widget, probe);\n\nconst isPresentationStalled = (widget: Gtk.Widget, probe: FrameProbe): boolean =>\n now() - probe.startedAt >= PRESENTATION_PROBE_MS && !isPresenting(widget, probe);\n\nconst allocateRoot = (widget: Gtk.Widget): void => {\n const root = widget.getRoot();\n\n if (!root) {\n return;\n }\n\n const width = root.getWidth();\n const height = root.getHeight();\n\n if (width > 0 && height > 0) {\n root.allocate(width, height, -1, null);\n }\n};\n\nconst isDirectlyPaintable = (child: Gtk.Widget): boolean =>\n child.getMapped() && child.getWidth() > 0 && !(child instanceof Gtk.Popover);\n\nconst getPaintableNode = (widget: Gtk.Widget, scale: number, width: number, height: number): Gsk.RenderNode | null => {\n const paintable = new Gtk.WidgetPaintable({ widget });\n const snapshot = new Gtk.Snapshot();\n snapshot.scale(scale, scale);\n paintable.snapshot(snapshot, width, height);\n appendPopovers(snapshot, widget);\n\n return snapshot.toNode();\n};\n\nconst getChildrenNode = (widget: Gtk.Widget, scale: number): Gsk.RenderNode | null => {\n const snapshot = new Gtk.Snapshot();\n snapshot.scale(scale, scale);\n\n for (let child = widget.getFirstChild(); child !== null; child = child.getNextSibling()) {\n if (isDirectlyPaintable(child)) {\n widget.snapshotChild(child, snapshot);\n }\n }\n\n appendPopovers(snapshot, widget);\n\n return snapshot.toNode();\n};\n\nconst getRenderNode = (widget: Gtk.Widget, scale: number, width: number, height: number): Gsk.RenderNode | null => {\n const presented = getPaintableNode(widget, scale, width, height);\n\n if (presented) {\n return presented;\n }\n\n allocateRoot(widget);\n\n return getPaintableNode(widget, scale, width, height) ?? getChildrenNode(widget, scale);\n};\n\nconst renderToPng = (widget: Gtk.Widget, node: Gsk.RenderNode, width: number, height: number): ScreenshotResult => {\n const renderer = new Gsk.CairoRenderer();\n renderer.realizeForDisplay(widget.getDisplay());\n\n try {\n const viewport = Graphene.Rect.alloc().init(0, 0, width, height);\n const texture = renderer.renderTexture(node, viewport);\n const data = texture.saveToPngBytes().getData();\n\n if (!data) {\n throw new Error(\"Failed to serialize screenshot to PNG\");\n }\n\n return { data: bytesToBase64(data), mimeType: \"image/png\", width, height };\n } finally {\n renderer.unrealize();\n }\n};\n\nconst captureSnapshot = (widget: Gtk.Widget, scale: number): CaptureResult => {\n const paintable = new Gtk.WidgetPaintable({ widget });\n const width = paintable.getIntrinsicWidth();\n const height = paintable.getIntrinsicHeight();\n\n if (width <= 0 || height <= 0) {\n return { status: \"failed\", failure: \"no-size\" };\n }\n\n const renderNode = getRenderNode(widget, scale, width, height);\n\n if (!renderNode) {\n return { status: \"failed\", failure: \"no-content\" };\n }\n\n const scaledWidth = Math.round(width * scale);\n const scaledHeight = Math.round(height * scale);\n\n return { status: \"captured\", result: renderToPng(widget, renderNode, scaledWidth, scaledHeight) };\n};\n\nconst failureMessage = (widget: Gtk.Widget, failure: CaptureFailure): string =>\n failure === \"no-size\"\n ? `Widget has no size: ensure it is realized and visible (${describeWidgetState(widget)})`\n : `Widget produced no render content (${describeWidgetState(widget)})`;\n\nconst notPresentingMessage = (widget: Gtk.Widget): string =>\n `${NOT_PRESENTING_MESSAGE} (${describePresentation(widget)})`;\n\nconst stalledMessage = (widget: Gtk.Widget, failure: CaptureFailure): string =>\n `${notPresentingMessage(widget)}\\n\\n${failureMessage(widget, failure)}`;\n\nconst presentingHint = (failure: CaptureFailure | null): string =>\n failure === \"no-content\" ? EMPTY_WIDGET_HINT : OTHER_FAILURE_HINT;\n\nconst timeoutHint = (widget: Gtk.Widget, state: CaptureState): string =>\n isPresenting(widget, state.probe) ? presentingHint(state.failure) : notPresentingMessage(widget);\n\nconst explainTimeout = (error: Error, widget: Gtk.Widget, state: CaptureState): Error =>\n getConfig().getElementError(`${error.message}\\n\\n${timeoutHint(widget, state)}`);\n\nconst attemptCapture = (widget: Gtk.Widget, scale: number, state: CaptureState): CaptureOutcome => {\n const attempt = captureSnapshot(widget, scale);\n\n if (attempt.status === \"captured\") {\n return attempt;\n }\n\n state.failure = attempt.failure;\n updateFrameProbe(widget, state.probe);\n\n if (isPresentationStalled(widget, state.probe)) {\n return { status: \"stalled\", failure: attempt.failure };\n }\n\n throw new Error(failureMessage(widget, attempt.failure));\n};\n\nconst writeScreenshot = (result: ScreenshotResult, path: string): void => {\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, Buffer.from(result.data, \"base64\"));\n};\n\nconst captureUntilPaintable = (\n widget: Gtk.Widget,\n scale: number,\n options: ScreenshotOptions | undefined,\n): Promise<CaptureOutcome> => {\n const state: CaptureState = { probe: startFrameProbe(widget), failure: null };\n\n return waitFor(() => attemptCapture(widget, scale, state), {\n timeout: options?.timeout,\n interval: options?.interval ?? DEFAULT_SCREENSHOT_INTERVAL,\n onTimeout: (error) => explainTimeout(error, widget, state),\n });\n};\n\n/**\n * Captures a PNG snapshot of a widget, retrying until it has a paintable size,\n * and writes the image to `options.path` when one is given, creating any\n * missing parent directories. Popovers open inside the widget render on their\n * own surfaces, so they are composited into the image at their on-screen\n * positions. A display that never presents a frame leaves GTK without a cached\n * render node, so the widget's contents are then snapshotted directly; when\n * even that yields nothing, the failure names the display instead of blaming\n * the widget.\n *\n * @param widget The widget to render to an image.\n * @param options Optional scale, timeout, retry interval, and output path.\n * @returns The base64-encoded PNG data along with its mime type and dimensions.\n */\nconst screenshot = async (widget: Gtk.Widget, options?: ScreenshotOptions): Promise<ScreenshotResult> => {\n const scale = options?.scale ?? 1;\n\n if (!Number.isFinite(scale) || scale <= 0) {\n throw new Error(`Screenshot scale must be a positive number, got ${String(scale)}`);\n }\n\n const outcome = await captureUntilPaintable(widget, scale, options);\n\n if (outcome.status === \"stalled\") {\n throw new Error(stalledMessage(widget, outcome.failure));\n }\n\n if (options?.path) {\n writeScreenshot(outcome.result, options.path);\n }\n\n return outcome.result;\n};\n\nconst screenTarget = (): Gtk.Window => {\n const target = activeToplevel() ?? mappedToplevels()[0];\n\n if (!target) {\n throw new Error(NOTHING_ON_SCREEN_MESSAGE);\n }\n\n return target;\n};\n\nconst captureScreen = async (options?: ScreenshotOptions): Promise<ScreenshotResult> =>\n screenshot(screenTarget(), options);\n\nexport { captureScreen, screenshot };\n"]}
1
+ {"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../src/screenshot.ts"],"names":[],"mappings":"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","sourcesContent":["import * as Gdk from \"@gtkx/gi/gdk\";\nimport * as Graphene from \"@gtkx/gi/graphene\";\nimport * as Gsk from \"@gtkx/gi/gsk\";\nimport * as Gtk from \"@gtkx/gi/gtk\";\nimport { mkdirSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport type { ScreenshotOptions, ScreenshotResult } from \"./types.js\";\nimport { getConfig } from \"./config.js\";\nimport { now } from \"./timers.js\";\nimport { descendants } from \"./traversal.js\";\nimport { waitFor } from \"./wait-for.js\";\nimport { requireWidget } from \"./widget-target.js\";\nimport { activeToplevel, mappedToplevels } from \"./window-state.js\";\n\ntype FrameProbe = {\n counter: bigint | null;\n startedAt: number;\n};\n\ntype CaptureFailure = \"no-size\" | \"no-content\";\n\ntype CaptureState = {\n probe: FrameProbe;\n failure: CaptureFailure | null;\n};\n\ntype CaptureResult =\n { status: \"captured\"; result: ScreenshotResult } |\n { status: \"failed\"; failure: CaptureFailure };\n\ntype CaptureOutcome =\n { status: \"captured\"; result: ScreenshotResult } |\n { status: \"stalled\"; failure: CaptureFailure };\n\ntype BackgroundSnapshot = {\n renderBackground(...args: [context: object, x: number, y: number, width: number, height: number]): void;\n};\n\ntype StyledWidget = {\n getStyleContext(): object;\n};\n\ntype RenderSize = {\n scale: number;\n width: number;\n height: number;\n};\n\nconst DEFAULT_SCREENSHOT_INTERVAL = 10;\nconst PRESENTATION_PROBE_MS = 250;\n\nconst NOT_PRESENTING_MESSAGE =\n \"Screenshot failed: the display is not presenting frames to this window, so GTK has no rendered \" +\n \"content to capture. The window is hidden, minimized, or its compositor is not presenting it; this \" +\n \"is a display problem, not a widget problem.\";\n\nconst EMPTY_WIDGET_HINT =\n \"The display is presenting frames to this window, so the widget itself is empty: it painted nothing.\";\n\nconst OTHER_FAILURE_HINT =\n \"The display is presenting frames to this window, so the capture failed for another reason.\";\n\nconst NOTHING_ON_SCREEN_MESSAGE = \"Nothing is on screen to capture: no toplevel window is mapped\";\n\nconst bytesToBase64 = (bytes: Uint8Array | number[]): string => Buffer.from(bytes).toString(\"base64\");\n\nconst describeWidgetState = (widget: Gtk.Widget): string =>\n `realized=${String(widget.getRealized())} mapped=${String(widget.getMapped())} ` +\n `visible=${String(widget.getVisible())}`;\n\nconst getMappedPopovers = (widget: Gtk.Widget): Gtk.Popover[] => {\n const popovers: Gtk.Popover[] = [];\n\n for (const descendant of descendants(widget)) {\n if (descendant instanceof Gtk.Popover && descendant.getMapped()) {\n popovers.push(descendant);\n }\n }\n\n return popovers;\n};\n\nconst appendPopover = (snapshot: Gtk.Snapshot, target: Gtk.Widget, popover: Gtk.Popover): void => {\n const [hasBounds, bounds] = popover.computeBounds(target);\n const paintable = new Gtk.WidgetPaintable({ widget: popover });\n const width = paintable.getIntrinsicWidth();\n const height = paintable.getIntrinsicHeight();\n\n if (!hasBounds || width <= 0 || height <= 0) {\n return;\n }\n\n snapshot.save();\n snapshot.translate(new Graphene.Point({ x: bounds.origin.x, y: bounds.origin.y }));\n paintable.snapshot(snapshot, width, height);\n snapshot.restore();\n};\n\nconst appendPopovers = (snapshot: Gtk.Snapshot, target: Gtk.Widget): void => {\n for (const popover of getMappedPopovers(target)) {\n appendPopover(snapshot, target, popover);\n }\n};\n\nconst getSurface = (widget: Gtk.Widget): Gdk.Surface | null => widget.getNative()?.getSurface() ?? null;\nconst isSurfaceOnScreen = (widget: Gtk.Widget): boolean => getSurface(widget)?.getMapped() ?? false;\n\nconst getFrameClock = (widget: Gtk.Widget): Gdk.FrameClock | null =>\n widget.getRoot()?.getFrameClock() ?? widget.getFrameClock();\n\nconst getFrameCounter = (widget: Gtk.Widget): bigint | null => getFrameClock(widget)?.getFrameCounter() ?? null;\n\nconst describePresentation = (widget: Gtk.Widget): string =>\n `${describeWidgetState(widget)} surfaceMapped=${String(isSurfaceOnScreen(widget))} ` +\n `frameCounter=${String(getFrameCounter(widget))}`;\n\nconst requestFrame = (widget: Gtk.Widget): void => {\n getFrameClock(widget)?.requestPhase(Gdk.FrameClockPhase.UPDATE);\n};\n\nconst startFrameProbe = (widget: Gtk.Widget): FrameProbe => {\n requestFrame(widget);\n\n return { counter: getFrameCounter(widget), startedAt: now() };\n};\n\nconst updateFrameProbe = (widget: Gtk.Widget, probe: FrameProbe): void => {\n requestFrame(widget);\n\n if (probe.counter !== null) {\n return;\n }\n\n const counter = getFrameCounter(widget);\n\n if (counter !== null) {\n probe.counter = counter;\n probe.startedAt = now();\n }\n};\n\nconst hasFrameAdvanced = (widget: Gtk.Widget, probe: FrameProbe): boolean => {\n const counter = getFrameCounter(widget);\n\n return counter !== null && probe.counter !== null && counter > probe.counter;\n};\n\nconst isPresenting = (widget: Gtk.Widget, probe: FrameProbe): boolean =>\n isSurfaceOnScreen(widget) && hasFrameAdvanced(widget, probe);\n\nconst isPresentationStalled = (widget: Gtk.Widget, probe: FrameProbe): boolean =>\n now() - probe.startedAt >= PRESENTATION_PROBE_MS && !isPresenting(widget, probe);\n\nconst allocateRoot = (widget: Gtk.Widget): void => {\n const root = widget.getRoot();\n\n if (!root) {\n return;\n }\n\n const width = root.getWidth();\n const height = root.getHeight();\n\n if (width > 0 && height > 0) {\n root.allocate(width, height, -1, null);\n }\n};\n\nconst isDirectlyPaintable = (child: Gtk.Widget): boolean =>\n child.getMapped() && child.getWidth() > 0 && !(child instanceof Gtk.Popover);\n\nconst getPaintableNode = (widget: Gtk.Widget, scale: number, width: number, height: number): Gsk.RenderNode | null => {\n const paintable = new Gtk.WidgetPaintable({ widget });\n const snapshot = new Gtk.Snapshot();\n snapshot.scale(scale, scale);\n paintable.snapshot(snapshot, width, height);\n appendPopovers(snapshot, widget);\n\n return snapshot.toNode();\n};\n\nconst getChildrenNode = (widget: Gtk.Widget, scale: number): Gsk.RenderNode | null => {\n const snapshot = new Gtk.Snapshot();\n snapshot.scale(scale, scale);\n\n for (let child = widget.getFirstChild(); child !== null; child = child.getNextSibling()) {\n if (isDirectlyPaintable(child)) {\n widget.snapshotChild(child, snapshot);\n }\n }\n\n appendPopovers(snapshot, widget);\n\n return snapshot.toNode();\n};\n\nconst addWindowBackground = (\n widget: Gtk.Widget,\n node: Gsk.RenderNode,\n { scale, width, height }: RenderSize,\n): Gsk.RenderNode => {\n if (!(widget instanceof Gtk.Window)) {\n return node;\n }\n\n const snapshot = new Gtk.Snapshot();\n const backgroundSnapshot: BackgroundSnapshot = snapshot;\n const styledWidget: StyledWidget = widget;\n snapshot.save();\n snapshot.scale(scale, scale);\n backgroundSnapshot.renderBackground(styledWidget.getStyleContext(), 0, 0, width, height);\n snapshot.restore();\n snapshot.appendNode(node);\n\n return snapshot.toNode() ?? node;\n};\n\nconst getFallbackNode = (widget: Gtk.Widget, size: RenderSize): Gsk.RenderNode | null => {\n const content = getChildrenNode(widget, size.scale);\n\n return content === null ? null : addWindowBackground(widget, content, size);\n};\n\nconst getRenderNode = (widget: Gtk.Widget, scale: number, width: number, height: number): Gsk.RenderNode | null => {\n const content = getPaintableNode(widget, scale, width, height);\n\n if (content) {\n return content;\n }\n\n allocateRoot(widget);\n\n return getPaintableNode(widget, scale, width, height) ?? getFallbackNode(widget, { scale, width, height });\n};\n\nconst renderToPng = (widget: Gtk.Widget, node: Gsk.RenderNode, width: number, height: number): ScreenshotResult => {\n const renderer = new Gsk.CairoRenderer();\n renderer.realizeForDisplay(widget.getDisplay());\n\n try {\n const viewport = Graphene.Rect.alloc().init(0, 0, width, height);\n const texture = renderer.renderTexture(node, viewport);\n const data = texture.saveToPngBytes().getData();\n\n if (!data) {\n throw new Error(\"Failed to serialize screenshot to PNG\");\n }\n\n return { data: bytesToBase64(data), mimeType: \"image/png\", width, height };\n } finally {\n renderer.unrealize();\n }\n};\n\nconst captureSnapshot = (widget: Gtk.Widget, scale: number): CaptureResult => {\n const paintable = new Gtk.WidgetPaintable({ widget });\n const width = paintable.getIntrinsicWidth();\n const height = paintable.getIntrinsicHeight();\n\n if (width <= 0 || height <= 0) {\n return { status: \"failed\", failure: \"no-size\" };\n }\n\n const renderNode = getRenderNode(widget, scale, width, height);\n\n if (!renderNode) {\n return { status: \"failed\", failure: \"no-content\" };\n }\n\n const scaledWidth = Math.round(width * scale);\n const scaledHeight = Math.round(height * scale);\n\n return { status: \"captured\", result: renderToPng(widget, renderNode, scaledWidth, scaledHeight) };\n};\n\nconst failureMessage = (widget: Gtk.Widget, failure: CaptureFailure): string =>\n failure === \"no-size\"\n ? `Widget has no size: ensure it is realized and visible (${describeWidgetState(widget)})`\n : `Widget produced no render content (${describeWidgetState(widget)})`;\n\nconst notPresentingMessage = (widget: Gtk.Widget): string =>\n `${NOT_PRESENTING_MESSAGE} (${describePresentation(widget)})`;\n\nconst stalledMessage = (widget: Gtk.Widget, failure: CaptureFailure): string =>\n `${notPresentingMessage(widget)}\\n\\n${failureMessage(widget, failure)}`;\n\nconst presentingHint = (failure: CaptureFailure | null): string =>\n failure === \"no-content\" ? EMPTY_WIDGET_HINT : OTHER_FAILURE_HINT;\n\nconst timeoutHint = (widget: Gtk.Widget, state: CaptureState): string =>\n isPresenting(widget, state.probe) ? presentingHint(state.failure) : notPresentingMessage(widget);\n\nconst explainTimeout = (error: Error, widget: Gtk.Widget, state: CaptureState): Error =>\n getConfig().getElementError(`${error.message}\\n\\n${timeoutHint(widget, state)}`);\n\nconst attemptCapture = (widget: Gtk.Widget, scale: number, state: CaptureState): CaptureOutcome => {\n const attempt = captureSnapshot(widget, scale);\n\n if (attempt.status === \"captured\") {\n return attempt;\n }\n\n state.failure = attempt.failure;\n updateFrameProbe(widget, state.probe);\n\n if (isPresentationStalled(widget, state.probe)) {\n return { status: \"stalled\", failure: attempt.failure };\n }\n\n throw new Error(failureMessage(widget, attempt.failure));\n};\n\nconst writeScreenshot = (result: ScreenshotResult, path: string): void => {\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, Buffer.from(result.data, \"base64\"));\n};\n\nconst captureUntilPaintable = (\n widget: Gtk.Widget,\n scale: number,\n options: ScreenshotOptions | undefined,\n): Promise<CaptureOutcome> => {\n const state: CaptureState = { probe: startFrameProbe(widget), failure: null };\n\n return waitFor(() => attemptCapture(widget, scale, state), {\n timeout: options?.timeout,\n interval: options?.interval ?? DEFAULT_SCREENSHOT_INTERVAL,\n onTimeout: (error) => explainTimeout(error, widget, state),\n });\n};\n\n/**\n * Captures a PNG snapshot of a widget, retrying until it has a paintable size,\n * and writes the image to `options.path` when one is given, creating any\n * missing parent directories. Popovers open inside the widget render on their\n * own surfaces, so they are composited into the image at their on-screen\n * positions. A display that never presents a frame leaves GTK without a cached\n * render node, so the widget's contents are then snapshotted directly; when\n * even that yields nothing, the failure names the display instead of blaming\n * the widget.\n *\n * @param widget The widget to render to an image.\n * @param options Optional scale, timeout, retry interval, and output path.\n * @returns The base64-encoded PNG data along with its mime type and dimensions.\n */\nconst screenshot = async (target: Gtk.Accessible, options?: ScreenshotOptions): Promise<ScreenshotResult> => {\n const widget = requireWidget(target);\n const scale = options?.scale ?? 1;\n\n if (!Number.isFinite(scale) || scale <= 0) {\n throw new Error(`Screenshot scale must be a positive number, got ${String(scale)}`);\n }\n\n const outcome = await captureUntilPaintable(widget, scale, options);\n\n if (outcome.status === \"stalled\") {\n throw new Error(stalledMessage(widget, outcome.failure));\n }\n\n if (options?.path) {\n writeScreenshot(outcome.result, options.path);\n }\n\n return outcome.result;\n};\n\nconst screenTarget = (): Gtk.Window => {\n const target = activeToplevel() ?? mappedToplevels()[0];\n\n if (!target) {\n throw new Error(NOTHING_ON_SCREEN_MESSAGE);\n }\n\n return target;\n};\n\nconst captureScreen = async (options?: ScreenshotOptions): Promise<ScreenshotResult> =>\n screenshot(screenTarget(), options);\n\nexport { captureScreen, screenshot };\n"]}
@@ -25,6 +25,6 @@ type Suggestion = {
25
25
  * @param method Restrict the suggestion to a specific query family instead of choosing by priority.
26
26
  * @returns The best available suggestion, or undefined when no query applies.
27
27
  */
28
- declare const getSuggestedQuery: (widget: Gtk.Widget, variant?: Variant, method?: Method) => Suggestion | undefined;
28
+ declare const getSuggestedQuery: (target: Gtk.Accessible, variant?: Variant, method?: Method) => Suggestion | undefined;
29
29
  export { getSuggestedQuery, type Variant, type Method, type Suggestion };
30
30
  //# sourceMappingURL=suggestions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"suggestions.d.ts","sourceRoot":"","sources":["../src/suggestions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AAYpC,8CAA8C;AAC9C,KAAK,OAAO,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,SAAS,CAAC;AAC5E,6CAA6C;AAC7C,KAAK,MAAM,GAAG,MAAM,GAAG,WAAW,GAAG,iBAAiB,GAAG,MAAM,GAAG,cAAc,GAAG,MAAM,CAAC;AAE1F;;;GAGG;AACH,KAAK,UAAU,GAAG;IACd,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,WAAW,EAAE,MAAM,CAAC;IACpB,yFAAyF;IACzF,OAAO,EAAE,OAAO,CAAC;IACjB,qGAAqG;IACrG,QAAQ,EAAE,MAAM,MAAM,CAAC;CAC1B,CAAC;AAsCF;;;;;;;GAOG;AACH,QAAA,MAAM,iBAAiB,GACnB,QAAQ,GAAG,CAAC,MAAM,EAClB,UAAS,OAAe,EACxB,SAAS,MAAM,KAChB,UAAU,GAAG,SA0Bf,CAAC;AAEF,OAAO,EAAE,iBAAiB,EAAE,KAAK,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,UAAU,EAAE,CAAC"}
1
+ {"version":3,"file":"suggestions.d.ts","sourceRoot":"","sources":["../src/suggestions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AAapC,8CAA8C;AAC9C,KAAK,OAAO,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,SAAS,CAAC;AAC5E,6CAA6C;AAC7C,KAAK,MAAM,GAAG,MAAM,GAAG,WAAW,GAAG,iBAAiB,GAAG,MAAM,GAAG,cAAc,GAAG,MAAM,CAAC;AAE1F;;;GAGG;AACH,KAAK,UAAU,GAAG;IACd,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,WAAW,EAAE,MAAM,CAAC;IACpB,yFAAyF;IACzF,OAAO,EAAE,OAAO,CAAC;IACjB,qGAAqG;IACrG,QAAQ,EAAE,MAAM,MAAM,CAAC;CAC1B,CAAC;AAsCF;;;;;;;GAOG;AACH,QAAA,MAAM,iBAAiB,GACnB,QAAQ,GAAG,CAAC,UAAU,EACtB,UAAS,OAAe,EACxB,SAAS,MAAM,KAChB,UAAU,GAAG,SA2Bf,CAAC;AAEF,OAAO,EAAE,iBAAiB,EAAE,KAAK,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,UAAU,EAAE,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import * as Gtk from "@gtkx/gi/gtk";
2
2
  import { formatRole } from "./role-helpers.js";
3
3
  import { getWidgetAccessibleName, getWidgetDisplayValue, getWidgetLabelledByText, getWidgetLabelText, getWidgetName, getWidgetOwnLabel, getWidgetPlaceholderText, } from "./widget-accessible-properties.js";
4
+ import { requireWidget } from "./widget-target.js";
4
5
  const makeSuggestion = (queryName, variant, argsText) => {
5
6
  const queryMethod = `${variant}By${queryName}`;
6
7
  return {
@@ -36,7 +37,8 @@ const textSuggestion = (queryName, variant, value) => {
36
37
  * @param method Restrict the suggestion to a specific query family instead of choosing by priority.
37
38
  * @returns The best available suggestion, or undefined when no query applies.
38
39
  */
39
- const getSuggestedQuery = (widget, variant = "get", method) => {
40
+ const getSuggestedQuery = (target, variant = "get", method) => {
41
+ const widget = requireWidget(target);
40
42
  const builders = {
41
43
  Role: () => roleSuggestion(widget, variant),
42
44
  LabelText: () => textSuggestion("LabelText", variant, getWidgetOwnLabel(widget) ?? getWidgetLabelledByText(widget)),
@@ -1 +1 @@
1
- {"version":3,"file":"suggestions.js","sourceRoot":"","sources":["../src/suggestions.ts"],"names":[],"mappings":"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","sourcesContent":["import * as Gtk from \"@gtkx/gi/gtk\";\nimport { formatRole } from \"./role-helpers.js\";\nimport {\n getWidgetAccessibleName,\n getWidgetDisplayValue,\n getWidgetLabelledByText,\n getWidgetLabelText,\n getWidgetName,\n getWidgetOwnLabel,\n getWidgetPlaceholderText,\n} from \"./widget-accessible-properties.js\";\n\n/** The query variant a suggestion targets. */\ntype Variant = \"get\" | \"getAll\" | \"query\" | \"queryAll\" | \"find\" | \"findAll\";\n/** The query family a suggestion targets. */\ntype Method = \"Role\" | \"LabelText\" | \"PlaceholderText\" | \"Text\" | \"DisplayValue\" | \"Name\";\n\n/**\n * A suggested query for reaching a widget, including its family, variant, method name, and a\n * `toString` that renders the full call.\n */\ntype Suggestion = {\n /** The query family, such as `Role`. */\n queryName: Method;\n /** The full query function name, such as `getByRole`. */\n queryMethod: string;\n /** The variant the suggestion was asked for, which prefixes `Suggestion.queryMethod`. */\n variant: Variant;\n /** Renders the suggested call with its arguments, such as `getByRole(Gtk.AccessibleRole.BUTTON)`. */\n toString: () => string;\n};\n\nconst makeSuggestion = (queryName: Method, variant: Variant, argsText: string): Suggestion => {\n const queryMethod = `${variant}By${queryName}`;\n\n return {\n queryName,\n queryMethod,\n variant,\n toString: () => `${queryMethod}(${argsText})`,\n };\n};\n\nconst roleSuggestion = (widget: Gtk.Widget, variant: Variant): Suggestion | undefined => {\n const role = widget.getAccessibleRole();\n\n if (role === Gtk.AccessibleRole.NONE || role === Gtk.AccessibleRole.GENERIC) {\n return undefined;\n }\n\n const roleText = `Gtk.AccessibleRole.${formatRole(role).toUpperCase()}`;\n const name = getWidgetAccessibleName(widget);\n\n if (name === null) {\n return makeSuggestion(\"Role\", variant, roleText);\n }\n\n return makeSuggestion(\"Role\", variant, `${roleText}, { name: '${name}' }`);\n};\n\nconst textSuggestion = (queryName: Method, variant: Variant, value: string | null): Suggestion | undefined => {\n if (value === null) {\n return undefined;\n }\n\n return makeSuggestion(queryName, variant, `'${value}'`);\n};\n\n/**\n * Computes the recommended query for reaching the given widget, preferring role, then label text,\n * placeholder text, text, display value, and name.\n * @param widget Widget to build a suggestion for.\n * @param variant Query variant the suggestion should use.\n * @param method Restrict the suggestion to a specific query family instead of choosing by priority.\n * @returns The best available suggestion, or undefined when no query applies.\n */\nconst getSuggestedQuery = (\n widget: Gtk.Widget,\n variant: Variant = \"get\",\n method?: Method,\n): Suggestion | undefined => {\n const builders: Record<Method, () => Suggestion | undefined> = {\n Role: () => roleSuggestion(widget, variant),\n LabelText: () =>\n textSuggestion(\"LabelText\", variant, getWidgetOwnLabel(widget) ?? getWidgetLabelledByText(widget)),\n PlaceholderText: () => textSuggestion(\"PlaceholderText\", variant, getWidgetPlaceholderText(widget)),\n Text: () => textSuggestion(\"Text\", variant, getWidgetLabelText(widget)),\n DisplayValue: () => textSuggestion(\"DisplayValue\", variant, getWidgetDisplayValue(widget)),\n Name: () => textSuggestion(\"Name\", variant, getWidgetName(widget)),\n };\n\n if (method) {\n return builders[method]();\n }\n\n const priority: Method[] = [\"Role\", \"LabelText\", \"PlaceholderText\", \"Text\", \"DisplayValue\", \"Name\"];\n\n for (const candidate of priority) {\n const suggestion = builders[candidate]();\n\n if (suggestion) {\n return suggestion;\n }\n }\n\n return undefined;\n};\n\nexport { getSuggestedQuery, type Variant, type Method, type Suggestion };\n"]}
1
+ {"version":3,"file":"suggestions.js","sourceRoot":"","sources":["../src/suggestions.ts"],"names":[],"mappings":"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","sourcesContent":["import * as Gtk from \"@gtkx/gi/gtk\";\nimport { formatRole } from \"./role-helpers.js\";\nimport {\n getWidgetAccessibleName,\n getWidgetDisplayValue,\n getWidgetLabelledByText,\n getWidgetLabelText,\n getWidgetName,\n getWidgetOwnLabel,\n getWidgetPlaceholderText,\n} from \"./widget-accessible-properties.js\";\nimport { requireWidget } from \"./widget-target.js\";\n\n/** The query variant a suggestion targets. */\ntype Variant = \"get\" | \"getAll\" | \"query\" | \"queryAll\" | \"find\" | \"findAll\";\n/** The query family a suggestion targets. */\ntype Method = \"Role\" | \"LabelText\" | \"PlaceholderText\" | \"Text\" | \"DisplayValue\" | \"Name\";\n\n/**\n * A suggested query for reaching a widget, including its family, variant, method name, and a\n * `toString` that renders the full call.\n */\ntype Suggestion = {\n /** The query family, such as `Role`. */\n queryName: Method;\n /** The full query function name, such as `getByRole`. */\n queryMethod: string;\n /** The variant the suggestion was asked for, which prefixes `Suggestion.queryMethod`. */\n variant: Variant;\n /** Renders the suggested call with its arguments, such as `getByRole(Gtk.AccessibleRole.BUTTON)`. */\n toString: () => string;\n};\n\nconst makeSuggestion = (queryName: Method, variant: Variant, argsText: string): Suggestion => {\n const queryMethod = `${variant}By${queryName}`;\n\n return {\n queryName,\n queryMethod,\n variant,\n toString: () => `${queryMethod}(${argsText})`,\n };\n};\n\nconst roleSuggestion = (widget: Gtk.Widget, variant: Variant): Suggestion | undefined => {\n const role = widget.getAccessibleRole();\n\n if (role === Gtk.AccessibleRole.NONE || role === Gtk.AccessibleRole.GENERIC) {\n return undefined;\n }\n\n const roleText = `Gtk.AccessibleRole.${formatRole(role).toUpperCase()}`;\n const name = getWidgetAccessibleName(widget);\n\n if (name === null) {\n return makeSuggestion(\"Role\", variant, roleText);\n }\n\n return makeSuggestion(\"Role\", variant, `${roleText}, { name: '${name}' }`);\n};\n\nconst textSuggestion = (queryName: Method, variant: Variant, value: string | null): Suggestion | undefined => {\n if (value === null) {\n return undefined;\n }\n\n return makeSuggestion(queryName, variant, `'${value}'`);\n};\n\n/**\n * Computes the recommended query for reaching the given widget, preferring role, then label text,\n * placeholder text, text, display value, and name.\n * @param widget Widget to build a suggestion for.\n * @param variant Query variant the suggestion should use.\n * @param method Restrict the suggestion to a specific query family instead of choosing by priority.\n * @returns The best available suggestion, or undefined when no query applies.\n */\nconst getSuggestedQuery = (\n target: Gtk.Accessible,\n variant: Variant = \"get\",\n method?: Method,\n): Suggestion | undefined => {\n const widget = requireWidget(target);\n const builders: Record<Method, () => Suggestion | undefined> = {\n Role: () => roleSuggestion(widget, variant),\n LabelText: () =>\n textSuggestion(\"LabelText\", variant, getWidgetOwnLabel(widget) ?? getWidgetLabelledByText(widget)),\n PlaceholderText: () => textSuggestion(\"PlaceholderText\", variant, getWidgetPlaceholderText(widget)),\n Text: () => textSuggestion(\"Text\", variant, getWidgetLabelText(widget)),\n DisplayValue: () => textSuggestion(\"DisplayValue\", variant, getWidgetDisplayValue(widget)),\n Name: () => textSuggestion(\"Name\", variant, getWidgetName(widget)),\n };\n\n if (method) {\n return builders[method]();\n }\n\n const priority: Method[] = [\"Role\", \"LabelText\", \"PlaceholderText\", \"Text\", \"DisplayValue\", \"Name\"];\n\n for (const candidate of priority) {\n const suggestion = builders[candidate]();\n\n if (suggestion) {\n return suggestion;\n }\n }\n\n return undefined;\n};\n\nexport { getSuggestedQuery, type Variant, type Method, type Suggestion };\n"]}
@@ -3,22 +3,22 @@ import * as Gtk from "@gtkx/gi/gtk";
3
3
  * A scope that resolves to a single root widget: the widget itself, the widget a controller or
4
4
  * layout manager is attached to, or a list item's or header's child.
5
5
  */
6
- type QueryContainer = Gtk.Widget | Gtk.EventController | Gtk.LayoutManager | Gtk.ListItem | Gtk.ListHeader;
6
+ type QueryContainer = Gtk.Accessible | Gtk.EventController | Gtk.LayoutManager | Gtk.ListItem | Gtk.ListHeader;
7
7
  /**
8
8
  * A scope that queries and traversal can run against: a widget, an event
9
9
  * controller, a layout manager, a list item or header, an application, or the
10
10
  * sentinel representing all current toplevel windows.
11
11
  */
12
12
  type Container = QueryContainer | Gtk.Application | typeof TOPLEVELS;
13
- type WidgetClass<T extends Gtk.Widget> = abstract new (...args: never[]) => T;
13
+ type WidgetClass<T extends object> = abstract new (...args: never[]) => T;
14
14
  /** Container sentinel that widens a query to every toplevel window currently open. */
15
15
  declare const TOPLEVELS: unique symbol;
16
16
  declare const isOnScreen: (widget: Gtk.Widget) => boolean;
17
17
  declare const children: (widget: Gtk.Widget) => Generator<Gtk.Widget>;
18
18
  declare const descendants: (widget: Gtk.Widget) => Generator<Gtk.Widget>;
19
19
  declare const ancestors: (widget: Gtk.Widget) => Generator<Gtk.Widget>;
20
- declare const ancestorFor: <T extends Gtk.Widget>(widget: Gtk.Widget, type: WidgetClass<T>) => T | null;
21
- declare const relationCandidates: (widget: Gtk.Widget) => Gtk.Accessible[];
20
+ declare const ancestorFor: <T extends object>(widget: Gtk.Widget, type: WidgetClass<T>) => T | null;
21
+ declare const relationCandidates: (widget: Gtk.Widget) => Iterable<Gtk.Accessible>[];
22
22
  declare const roots: (container: Container) => Generator<Gtk.Widget>;
23
23
  declare const traverse: (container: Container) => Generator<Gtk.Widget>;
24
24
  declare const findAll: (container: Container, isMatch: (node: Gtk.Widget) => boolean) => Gtk.Widget[];
@@ -1 +1 @@
1
- {"version":3,"file":"traversal.d.ts","sourceRoot":"","sources":["../src/traversal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AAEpC;;;GAGG;AACH,KAAK,cAAc,GAAG,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,eAAe,GAAG,GAAG,CAAC,aAAa,GAAG,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,UAAU,CAAC;AAC3G;;;;GAIG;AACH,KAAK,SAAS,GAAG,cAAc,GAAG,GAAG,CAAC,WAAW,GAAG,OAAO,SAAS,CAAC;AACrE,KAAK,WAAW,CAAC,CAAC,SAAS,GAAG,CAAC,MAAM,IAAI,QAAQ,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;AAE9E,sFAAsF;AACtF,QAAA,MAAM,SAAS,EAAE,OAAO,MAAiC,CAAC;AAI1D,QAAA,MAAM,UAAU,GAAI,QAAQ,GAAG,CAAC,MAAM,KAAG,OAA6B,CAAC;AAkBvE,QAAA,MAAM,QAAQ,GAAc,QAAQ,GAAG,CAAC,MAAM,KAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAOpE,CAAC;AAEF,QAAA,MAAM,WAAW,GAAc,QAAQ,GAAG,CAAC,MAAM,KAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAIvE,CAAC;AAEF,QAAA,MAAM,SAAS,GAAc,QAAQ,GAAG,CAAC,MAAM,KAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAOrE,CAAC;AAEF,QAAA,MAAM,WAAW,GAAI,CAAC,SAAS,GAAG,CAAC,MAAM,EAAE,QAAQ,GAAG,CAAC,MAAM,EAAE,MAAM,WAAW,CAAC,CAAC,CAAC,KAAG,CAAC,GAAG,IAQzF,CAAC;AAEF,QAAA,MAAM,kBAAkB,GAAI,QAAQ,GAAG,CAAC,MAAM,KAAG,GAAG,CAAC,UAAU,EAS9D,CAAC;AAsBF,QAAA,MAAM,KAAK,GAAc,WAAW,SAAS,KAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAYnE,CAAC;AAEF,QAAA,MAAM,QAAQ,GAAc,WAAW,SAAS,KAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAItE,CAAC;AAEF,QAAA,MAAM,OAAO,GAAI,WAAW,SAAS,EAAE,SAAS,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,KAAK,OAAO,KAAG,GAAG,CAAC,MAAM,EAUzF,CAAC;AAEF,OAAO,EACH,SAAS,EACT,WAAW,EACX,SAAS,EACT,QAAQ,EACR,WAAW,EACX,OAAO,EACP,UAAU,EACV,kBAAkB,EAClB,KAAK,EACL,QAAQ,EACR,KAAK,SAAS,GACjB,CAAC"}
1
+ {"version":3,"file":"traversal.d.ts","sourceRoot":"","sources":["../src/traversal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AAGpC;;;GAGG;AACH,KAAK,cAAc,GAAG,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC,eAAe,GAAG,GAAG,CAAC,aAAa,GAAG,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,UAAU,CAAC;AAC/G;;;;GAIG;AACH,KAAK,SAAS,GAAG,cAAc,GAAG,GAAG,CAAC,WAAW,GAAG,OAAO,SAAS,CAAC;AACrE,KAAK,WAAW,CAAC,CAAC,SAAS,MAAM,IAAI,QAAQ,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;AAE1E,sFAAsF;AACtF,QAAA,MAAM,SAAS,EAAE,OAAO,MAAiC,CAAC;AAK1D,QAAA,MAAM,UAAU,GAAI,QAAQ,GAAG,CAAC,MAAM,KAAG,OAA6B,CAAC;AAgCvE,QAAA,MAAM,QAAQ,GAAc,QAAQ,GAAG,CAAC,MAAM,KAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAOpE,CAAC;AAEF,QAAA,MAAM,WAAW,GAAc,QAAQ,GAAG,CAAC,MAAM,KAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAIvE,CAAC;AAEF,QAAA,MAAM,SAAS,GAAc,QAAQ,GAAG,CAAC,MAAM,KAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAOrE,CAAC;AAEF,QAAA,MAAM,WAAW,GAAI,CAAC,SAAS,MAAM,EAAE,QAAQ,GAAG,CAAC,MAAM,EAAE,MAAM,WAAW,CAAC,CAAC,CAAC,KAAG,CAAC,GAAG,IAQrF,CAAC;AAcF,QAAA,MAAM,kBAAkB,GAAI,QAAQ,GAAG,CAAC,MAAM,KAAG,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,EAKxE,CAAC;AAsBF,QAAA,MAAM,KAAK,GAAc,WAAW,SAAS,KAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAYnE,CAAC;AAEF,QAAA,MAAM,QAAQ,GAAc,WAAW,SAAS,KAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAItE,CAAC;AAEF,QAAA,MAAM,OAAO,GAAI,WAAW,SAAS,EAAE,SAAS,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,KAAK,OAAO,KAAG,GAAG,CAAC,MAAM,EAUzF,CAAC;AAEF,OAAO,EACH,SAAS,EACT,WAAW,EACX,SAAS,EACT,QAAQ,EACR,WAAW,EACX,OAAO,EACP,UAAU,EACV,kBAAkB,EAClB,KAAK,EACL,QAAQ,EACR,KAAK,SAAS,GACjB,CAAC"}
package/dist/traversal.js CHANGED
@@ -1,9 +1,21 @@
1
1
  import * as Gtk from "@gtkx/gi/gtk";
2
+ import { getClassType, getInstanceType, typeIsA } from "@gtkx/runtime";
2
3
  /** Container sentinel that widens a query to every toplevel window currently open. */
3
4
  const TOPLEVELS = Symbol("gtkx.toplevels");
5
+ const nativeWidgetTypes = new Map();
4
6
  const isApplication = (container) => container instanceof Gtk.Application;
5
7
  const isAnyWidget = () => true;
6
8
  const isOnScreen = (widget) => widget.getMapped();
9
+ const isNativeWidget = (widget) => {
10
+ const type = getInstanceType(widget);
11
+ const cached = nativeWidgetTypes.get(type);
12
+ if (cached !== undefined) {
13
+ return cached;
14
+ }
15
+ const isNative = typeIsA(type, getClassType(Gtk.Native));
16
+ nativeWidgetTypes.set(type, isNative);
17
+ return isNative;
18
+ };
7
19
  const traverseWidgetTree = function* (root, isIncluded) {
8
20
  if (isIncluded(root)) {
9
21
  yield root;
@@ -41,13 +53,19 @@ const ancestorFor = (widget, type) => {
41
53
  }
42
54
  return null;
43
55
  };
56
+ const mappedWidgets = function* (widget, isParentMapped) {
57
+ const isMapped = (isParentMapped || isNativeWidget(widget)) && isOnScreen(widget);
58
+ if (isMapped) {
59
+ yield widget;
60
+ }
61
+ for (const child of children(widget)) {
62
+ yield* mappedWidgets(child, isMapped);
63
+ }
64
+ };
44
65
  const relationCandidates = (widget) => {
45
- const pool = [...widget.listMnemonicLabels(), ...descendants(widget)];
46
66
  const root = widget.getRoot();
47
- if (root instanceof Gtk.Widget) {
48
- pool.push(...traverseWidgetTree(root, isAnyWidget));
49
- }
50
- return [...new Set(pool)];
67
+ const tree = root instanceof Gtk.Widget ? traverseWidgetTree(root, isAnyWidget) : [];
68
+ return [widget.listMnemonicLabels(), descendants(widget), tree];
51
69
  };
52
70
  const resolveRoot = (container) => {
53
71
  if (container instanceof Gtk.Widget) {
@@ -62,7 +80,7 @@ const resolveRoot = (container) => {
62
80
  if (container instanceof Gtk.ListItem || container instanceof Gtk.ListHeader) {
63
81
  return container.getChild();
64
82
  }
65
- return null;
83
+ throw new TypeError("Query container must resolve to a Gtk.Widget");
66
84
  };
67
85
  const roots = function* (container) {
68
86
  if (container === TOPLEVELS || isApplication(container)) {
@@ -76,7 +94,7 @@ const roots = function* (container) {
76
94
  };
77
95
  const traverse = function* (container) {
78
96
  for (const root of roots(container)) {
79
- yield* traverseWidgetTree(root, isOnScreen);
97
+ yield* mappedWidgets(root, true);
80
98
  }
81
99
  };
82
100
  const findAll = (container, isMatch) => {
@@ -1 +1 @@
1
- {"version":3,"file":"traversal.js","sourceRoot":"","sources":["../src/traversal.ts"],"names":[],"mappings":"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","sourcesContent":["import * as Gtk from \"@gtkx/gi/gtk\";\n\n/**\n * A scope that resolves to a single root widget: the widget itself, the widget a controller or\n * layout manager is attached to, or a list item's or header's child.\n */\ntype QueryContainer = Gtk.Widget | Gtk.EventController | Gtk.LayoutManager | Gtk.ListItem | Gtk.ListHeader;\n/**\n * A scope that queries and traversal can run against: a widget, an event\n * controller, a layout manager, a list item or header, an application, or the\n * sentinel representing all current toplevel windows.\n */\ntype Container = QueryContainer | Gtk.Application | typeof TOPLEVELS;\ntype WidgetClass<T extends Gtk.Widget> = abstract new (...args: never[]) => T;\n\n/** Container sentinel that widens a query to every toplevel window currently open. */\nconst TOPLEVELS: unique symbol = Symbol(\"gtkx.toplevels\");\n\nconst isApplication = (container: Container): container is Gtk.Application => container instanceof Gtk.Application;\nconst isAnyWidget = (): boolean => true;\nconst isOnScreen = (widget: Gtk.Widget): boolean => widget.getMapped();\n\nconst traverseWidgetTree = function* (\n root: Gtk.Widget,\n isIncluded: (widget: Gtk.Widget) => boolean,\n): Generator<Gtk.Widget> {\n if (isIncluded(root)) {\n yield root;\n }\n\n let child = root.getFirstChild();\n\n while (child) {\n yield* traverseWidgetTree(child, isIncluded);\n child = child.getNextSibling();\n }\n};\n\nconst children = function* (widget: Gtk.Widget): Generator<Gtk.Widget> {\n let child = widget.getFirstChild();\n\n while (child) {\n yield child;\n child = child.getNextSibling();\n }\n};\n\nconst descendants = function* (widget: Gtk.Widget): Generator<Gtk.Widget> {\n const tree = traverseWidgetTree(widget, isAnyWidget);\n tree.next();\n yield* tree;\n};\n\nconst ancestors = function* (widget: Gtk.Widget): Generator<Gtk.Widget> {\n let parent = widget.getParent();\n\n while (parent) {\n yield parent;\n parent = parent.getParent();\n }\n};\n\nconst ancestorFor = <T extends Gtk.Widget>(widget: Gtk.Widget, type: WidgetClass<T>): T | null => {\n for (const ancestor of ancestors(widget)) {\n if (ancestor instanceof type) {\n return ancestor;\n }\n }\n\n return null;\n};\n\nconst relationCandidates = (widget: Gtk.Widget): Gtk.Accessible[] => {\n const pool: Gtk.Accessible[] = [...widget.listMnemonicLabels(), ...descendants(widget)];\n const root = widget.getRoot();\n\n if (root instanceof Gtk.Widget) {\n pool.push(...traverseWidgetTree(root, isAnyWidget));\n }\n\n return [...new Set(pool)];\n};\n\nconst resolveRoot = (container: QueryContainer): Gtk.Widget | null => {\n if (container instanceof Gtk.Widget) {\n return container;\n }\n\n if (container instanceof Gtk.EventController) {\n return container.getWidget();\n }\n\n if (container instanceof Gtk.LayoutManager) {\n return container.getWidget();\n }\n\n if (container instanceof Gtk.ListItem || container instanceof Gtk.ListHeader) {\n return container.getChild();\n }\n\n return null;\n};\n\nconst roots = function* (container: Container): Generator<Gtk.Widget> {\n if (container === TOPLEVELS || isApplication(container)) {\n yield* Gtk.Window.listToplevels();\n\n return;\n }\n\n const root = resolveRoot(container);\n\n if (root) {\n yield root;\n }\n};\n\nconst traverse = function* (container: Container): Generator<Gtk.Widget> {\n for (const root of roots(container)) {\n yield* traverseWidgetTree(root, isOnScreen);\n }\n};\n\nconst findAll = (container: Container, isMatch: (node: Gtk.Widget) => boolean): Gtk.Widget[] => {\n const results: Gtk.Widget[] = [];\n\n for (const node of traverse(container)) {\n if (isMatch(node)) {\n results.push(node);\n }\n }\n\n return results;\n};\n\nexport {\n TOPLEVELS,\n ancestorFor,\n ancestors,\n children,\n descendants,\n findAll,\n isOnScreen,\n relationCandidates,\n roots,\n traverse,\n type Container,\n};\n"]}
1
+ {"version":3,"file":"traversal.js","sourceRoot":"","sources":["../src/traversal.ts"],"names":[],"mappings":"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","sourcesContent":["import * as Gtk from \"@gtkx/gi/gtk\";\nimport { getClassType, getInstanceType, typeIsA } from \"@gtkx/runtime\";\n\n/**\n * A scope that resolves to a single root widget: the widget itself, the widget a controller or\n * layout manager is attached to, or a list item's or header's child.\n */\ntype QueryContainer = Gtk.Accessible | Gtk.EventController | Gtk.LayoutManager | Gtk.ListItem | Gtk.ListHeader;\n/**\n * A scope that queries and traversal can run against: a widget, an event\n * controller, a layout manager, a list item or header, an application, or the\n * sentinel representing all current toplevel windows.\n */\ntype Container = QueryContainer | Gtk.Application | typeof TOPLEVELS;\ntype WidgetClass<T extends object> = abstract new (...args: never[]) => T;\n\n/** Container sentinel that widens a query to every toplevel window currently open. */\nconst TOPLEVELS: unique symbol = Symbol(\"gtkx.toplevels\");\nconst nativeWidgetTypes: Map<bigint, boolean> = new Map();\n\nconst isApplication = (container: Container): container is Gtk.Application => container instanceof Gtk.Application;\nconst isAnyWidget = (): boolean => true;\nconst isOnScreen = (widget: Gtk.Widget): boolean => widget.getMapped();\n\nconst isNativeWidget = (widget: Gtk.Widget): boolean => {\n const type = getInstanceType(widget);\n const cached = nativeWidgetTypes.get(type);\n\n if (cached !== undefined) {\n return cached;\n }\n\n const isNative = typeIsA(type, getClassType(Gtk.Native));\n nativeWidgetTypes.set(type, isNative);\n\n return isNative;\n};\n\nconst traverseWidgetTree = function* (\n root: Gtk.Widget,\n isIncluded: (widget: Gtk.Widget) => boolean,\n): Generator<Gtk.Widget> {\n if (isIncluded(root)) {\n yield root;\n }\n\n let child = root.getFirstChild();\n\n while (child) {\n yield* traverseWidgetTree(child, isIncluded);\n child = child.getNextSibling();\n }\n};\n\nconst children = function* (widget: Gtk.Widget): Generator<Gtk.Widget> {\n let child = widget.getFirstChild();\n\n while (child) {\n yield child;\n child = child.getNextSibling();\n }\n};\n\nconst descendants = function* (widget: Gtk.Widget): Generator<Gtk.Widget> {\n const tree = traverseWidgetTree(widget, isAnyWidget);\n tree.next();\n yield* tree;\n};\n\nconst ancestors = function* (widget: Gtk.Widget): Generator<Gtk.Widget> {\n let parent = widget.getParent();\n\n while (parent) {\n yield parent;\n parent = parent.getParent();\n }\n};\n\nconst ancestorFor = <T extends object>(widget: Gtk.Widget, type: WidgetClass<T>): T | null => {\n for (const ancestor of ancestors(widget)) {\n if (ancestor instanceof type) {\n return ancestor;\n }\n }\n\n return null;\n};\n\nconst mappedWidgets = function* (widget: Gtk.Widget, isParentMapped: boolean): Generator<Gtk.Widget> {\n const isMapped = (isParentMapped || isNativeWidget(widget)) && isOnScreen(widget);\n\n if (isMapped) {\n yield widget;\n }\n\n for (const child of children(widget)) {\n yield* mappedWidgets(child, isMapped);\n }\n};\n\nconst relationCandidates = (widget: Gtk.Widget): Iterable<Gtk.Accessible>[] => {\n const root = widget.getRoot();\n const tree: Iterable<Gtk.Accessible> = root instanceof Gtk.Widget ? traverseWidgetTree(root, isAnyWidget) : [];\n\n return [widget.listMnemonicLabels(), descendants(widget), tree];\n};\n\nconst resolveRoot = (container: QueryContainer): Gtk.Widget | null => {\n if (container instanceof Gtk.Widget) {\n return container;\n }\n\n if (container instanceof Gtk.EventController) {\n return container.getWidget();\n }\n\n if (container instanceof Gtk.LayoutManager) {\n return container.getWidget();\n }\n\n if (container instanceof Gtk.ListItem || container instanceof Gtk.ListHeader) {\n return container.getChild();\n }\n\n throw new TypeError(\"Query container must resolve to a Gtk.Widget\");\n};\n\nconst roots = function* (container: Container): Generator<Gtk.Widget> {\n if (container === TOPLEVELS || isApplication(container)) {\n yield* Gtk.Window.listToplevels();\n\n return;\n }\n\n const root = resolveRoot(container);\n\n if (root) {\n yield root;\n }\n};\n\nconst traverse = function* (container: Container): Generator<Gtk.Widget> {\n for (const root of roots(container)) {\n yield* mappedWidgets(root, true);\n }\n};\n\nconst findAll = (container: Container, isMatch: (node: Gtk.Widget) => boolean): Gtk.Widget[] => {\n const results: Gtk.Widget[] = [];\n\n for (const node of traverse(container)) {\n if (isMatch(node)) {\n results.push(node);\n }\n }\n\n return results;\n};\n\nexport {\n TOPLEVELS,\n ancestorFor,\n ancestors,\n children,\n descendants,\n findAll,\n isOnScreen,\n relationCandidates,\n roots,\n traverse,\n type Container,\n};\n"]}