diff --git a/demos/WebViewAdoptPopupDemo/README.md b/demos/WebViewAdoptPopupDemo/README.md index bba3d38..c35a46f 100644 --- a/demos/WebViewAdoptPopupDemo/README.md +++ b/demos/WebViewAdoptPopupDemo/README.md @@ -32,6 +32,17 @@ and launches the demo. custom UA you set. - **window.open → popup** and the **target=_blank** link also open as tabs. - No native popup window appears at any point. + - **Teardown of an adopted tab** (Canvas 18 Op 10.3). Select an adopted + tab and click **Close tab**: the tab is removed and its + `WebViewComponent` is disposed, which destroys the native engine. The + button does nothing on the opener tab. Repeat several times with each + popup kind above. The app must keep running. + - **window.open → self-closing popup** opens an adopted tab with a + **window.close()** button. Click it (the page asks to close itself), + then close the tab with **Close tab**. Repeat several times. + - Run with `NSZombieEnabled=YES ./run-mac-adopt-popup-demo.sh` so a + message sent to a freed Objective-C object stops the app at once + instead of crashing it later. - **Native window** — the Canvas 15 behaviour: the popup opens in a separate native window (POST preserved, opener-linked). - **Block** — `window.open` returns `null`; the POST form submit is blocked. diff --git a/demos/WebViewAdoptPopupDemo/src/ca/weblite/webview/demos/WebViewAdoptPopupDemo.java b/demos/WebViewAdoptPopupDemo/src/ca/weblite/webview/demos/WebViewAdoptPopupDemo.java index 6f7cbe3..f539990 100644 --- a/demos/WebViewAdoptPopupDemo/src/ca/weblite/webview/demos/WebViewAdoptPopupDemo.java +++ b/demos/WebViewAdoptPopupDemo/src/ca/weblite/webview/demos/WebViewAdoptPopupDemo.java @@ -140,13 +140,14 @@ private static void buildUi() { }); opener.setUrl(openerPage()); - frame.add(buildControls(opener), java.awt.BorderLayout.NORTH); + frame.add(buildControls(opener, tabs), java.awt.BorderLayout.NORTH); addTab(tabs, "opener", opener); frame.add(tabs, java.awt.BorderLayout.CENTER); frame.setVisible(true); } - private static JPanel buildControls(WebViewComponent opener) { + private static JPanel buildControls(WebViewComponent opener, + JTabbedPane tabs) { // Canvas 21 Op 14.4: three rows, not one long FlowLayout line. A row // wider than the frame silently wraps its trailing components out of // view, and in a fixed-height row they become unreachable -- the @@ -206,6 +207,25 @@ private static JPanel buildControls(WebViewComponent opener) { }); bar.add(clearCache); + // Canvas 18 Op 10.3: close the selected ADOPTED tab and dispose it. + // Removing a heavyweight component from its parent does not destroy + // its native peer; dispose() is what reaches cocoa_destroy_engine, so + // this is the step that exercises an adopted child's teardown. The + // opener tab is never closed by this button. + JButton closeTab = new JButton("Close tab"); + closeTab.addActionListener(e -> { + java.awt.Component sel = tabs.getSelectedComponent(); + if (sel == null || sel == opener + || !(sel instanceof WebViewComponent)) { + System.out.println("[demo] Close tab: select an adopted tab"); + return; + } + tabs.remove(sel); + ((WebViewComponent) sel).dispose(); + System.out.println("[demo] closed and disposed an adopted tab"); + }); + bar.add(closeTab); + // Row 2: the User-Agent field takes the slack, its buttons pin right, // so the row's width never depends on the field's preferred size. JPanel uaRow = fieldRow("User-Agent:", uaField, setUa, resetUa); @@ -331,6 +351,15 @@ private static String openerPage() { + "window.open → popup" + "