Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 14 additions & 34 deletions docs/src/content/docs/features/windows/multiple.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ func CreateToolPalette(app *application.Application) *application.WebviewWindow
}
```

### Pattern 4: Modal dialogs
### Pattern 4: Modal dialogs (macOS only)

Child windows that block parent:

Expand All @@ -303,14 +303,7 @@ func ShowModaldialog(parent *application.WebviewWindow, title string) {
Resizable: false,
})

// Disable parent (platform-specific)
parent.SetEnabled(false)

// Re-enable parent on close
dialog.OnDestroy(func() {
parent.SetEnabled(true)
parent.SetFocus()
})
parent.AttachModal(dialog)
}
```

Expand Down Expand Up @@ -359,51 +352,38 @@ func (e *EditorApp) TogglePreview() {
```go
childWindow := app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Child Window",
Parent: parentWindow,
})

parentWindow.AttachModal(childWindow)
```

**Behaviour:**
- Child closes when parent closes
- Child stays above parent (on some platforms)
- Child minimises with parent (on some platforms)
- Child stays above parent
- Child moves with parent
- Child blocks interaction to parent

**Platform support:**

| Feature | macOS | Windows | Linux |
|---------|-------|---------|-------|
| Auto-close | ✅ | ✅ | ⚠️ Varies |
| Stay above | ✅ | ⚠️ Partial | ⚠️ Varies |
| Minimise together | ✅ | ❌ | ⚠️ Varies |
| macOS | Windows | Linux |
|-------|---------|-------|
| ✅ | ❌ | ❌ |

### Modal Behaviour

Create modal-like behaviour:

```go
func ShowModal(parent *application.WebviewWindow) {
modal := app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "Modal dialog",
func ShowModaldialog(parent *application.WebviewWindow, title string) {
dialog := app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: title,
Width: 400,
Height: 200,
Parent: parent,
AlwaysOnTop: true,
})

// Disable parent interaction
parent.SetEnabled(false)

// Re-enable on close
modal.OnClose(func() bool {
parent.SetEnabled(true)
parent.SetFocus()
return true
})
parent.AttachModal(dialog)
}
```

**Note:** True modal behaviour (blocking) varies by platform.

## Window Lifecycle Management

### Creation Callbacks
Expand Down
23 changes: 19 additions & 4 deletions docs/src/content/docs/reference/window.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -597,12 +597,27 @@ if err != nil {
}
```

### AttachModal()

Attaches a second Window as a sheet modal.

```go
func (w *Window) AttachModal(modalWindow Window)
```

**Parameters:**
- `modalWindow` - The window to attach as a modal

**Platform support:**
- **macOS**: Full support
- **Windows**: Full support
- **Linux**: Full support
- **macOS**: Full support (presents as a sheet)
- **Windows**: No support
- **Linux**: No support

**Note:** This triggers the native OS print dialog, allowing the user to select printer settings and print the current window content.
**Example:**
```go
modalWindow := app.Window.NewWebviewWindow()
window.AttachModal(modalWindow)
```

## Complete Example

Expand Down
1 change: 1 addition & 0 deletions v3/UNRELEASED_CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ After processing, the content will be moved to the main changelog and this file

## Added
<!-- New features, capabilities, or enhancements -->
- Add support for modal sheets (macOS)

## Changed
<!-- Changes in existing functionality -->
Expand Down
17 changes: 17 additions & 0 deletions v3/pkg/application/webview_window.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ type (
setMenu(menu *Menu)
snapAssist()
setContentProtection(enabled bool)
attachModal(modalWindow *WebviewWindow)
}
)

Expand Down Expand Up @@ -1265,6 +1266,22 @@ func (w *WebviewWindow) NativeWindow() unsafe.Pointer {
return w.impl.nativeWindow()
}

// AttachModal attaches a modal window to this window, presenting it as a sheet on macOS.
func (w *WebviewWindow) AttachModal(modalWindow Window) {
if w.impl == nil || w.isDestroyed() {
return
}

modalWebviewWindow, ok := modalWindow.(*WebviewWindow)
if !ok || modalWebviewWindow == nil {
return
}

InvokeSync(func() {
w.impl.attachModal(modalWebviewWindow)
})
}

// shouldUnconditionallyClose returns whether the window should close unconditionally
func (w *WebviewWindow) shouldUnconditionallyClose() bool {
return atomic.LoadUint32(&w.unconditionallyClose) != 0
Expand Down
4 changes: 4 additions & 0 deletions v3/pkg/application/webview_window_android.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,10 @@ func (w *androidWebviewWindow) nativeWindow() unsafe.Pointer {
return nil
}

func (w *androidWebviewWindow) attachModal(modalWindow *WebviewWindow) {
// Modal windows are not supported on Android
}

func (w *androidWebviewWindow) on(eventID uint) {
// Android event handling
}
Expand Down
26 changes: 26 additions & 0 deletions v3/pkg/application/webview_window_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,21 @@ void windowZoomOut(void* nsWindow) {
}
}

// createModalWindow presents a modal window as a sheet attached to the parent window
void createModalWindow(void* parentWindowPtr, void* modalWindowPtr) {
if (parentWindowPtr == NULL || modalWindowPtr == NULL) {
return;
}

NSWindow* parentWindow = (NSWindow*)parentWindowPtr;
NSWindow* modalWindow = (NSWindow*)modalWindowPtr;

// Present the modal window as a sheet attached to the parent window
[parentWindow beginSheet:modalWindow completionHandler:^(NSModalResponse returnCode) {
// Sheet was dismissed - window will be released automatically
}];
}

// set the window position relative to the screen
void windowSetRelativePosition(void* nsWindow, int x, int y) {
WebviewWindow* window = (WebviewWindow*)nsWindow;
Expand Down Expand Up @@ -1516,6 +1531,17 @@ func (w *macosWebviewWindow) setContentProtection(enabled bool) {
C.setContentProtection(w.nsWindow, C.bool(enabled))
}

func (w *macosWebviewWindow) attachModal(modalWindow *WebviewWindow) {
if modalWindow == nil || modalWindow.impl == nil || modalWindow.isDestroyed() {
return
}
modalNativeWindow := modalWindow.impl.nativeWindow()
if modalNativeWindow == nil {
return
}
C.createModalWindow(w.nsWindow, modalNativeWindow)
}

func (w *macosWebviewWindow) cut() {
}

Expand Down
4 changes: 4 additions & 0 deletions v3/pkg/application/webview_window_ios.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,10 @@ func (w *iosWebviewWindow) nativeWindow() unsafe.Pointer {
return w.nativeHandle
}

func (w *iosWebviewWindow) attachModal(modalWindow *WebviewWindow) {
// Modal windows are supported on iOS
}

func (w *iosWebviewWindow) on(eventID uint) {
// iOS event handling
}
Expand Down
4 changes: 4 additions & 0 deletions v3/pkg/application/webview_window_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,10 @@ func (w *linuxWebviewWindow) nativeWindow() unsafe.Pointer {
return unsafe.Pointer(w.window)
}

func (w *linuxWebviewWindow) attachModal(modalWindow *WebviewWindow) {
// Modal windows are not supported on Linux
}

func (w *linuxWebviewWindow) print() error {
w.execJS("window.print();")
return nil
Expand Down
4 changes: 4 additions & 0 deletions v3/pkg/application/webview_window_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,10 @@ func (w *windowsWebviewWindow) startDrag() error {
return nil
}

func (w *windowsWebviewWindow) attachModal(modalWindow *WebviewWindow) {
// Modal windows are not supported on Windows
}

func (w *windowsWebviewWindow) nativeWindow() unsafe.Pointer {
return unsafe.Pointer(w.hwnd)
}
Expand Down
1 change: 1 addition & 0 deletions v3/pkg/application/window.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ type Window interface {
Flash(enabled bool)
Print() error
RegisterHook(eventType events.WindowEventType, callback func(event *WindowEvent)) func()
AttachModal(modalWindow Window)
shouldUnconditionallyClose() bool

// Editing methods
Expand Down
Loading