# Java

Source: https://docs.interop.io/desktop/capabilities/windows/window-management/java/index.html

## io.Connect Windows

In order for windows created from an external Java apps to become io.Connect Windows, they must first be registered via the Java Window Management API.

### Registering Swing Windows

The Window Management API is accessible via `io.windows()`.

Currently, io.Connect Windows requires the underlying native handle (`hwnd` in the case of Windows) to be initialized and attached to the `JFrame` before the window can be registered. This is achieved internally through io.Connect Windows:

```java
WindowHandle<JFrame> handle = io.windows().getWindowHandle(frame);

Window myWindow =
    io.windows().register(handle)
        .thenAccept(window ->
            frame.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e)
                {
                    window.closeAsync();
                }
            }));
```

### Popup Behavior

When a Swing `JFrame` is registered as an io.Connect Window, the window is re-parented. This affects how Swing handles popup components such as `JPopupMenu` and `JComboBox` dropdowns.

#### Heavyweight Popups Enforcement

By default, Swing uses lightweight popups (rendered within the same window) when possible for better performance. However, lightweight popups don't function correctly in re-parented windows due to mouse event dispatching issues - clicks may be incorrectly routed to components behind the popup rather than to the popup itself.

To address this, the io.Connect framework automatically enforces heavyweight popups for all `JPopupMenu` components within
registered windows. Heavyweight popups are rendered in their own native window, which ensures proper event handling
after re-parenting.

This may affect:

- `JComboBox` dropdown lists
- `JPopupMenu` context menus
- Any custom popup menus

#### Popup Focusability

Additionally, the `focusable` property of popup menus is disabled when windows are re-parented. This prevents focus-related
issues that may occur when the parent window hierarchy of the popup has been modified. While this ensures reliable popup
behavior, it means that keyboard navigation within popups may behave differently than in windows that haven't been re-parented.

> ⚠️ *Note that these adjustments are applied automatically during window registration. If your app has specific popup requirements or you experience unexpected behavior, contact us for support.*

## Finding Windows

To retrieve a list of all available io.Connect Windows, use the `list()` method:

```java
List<Window> allWindows = io.windows().list();
```

## Window Operations

Once an app window is registered, io.Connect Windows will accept full control over the window position, size and visibility. The app shouldn't use native methods (e.g., Swing calls) to control the window as this will interfere with the io.Connect Window management.

The Java Window Management API allows you to control the following window properties:

### Mode

