- Qt 6.7
- Qt Wayland Compositor
- Qt Wayland Compositor Examples
- IVI Compositor
- Qt Wayland Compositor | Commercial or GPLv3

# IVI Compositor

IVI Compositor is an example that demonstrates how to use the IviApplication extension.

#### Introduction

This example demonstrates using the IviApplication shell extension in a Wayland display server (also known as a Wayland compositor).

For an introduction to the basic principles of creating a Qt Wayland Compositor with Qt, see the Minimal QML example.

#### The Protocol

IviApplication is a shell extension that was designed specifically for making In-vehice Infotainment systems.

It is a minimalistic protocol, and only provides the following functionality:

1. The client can identify itself with an IVI-id.
2. The server can request that the client resizes itself.

##### The Identification Numbers

In a typical IviApplication setup, you will have a predefined set of applications that can connect to the server. Since these applications are already known when the system is designed, they can be assigned hardcoded numbers that identify them. Given that the client and server agree on these numbers ahead of time, semantics can be built into the ID numbers.

For instance, if a client identifies itself as the navigation application, the server can recognize this and allocate a large, centered part of the screen for its window. An application identifying itself as a clock, on the other hand, might be delegated to a smaller area in the margins of the screen.

By default, Qt applications will advertise their system PIDs ("process IDs") as the IVI-id. The client can override this by setting `QT_IVI_SURFACE_ID` in its environment before connecting to the server.

#### The Example

A Qt Wayland Compositor may support multiple shell extensions at once, but the IVICompositor example only supports the IviApplication protocol. This means that the clients have to also support this shell extension in order to connect to the server.

The compositor window in the example is split into two horizontally: A left area which is designated for a specialized application with the id "1337", and a right area which is for all other applications.

##### Creating the Layout

The layout of the window is created inside a WaylandOutput. This typically corresponds to a physical screen available to the compositor. If a single WaylandOutput is created, as in the IVICompositor example, it will usually correspond to the primary screen.

     WaylandOutput {
         sizeFollowsWindow: true
         window: Window {
             width: 1024
             height: 768
             visible: true
             Rectangle {
                 id: leftArea
                 width: parent.width / 2
                 height: parent.height
                 anchors.left: parent.left
                 color: "cornflowerblue"
                 Text {
                     anchors.centerIn: parent
                     text: "Ivi surface with id 1337"
                 }
             }
             Rectangle {
                 id: rightArea
                 width: parent.width / 2
                 height: parent.height
                 anchors.right: parent.right
                 color: "burlywood"
                 Text {
                     anchors.centerIn: parent
                     text: "Other surfaces"
                 }
             }
         }
     }

The code creates a WaylandOutput for the screen and creates a Window on this as the top level container of all compositor contents. Inside this window, it creates two rectangles that will serve as containers for applications as they connect.

##### Connecting Clients

If no additional configuration has been done, a Qt application will connect with an IVI-id equal to its process ID. For instance, if we run another Qt example application with `-platform wayland`, it will be delegated to the right-hand side of the layout, granted that its ID is different from "1337".

However, if we set the `QT_IVI_SURFACE_ID` environment variable to "1337" before starting the example, it will be delegated to the left-hand side of the layout.

When a client connects to the `IVIApplication` interface, it will emit the `iviSurfaceCreated` signal. This is where the positioning of the application's surface is handled.

     IviApplication {
         onIviSurfaceCreated: (iviSurface) =>  {
             var surfaceArea = iviSurface.iviId === 1337 ? leftArea : rightArea;
             var item = chromeComponent.createObject(surfaceArea, { "shellSurface": iviSurface } );
             item.handleResized();
         }
     }

The `iviSurfaceCreated` signal receives an IviSurface argument which can be used to access the client's ID. The compositor then creates a ShellSurfaceItem for the surface (as defined by the `chromeComponent`). `ShellSurfaceItem` is the class used for placing shell surfaces into the Qt Quick scene, and you will see this same pattern in all the Qt Wayland Compositor examples.

What makes the IVICompositor example special is that it checks the `iviId` property of the incoming shell surface and decides on a parent for the ShellSurfaceItem depending on what this is. If the ID is equal to "1337" it will be parented to the `leftArea`, and if not it will be in the `rightArea`.

The implementation of the ShellSurfaceItem handles resizing by informing the client whenever the size changes (which can happen if the compositor is running inside a desktop-style windowing system and its window is resized).

     onWidthChanged: handleResized()
     onHeightChanged: handleResized()
     function handleResized() {
         if (width > 0 && height > 0)
             shellSurface.sendConfigure(Qt.size(width, height));
     }

The `sendConfigure()` method is defined in IviSurface and will send an event to the client. The client will receive a resize event with the new size, so it can relayout its contents.

If multiple applications connect to the same area in the layout, they will simply be stacked according to normal Qt Quick ordering rules. There are no built-in mechanisms for closing applications or managing state, but this can easily be added as ordinary Qt Quick code.

Example project @ code.qt.io