or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

composables.mdcore-ui.mdgraphics.mdindex.mdinput.mdios-integration.mdlayout.mdmaterial-design.mdresources.mdstate.mdtext.mdwindow.md

window.mddocs/

0

# Window and Platform Management

1

2

Platform-specific window management and integration capabilities for Desktop, iOS, Android, and Web platforms, providing native-like application experiences across all supported targets.

3

4

## Capabilities

5

6

### Desktop Window Management

7

8

Comprehensive window management system for desktop applications with support for multiple windows, window states, and native platform integration.

9

10

```kotlin { .api }

11

/**

12

* Creates a single window application.

13

*/

14

@Composable

15

fun singleWindowApplication(

16

state: WindowState = rememberWindowState(),

17

visible: Boolean = true,

18

title: String = "Untitled",

19

icon: Painter? = null,

20

undecorated: Boolean = false,

21

transparent: Boolean = false,

22

resizable: Boolean = true,

23

enabled: Boolean = true,

24

focusable: Boolean = true,

25

alwaysOnTop: Boolean = false,

26

onPreviewKeyEvent: (KeyEvent) -> Boolean = { false },

27

onKeyEvent: (KeyEvent) -> Boolean = { false },

28

content: @Composable WindowScope.() -> Unit

29

)

30

31

/**

32

* Creates a window application with multiple windows.

33

*/

34

@Composable

35

fun application(

36

exitProcessOnExit: Boolean = true,

37

content: @Composable ApplicationScope.() -> Unit

38

)

39

40

/**

41

* Creates a window within an application.

42

*/

43

@Composable

44

fun ApplicationScope.Window(

45

onCloseRequest: () -> Unit,

46

state: WindowState = rememberWindowState(),

47

visible: Boolean = true,

48

title: String = "Untitled",

49

icon: Painter? = null,

50

undecorated: Boolean = false,

51

transparent: Boolean = false,

52

resizable: Boolean = true,

53

enabled: Boolean = true,

54

focusable: Boolean = true,

55

alwaysOnTop: Boolean = false,

56

onPreviewKeyEvent: (KeyEvent) -> Boolean = { false },

57

onKeyEvent: (KeyEvent) -> Boolean = { false },

58

content: @Composable WindowScope.() -> Unit

59

)

60

61

/**

62

* State holder for window properties.

63

*/

64

@Stable

65

class WindowState(

66

placement: WindowPlacement = WindowPlacement.Floating,

67

isMinimized: Boolean = false,

68

position: WindowPosition = WindowPosition.PlatformDefault,

69

size: DpSize = DpSize.Unspecified

70

) {

71

/**

72

* Current window placement mode.

73

*/

74

var placement: WindowPlacement by mutableStateOf(placement)

75

76

/**

77

* Whether the window is minimized.

78

*/

79

var isMinimized: Boolean by mutableStateOf(isMinimized)

80

81

/**

82

* Current window position.

83

*/

84

var position: WindowPosition by mutableStateOf(position)

85

86

/**

87

* Current window size.

88

*/

89

var size: DpSize by mutableStateOf(size)

90

}

91

92

/**

93

* Remember a WindowState across recompositions.

94

*/

95

@Composable

96

fun rememberWindowState(

97

placement: WindowPlacement = WindowPlacement.Floating,

98

isMinimized: Boolean = false,

99

position: WindowPosition = WindowPosition.PlatformDefault,

100

size: DpSize = DpSize.Unspecified

101

): WindowState

102

103

/**

104

* Window placement modes.

105

*/

106

enum class WindowPlacement {

107

Floating, Maximized, Fullscreen

108

}

109

110

/**

111

* Window position specification.

112

*/

113

sealed class WindowPosition {

114

object PlatformDefault : WindowPosition()

115

data class Absolute(val x: Dp, val y: Dp) : WindowPosition()

116

data class Aligned(val alignment: Alignment) : WindowPosition()

117

}

118

119

/**

120

* Size specification for windows.

121

*/

122

@Immutable

123

data class DpSize(

124

val width: Dp,

125

val height: Dp

126

) {

127

companion object {

128

val Unspecified: DpSize = DpSize(Dp.Unspecified, Dp.Unspecified)

129

val Zero: DpSize = DpSize(0.dp, 0.dp)

130

}

131

}

132

133

/**

134

* Scope for window content.

135

*/

136

interface WindowScope {

137

/**

138

* The current window state.

139

*/

140

val window: ComposeWindow

141

}

142

143

/**

144

* Scope for application content.

145

*/

146

interface ApplicationScope {

147

/**

148

* Exit the application.

149

*/

150

fun exitApplication()

151

}

152

```