The [window mode](https://docs.interop.io/desktop/capabilities/windows/window-management/overview/index.md#window_modes) is controlled by the `mode` window option which can be specified in the app definition or during window registration:

```java
Window myWindow = io.windows().register(handle, options -> options.mode(WindowMode.FLAT));
```

### Title

The following example demonstrates how to set the window title during the window registration (this will ignore the title specified in the app definition):

```java
Window myWindow = io.windows().register(handle, options -> options.title("My Title"));
```

To change the window title dynamically, use the `changeTitle()` method of an io.Connect Window instance and pass the new title as an argument:

```java
myWindow.changeTitle("New Title");
```

### Bounds

To change the window bounds (position and size), use the `changeBounds()` method and pass a `Bounds` object as an argument. The `Bounds()` constructor accepts `x`, `y`, `width` and `height` arguments specifying the position and the size of the window on the screen in pixels:

```java
myWindow.changeBounds(new Bounds(10, 10, 400, 600));
```

### Channel

To change the Channel of the window, use the `changeChannel()` method and pass the name of the new Channel as an argument:

```java
myWindow.changeChannel("Green");
```

To instruct the window to leave the current Channel, pass `null` as an argument:

```java
myWindow.changeChannel(null);
```

### Visibility

To hide or show the window, use the `changeVisibility()` method. Changing the window visibility also affects its associated icon:

```java
myWindow.changeVisibility(false);
```

### State

To maximize the window, use the `maximize()` method:

```java
myWindow.maximize();
```

To minimize the window, use the `minimize()` method:

```java
myWindow.minimize();
```

To restore the window to its normal state, use the `restore()` method:

```java
myWindow.restore();
```

To collapse the window, use the `collapse()` method:

```java
myWindow.collapse();
```

To expand a collapsed window, use the `expand()` method:

```java
myWindow.expand();
```

### Focus

To focus the window, use the `focus()` method:

```java
myWindow.focus();
```

### Z-Order

Available since io.Connect Java 1.4.15

To set a window on top of the z-order, use the `onTopState()` method when supplying options for registering your window in the io.Connect framework:

```java
Window myWindow = io.windows().register(handle, options -> options.onTopState(WindowOnTopState.YES));
```

> ⚠️ *Note that using the `WindowOnTopState.YES` option will allow the io.Connect Window to be on top only until the window is visible and not joined to an io.Connect Window group. If the window is hidden programmatically or the user snaps it to another io.Connect Window or window group, it will no longer be on top of the z-order when it becomes visible or when the user tears it off from the group.*

To instruct the window to remain permanently on top of the z-order, regardless of changes to its visibility or whether it joins or leaves an io.Connect Window group, use the `WindowOnTopState.ALWAYS` option:

```java
Window myWindow = io.windows().register(handle, options -> options.onTopState(WindowOnTopState.ALWAYS));
```

To remove any z-order preferences for the window, use the `WindowOnTopState.NO` option:

```java
Window myWindow = io.windows().register(handle, options -> options.onTopState(WindowOnTopState.NO));
```

## Context

Each io.Connect Window has a dedicated context. The window context is a `Map<String, Object>` object which may contain any information regarding the window instance in the form of key/value pairs.

Contexts can be set initially on window creation and updated dynamically. Context changes can be tracked by subscribing to an event which fires when the window context has been updated (see [Events > Context](#events-context)).

> ⚠️ *Note that saving large volumes of custom data as window context (e.g., thousands of lines of table data) can lead to significant delays. A user usually has several (in some cases - many) running apps and Workspaces (which can also contain many apps) and if one or more of the apps saves large amounts of context data, this will significantly slow down the saving process (e.g., on shutdown or when saving a Layout). Saving custom context works best with smaller amounts of data. If your app needs to save large amounts of data, you have to think about how to design this process better - for instance, you may store IDs, indices, etc., as context data, save the actual data to a database, and when you restore the app, fetch the data using the data IDs saved as window context.*

To update the context of an io.Connect Window, use the `changeContext()` method and provide the new context object as an argument:

```java
Map<String, Object> context = new LinkedHashMap<>();
context.put("RIC", "BMW.GR");
context.put("ClientID", 235399);
context.put("AccountID", "X2343");

myWindow.changeContext(context);
```

## Frame Buttons

You can add extra buttons in the frame area of the window and [handle clicks](#events-frame_buttons) for them.

### Adding Buttons

To add a new button to the window frame, use the `addFrameButton()` method:

```java
myWindow.addFrameButton(
                "search-button",
                ButtonOptions.builder()
                    .toolTip("Search")
                    .order(1)
                    .image(new byte[0]) // Must be a valid image.
                    .build())
            .thenRun(() -> System.out.println("Created a frame button."));
```

### Removing Buttons

To remove a button from the window frame, use the `removeFrameButton()` method:

```java
myWindow.removeFrameButton("search-button")
            .thenRun(() -> System.out.println("Removed a frame button."));
```

### System Buttons

Available since io.Connect Java 1.4.17

To enable or disable the default io.Connect system buttons, use the `windowButtons()` method when supplying options for registering your window in the io.Connect framework:

```java
Window myWindow =
    io.windows()
        .register(handle, options -> {
            options.windowButtons(
                WindowButtons.builder()
                                .allowClose(true)
                                .allowCollapse(false)
                                .allowLockUnlock(true)
                                .allowMaximize(false)
                                .allowMinimize(false)
                                .build()
            )});
```

To retrieve the current configuration of system buttons, use the `getButtons()` method:

```java
WindowButtons systemButtons = myWindow.getButtons();
```

To provide a new configuration for the system buttons, use the `resetButtons()` method and pass a `WindowButtons` object as an argument:

```java
myWindow.resetButtons(
            WindowButtons.builder()
                            .allowClose(true)
                            .allowMaximize(true)
                            .allowMinimize(true)
                            .build());
```

## Events

The Java Window Management API offers methods for handling io.Connect Window events related to changes of the window title, bounds, visibility, context and more. All subscription methods return an object that can be used to unsubscribe from the respective event.

### Title

To subscribe for changes of the window title, use the `onTitleChanged()` method:

```java
myWindow.onTitleChanged(e -> System.out.println("Window title changed to: " + e.getTitle()));
```

### Bounds

To subscribe for changes of the window bounds, use the `onBoundsChanged()` method:

```java
myWindow.onBoundsChanged(e -> System.out.println("Window bounds changed to: " + e.getBounds()));
```

### Visibility

To subscribe for changes of the window visibility, use the `onVisibilityChanged()` method:

```java
myWindow.onVisibilityChanged(e -> System.out.println("Window is now " + (e.isVisible() ? "visible." : "hidden.")));
```

### State

To subscribe for changes of the window state, use the `onStateChanged()` method:

```java
myWindow.onStateChanged(e -> System.out.println("Window state changed to " + e.getState()));
```

### Focus

To subscribe for changes of the window focus, use the `onFocusChanged()` method:

```java
myWindow.onFocusChanged(e -> System.out.println("Window " + (e.isFocused() ? "is now on focus." : "has lost focus.")));
```

### Context

To subscribe for updates of the window context, use the `onContextUpdated()` method:

```java
myWindow.onContextUpdated(e -> System.out.println("Window context updated: " + e.getContext()));
```

### Frame Buttons

To subscribe for clicks on any [frame buttons](#frame_buttons) you may have added to the window, use the `onFrameButtonClicked()` method:

```java
myWindow.onFrameButtonClicked(e -> {
    if ("search-button".equals(e.getButtonId())) {
        System.out.println("Search button clicked.");
    }
});
```

### Close

Available since io.Connect Java 1.4.16

To prevent an io.Connect Window from closing, use the `onClosing()` method. The event handler callback must return asynchronously a `PreventClosingOptions` object whose methods you can use to specify the behavior of a window that is about to be closed.

The following example demonstrates how to prevent the window from closing and show a confirmation dialog to the user:

```java
myWindow.onClosing(() → CompletableFuture.supplyAsync(PreventClosingOptions :: dialog));
```

The `PreventClosingOptions` object has the following methods:

| Method | Description |
|--------|-------------|
| `allow()` | Will allow the window to close. |
| `dialog()` | Will prevent the window from closing and will show a confirmation dialog to the user. |
| `prevent()` | Will prevent the window from closing. |