153

154

**Usage Examples:**

155

156

```kotlin

157

// Single window application

158

fun main() = singleWindowApplication(

159

title = "My Desktop App",

160

state = rememberWindowState(

161

placement = WindowPlacement.Floating,

162

size = DpSize(800.dp, 600.dp),

163

position = WindowPosition.Aligned(Alignment.Center)

164

),

165

resizable = true,

166

icon = painterResource("app_icon.png")

167

) {

168

Column(

169

modifier = Modifier.fillMaxSize().padding(16.dp)

170

) {

171

Text("Desktop Application")

172

Button(onClick = {

173

window.close()

174

}) {

175

Text("Close Window")

176

}

177

}

178

}

179

180

// Multi-window application

181

fun main() = application {

182

var isSecondWindowVisible by remember { mutableStateOf(false) }

183

184

Window(

185

onCloseRequest = ::exitApplication,

186

title = "Main Window",

187

state = rememberWindowState(size = DpSize(600.dp, 400.dp))

188

) {

189

Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {

190

Text("Main Window")

191

Button(onClick = { isSecondWindowVisible = true }) {

192

Text("Open Second Window")

193

}

194

}

195

}

196

197

if (isSecondWindowVisible) {

198

Window(

199

onCloseRequest = { isSecondWindowVisible = false },

200

title = "Second Window",

201

state = rememberWindowState(

202

position = WindowPosition.Absolute(100.dp, 100.dp),

203

size = DpSize(400.dp, 300.dp)

204

)

205

) {

206

Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {

207

Text("Second Window")

208

Button(onClick = { isSecondWindowVisible = false }) {

209

Text("Close")

210

}

211

}

212

}

213

}

214

}

215

216

// Window with custom properties

217

fun main() = singleWindowApplication(

218

title = "Custom Window",

219

undecorated = true,

220

transparent = true,

221

alwaysOnTop = true,

222

state = rememberWindowState(

223

placement = WindowPlacement.Floating,

224

size = DpSize(300.dp, 200.dp)

225

)

226

) {

227

Box(

228

modifier = Modifier

229

.fillMaxSize()

230

.background(

231

Color.Black.copy(alpha = 0.8f),

232

RoundedCornerShape(8.dp)

233

)

234

) {

235

Text(

236

text = "Custom Window",

237

color = Color.White,

238

modifier = Modifier.align(Alignment.Center)

239

)

240

}

241

}

242

```

243

244

### iOS Platform Integration

245

246

Integration layer for iOS applications using UIKit interoperability and native iOS features.

247

248

```kotlin { .api }

249

/**

250

* Creates a UIViewController that hosts Compose content.

251

*/

252

fun ComposeUIViewController(

253

configure: ComposeUIViewControllerConfiguration = ComposeUIViewControllerConfiguration(),

254

content: @Composable () -> Unit

255

): UIViewController

256

257

/**

258

* Configuration for Compose UIViewController.

259

*/

260

class ComposeUIViewControllerConfiguration {

261

/**

262

* Whether the view controller should automatically adjust for safe areas.

263

*/

264

var automaticallyAdjustForSafeArea: Boolean = true

265

266

/**

267

* Background color for the view controller.

268

*/

269

var backgroundColor: UIColor? = null

270

271

/**

272

* Whether to use system gestures.

273

*/

274

var systemGestures: Boolean = true

275

276

/**

277

* Status bar style preference.

278

*/

279

var statusBarStyle: UIStatusBarStyle? = null

280

}

281

282

/**

283

* Access to iOS-specific platform features.

284

*/

285

object IOSPlatform {

286

/**

287

* Get the current safe area insets.

288

*/

289

val safeAreaInsets: EdgeInsets

290

291

/**

292

* Whether the device is in dark mode.

293

*/

294

val isDarkMode: Boolean

295

296

/**

297

* Current device orientation.

298

*/

299

val deviceOrientation: DeviceOrientation

300

301

/**

302

* Show/hide the status bar.

303

*/

304

fun setStatusBarHidden(hidden: Boolean, animated: Boolean = true)

305

306

/**

307

* Present a native iOS alert.

308

*/

309

suspend fun showAlert(

310

title: String,

311

message: String,

312

primaryButton: String = "OK",

313

secondaryButton: String? = null

314

): Boolean

315

}

316

317

/**

318

* Device orientation states.

319

*/

320

enum class DeviceOrientation {

321

Portrait, PortraitUpsideDown, LandscapeLeft, LandscapeRight, Unknown

322

}

323

324

/**

325

* Edge insets for safe areas.

326

*/

327

@Immutable

328

data class EdgeInsets(

329

val top: Dp,

330

val leading: Dp,

331

val bottom: Dp,

332

val trailing: Dp

333

)

334

335

/**

336

* CompositionLocal for accessing iOS platform features.

337

*/

338

val LocalIOSPlatform: ProvidableCompositionLocal<IOSPlatform>

339

```

340

341

**Usage Examples:**

342

343

```kotlin

344

// Basic iOS integration

345

fun createMainViewController() = ComposeUIViewController(

346

configure = ComposeUIViewControllerConfiguration().apply {

347

automaticallyAdjustForSafeArea = true

348

backgroundColor = UIColor.systemBackgroundColor

349

statusBarStyle = UIStatusBarStyle.UIStatusBarStyleDefault

350

}

351

) {

352

IOSApp()

353

}

354

355

@Composable

356

fun IOSApp() {

357

val platform = LocalIOSPlatform.current

358

val safeAreaInsets = platform.safeAreaInsets

359

360

Column(

361

modifier = Modifier

362

.fillMaxSize()

363

.padding(

364

top = safeAreaInsets.top,

365

bottom = safeAreaInsets.bottom,

366

start = safeAreaInsets.leading,

367

end = safeAreaInsets.trailing

368

)

369

) {

370

Text("iOS Application")

371

372

Button(onClick = {

373

// Show native iOS alert

374

coroutineScope.launch {

375

val result = platform.showAlert(

376

title = "Confirmation",

377

message = "Are you sure?",

378

primaryButton = "Yes",

379

secondaryButton = "No"

380

)

381

if (result) {

382

// User tapped "Yes"

383

}

384

}

385

}) {

386

Text("Show Alert")

387

}

388

389

Text("Dark mode: ${platform.isDarkMode}")

390

Text("Orientation: ${platform.deviceOrientation}")

391

}

392

}

393

394

// Custom iOS view controller integration

395

class CustomIOSViewController : UIViewController {

396

private val composeView = ComposeUIViewController {

397

MyComposeContent()

398

}

399

400

override fun viewDidLoad() {

401

super.viewDidLoad()

402

403

// Add Compose content as child view controller

404

addChild(composeView)

405

view.addSubview(composeView.view)

406

composeView.didMove(toParent = this)

407

408

// Setup constraints

409

composeView.view.translatesAutoresizingMaskIntoConstraints = false

410

NSLayoutConstraint.activate(listOf(

411

composeView.view.topAnchor.constraint(equalTo = view.safeAreaLayoutGuide.topAnchor),

412

composeView.view.leadingAnchor.constraint(equalTo = view.leadingAnchor),

413

composeView.view.trailingAnchor.constraint(equalTo = view.trailingAnchor),

414

composeView.view.bottomAnchor.constraint(equalTo = view.safeAreaLayoutGuide.bottomAnchor)

415

))

416

}

417

}

418

```

419

420

### Web Platform Integration

421

422

Web-specific window and platform features for Compose Multiplatform web applications.

423

424

```kotlin { .api }

425

/**

426

* Creates a Compose application for the web platform.

427

*/

428

fun CanvasBasedWindow(

429

canvasElementId: String? = null,

430

title: String = "Compose Application",

431

content: @Composable () -> Unit

432

)

433

434

/**

435

* Access to web-specific platform features.

436

*/

437

object WebPlatform {

438

/**

439

* The current browser window.

440

*/

441

val window: Window

442

443

/**

444

* The current document.

445

*/

446

val document: Document

447

448

/**

449

* Current viewport size.

450

*/

451

val viewportSize: IntSize

452

453

/**

454

* Whether the page is loaded via HTTPS.

455

*/

456

val isSecure: Boolean

457

458

/**

459

* Current page URL.

460

*/

461

val currentUrl: String

462

463

/**

464

* Navigate to a new URL.

465

*/

466

fun navigateTo(url: String)

467

468

/**

469

* Show a browser alert dialog.

470

*/

471

fun alert(message: String)

472

473

/**

474

* Show a browser confirmation dialog.

475

*/

476

fun confirm(message: String): Boolean

477

478

/**

479

* Download a file.

480

*/

481

fun downloadFile(data: ByteArray, fileName: String, mimeType: String = "application/octet-stream")

482

483

/**

484

* Copy text to clipboard.

485

*/

486

suspend fun copyToClipboard(text: String): Boolean

487

488

/**

489

* Read text from clipboard.

490

*/

491

suspend fun readFromClipboard(): String?

492

}

493

494

/**

495

* Browser storage access.

496

*/

497

object WebStorage {

498

/**

499

* Local storage operations.

500

*/

501

object Local {

502

fun setItem(key: String, value: String)

503

fun getItem(key: String): String?

504

fun removeItem(key: String)

505

fun clear()

506

val length: Int

507

}

508

509

/**

510

* Session storage operations.

511

*/

512

object Session {

513

fun setItem(key: String, value: String)

514

fun getItem(key: String): String?

515

fun removeItem(key: String)

516

fun clear()

517

val length: Int

518

}

519

}

520

521

/**

522

* CompositionLocal for accessing web platform features.

523

*/

524

val LocalWebPlatform: ProvidableCompositionLocal<WebPlatform>

525

```

526

527

**Usage Examples:**

528

529

```kotlin

530

// Web application setup

531

fun main() {

532

CanvasBasedWindow(

533

canvasElementId = "ComposeTarget",

534

title = "My Web App"

535

) {

536

WebApp()

537

}

538

}

539

540

@Composable

541

fun WebApp() {

542

val platform = LocalWebPlatform.current

543

var viewportSize by remember { mutableStateOf(platform.viewportSize) }

544

var clipboardContent by remember { mutableStateOf("") }

545

546

// Update viewport size on window resize

547

LaunchedEffect(Unit) {

548

// Listen for window resize events

549

platform.window.addEventListener("resize") {

550

viewportSize = platform.viewportSize

551

}

552

}

553

554

Column(

555

modifier = Modifier

556

.fillMaxSize()

557

.padding(16.dp)

558

) {

559

Text("Web Application")

560

Text("Viewport: ${viewportSize.width} x ${viewportSize.height}")

561

Text("URL: ${platform.currentUrl}")

562

Text("Secure: ${platform.isSecure}")

563

564

Spacer(modifier = Modifier.height(16.dp))

565

566

Row {

567

Button(onClick = {

568

platform.alert("Hello from Compose!")

569

}) {

570

Text("Show Alert")

571

}

572

573

Spacer(modifier = Modifier.width(8.dp))

574

575

Button(onClick = {

576

val confirmed = platform.confirm("Are you sure?")

577

if (confirmed) {

578

platform.alert("Confirmed!")

579

}

580

}) {

581

Text("Show Confirm")

582

}

583

}

584

585

Spacer(modifier = Modifier.height(16.dp))

586

587

// Clipboard operations

588

TextField(

589

value = clipboardContent,

590

onValueChange = { clipboardContent = it },

591

label = { Text("Clipboard content") },

592

modifier = Modifier.fillMaxWidth()

593

)

594

595

Row {

596

Button(onClick = {

597

coroutineScope.launch {

598

platform.copyToClipboard(clipboardContent)

599

}

600

}) {

601

Text("Copy to Clipboard")

602

}

603

604

Spacer(modifier = Modifier.width(8.dp))

605

606

Button(onClick = {

607

coroutineScope.launch {

608

val content = platform.readFromClipboard()

609

if (content != null) {

610

clipboardContent = content

611

}

612

}

613

}) {

614

Text("Read from Clipboard")

615

}

616

}

617

618

Spacer(modifier = Modifier.height(16.dp))

619

620

// File download

621

Button(onClick = {

622

val data = "Hello, World!".toByteArray()

623

platform.downloadFile(data, "hello.txt", "text/plain")

624

}) {

625

Text("Download File")

626

}

627

628

// Local storage operations

629

Button(onClick = {

630

WebStorage.Local.setItem("myKey", clipboardContent)

631

platform.alert("Saved to local storage!")

632

}) {

633

Text("Save to Local Storage")

634

}

635

636

Button(onClick = {

637

val stored = WebStorage.Local.getItem("myKey")

638

if (stored != null) {

639

clipboardContent = stored

640

}

641

}) {

642

Text("Load from Local Storage")

643

}

644

}

645

}

646

```

647

648

### Dialog and Modal Management

649

650

Cross-platform dialog and modal window management for user interactions and confirmations.

651

652

```kotlin { .api }

653

/**

654

* A modal dialog window.

655

*/

656

@Composable

657

fun Dialog(

658

onDismissRequest: () -> Unit,

659

properties: DialogProperties = DialogProperties(),

660

content: @Composable () -> Unit

661

)

662

663

/**

664

* Properties for configuring dialog behavior.

665

*/

666

@Immutable

667

data class DialogProperties(

668

val dismissOnBackPress: Boolean = true,

669

val dismissOnClickOutside: Boolean = true,

670

val securePolicy: SecureFlagPolicy = SecureFlagPolicy.Inherit,

671

val usePlatformDefaultWidth: Boolean = true,

672

val decorFitsSystemWindows: Boolean = true

673

)

674

675

/**

676

* Security policies for dialog windows.

677

*/

678

enum class SecureFlagPolicy {

679

Inherit, SecureOn, SecureOff

680

}

681

682

/**

683

* A popup window positioned relative to its parent.

684

*/

685

@Composable

686

fun Popup(

687

alignment: Alignment = Alignment.TopStart,

688

offset: IntOffset = IntOffset.Zero,

689

onDismissRequest: (() -> Unit)? = null,

690

properties: PopupProperties = PopupProperties(),

691

content: @Composable () -> Unit

692

)

693

694

/**

695

* Properties for configuring popup behavior.

696

*/

697

@Immutable

698

data class PopupProperties(

699

val focusable: Boolean = false,

700

val dismissOnBackPress: Boolean = true,

701

val dismissOnClickOutside: Boolean = true,

702

val securePolicy: SecureFlagPolicy = SecureFlagPolicy.Inherit,

703

val excludeFromSystemGesture: Boolean = true,

704

val clippingEnabled: Boolean = true,

705

val usePlatformDefaultWidth: Boolean = false

706

)

707

708

/**

709

* Desktop-specific file dialogs.

710

*/

711

object FileDialog {

712

/**

713

* Show a file chooser dialog.

714

*/

715

suspend fun openFileDialog(

716

title: String = "Open File",

717

allowedExtensions: List<String> = emptyList(),

718

allowMultiSelection: Boolean = false,

719

initialDirectory: String? = null

720

): List<String>?

721

722

/**

723

* Show a save file dialog.

724

*/

725

suspend fun saveFileDialog(

726

title: String = "Save File",

727

allowedExtensions: List<String> = emptyList(),

728

initialFileName: String? = null,

729

initialDirectory: String? = null

730

): String?

731

732

/**

733

* Show a directory chooser dialog.

734

*/

735

suspend fun openDirectoryDialog(

736

title: String = "Choose Directory",

737

initialDirectory: String? = null

738

): String?

739

}

740

```

741

742

**Usage Examples:**

743

744

```kotlin

745

// Basic dialog usage

746

@Composable

747

fun DialogExample() {

748

var showDialog by remember { mutableStateOf(false) }

749

750

Column {

751

Button(onClick = { showDialog = true }) {

752

Text("Show Dialog")

753

}

754

755

if (showDialog) {

756

Dialog(

757

onDismissRequest = { showDialog = false },

758

properties = DialogProperties(

759

dismissOnBackPress = true,

760

dismissOnClickOutside = true

761

)

762

) {

763

Card(

764

modifier = Modifier

765

.fillMaxWidth()

766

.padding(16.dp),

767

shape = RoundedCornerShape(16.dp)

768

) {

769

Column(

770

modifier = Modifier.padding(24.dp),

771

verticalArrangement = Arrangement.spacedBy(16.dp)

772

) {

773

Text(

774

text = "Dialog Title",

775

style = MaterialTheme.typography.h6

776

)

777

778

Text("This is the dialog content.")

779

780

Row(

781

modifier = Modifier.fillMaxWidth(),

782

horizontalArrangement = Arrangement.End

783

) {

784

TextButton(onClick = { showDialog = false }) {

785

Text("Cancel")

786

}

787

TextButton(onClick = { showDialog = false }) {

788

Text("OK")

789

}

790

}

791

}

792

}

793

}

794

}

795

}

796

}

797

798

// Popup window example

799

@Composable

800

fun PopupExample() {

801

var showPopup by remember { mutableStateOf(false) }

802

803

Box {

804

Button(onClick = { showPopup = !showPopup }) {

805

Text("Toggle Popup")

806

}

807

808

if (showPopup) {

809

Popup(

810

alignment = Alignment.TopEnd,

811

offset = IntOffset(0, 40),

812

onDismissRequest = { showPopup = false }

813

) {

814

Card(

815

modifier = Modifier.size(200.dp, 150.dp),

816

elevation = 8.dp

817

) {

818

Column(

819

modifier = Modifier.padding(16.dp),

820

verticalArrangement = Arrangement.spacedBy(8.dp)

821

) {

822

Text("Popup Content")

823

Text("Click outside to dismiss")

824

Button(onClick = { showPopup = false }) {

825

Text("Close")

826

}

827

}

828

}

829

}

830

}

831

}

832

}

833

834

// File dialog example (Desktop)

835

@Composable

836

fun FileDialogExample() {

837

var selectedFiles by remember { mutableStateOf<List<String>>(emptyList()) }

838

var saveLocation by remember { mutableStateOf<String?>(null) }

839

val coroutineScope = rememberCoroutineScope()

840

841

Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {

842

Button(onClick = {

843

coroutineScope.launch {

844

val files = FileDialog.openFileDialog(

845

title = "Select Images",

846

allowedExtensions = listOf("jpg", "png", "gif"),

847

allowMultiSelection = true

848

)

849

if (files != null) {

850

selectedFiles = files

851

}

852

}

853

}) {

854

Text("Open Files")

855

}

856

857

if (selectedFiles.isNotEmpty()) {

858

Text("Selected files:")

859

selectedFiles.forEach { file ->

860

Text("• $file", style = MaterialTheme.typography.body2)

861

}

862

}

863

864

Button(onClick = {

865

coroutineScope.launch {

866

val location = FileDialog.saveFileDialog(

867

title = "Save Document",

868

allowedExtensions = listOf("txt", "md"),

869

initialFileName = "document.txt"

870

)

871

saveLocation = location

872

}

873

}) {

874

Text("Save File")

875

}

876

877

saveLocation?.let { location ->

878

Text("Save location: $location")

879

}

880

881

Button(onClick = {

882

coroutineScope.launch {

883

val directory = FileDialog.openDirectoryDialog(

884

title = "Choose Output Directory"

885

)

886

if (directory != null) {

887

// Handle directory selection

888

}

889

}

890

}) {

891

Text("Choose Directory")

892

}

893

}

894

}

895

```