|
| 1 | +--- |
| 2 | +title: Kirigami with Rust |
| 3 | +weight: 3 |
| 4 | +group: setup |
| 5 | +description: > |
| 6 | + Create your first Kirigami application with Rust |
| 7 | +aliases: |
| 8 | + - /docs/getting-started/kirigami/setup-rust/ |
| 9 | +--- |
| 10 | + |
| 11 | +## Installing Kirigami |
| 12 | + |
| 13 | +Before getting started, we will need to install Kirigami and Rust on our machine. |
| 14 | + |
| 15 | +{{< installpackage |
| 16 | + arch="cargo cmake extra-cmake-modules kirigami breeze qqc2-desktop-style" |
| 17 | + opensuse="cargo cmake kf6-extra-cmake-modules kf6-kirigami-devel qt6-quickcontrols2-devel kf6-qqc2-desktop-style" |
| 18 | + fedora="cargo cmake extra-cmake-modules kf6-kirigami2-devel kf6-qqc2-desktop-style" >}} |
| 19 | + |
| 20 | +Further information for other distributions can be found [here](/docs/getting-started/building/help-dependencies). |
| 21 | + |
| 22 | +## Project structure |
| 23 | + |
| 24 | +First we create our project folder (you can use the commands below). We are going to call ours `kirigami_rust/`. This will be the project's structure: |
| 25 | + |
| 26 | +``` |
| 27 | +kirigami_rust/ |
| 28 | +├── CMakeLists.txt |
| 29 | +├── Cargo.toml |
| 30 | +├── build.rs |
| 31 | +├── org.kde.kirigami_rust.desktop |
| 32 | +└── src/ |
| 33 | + ├── main.rs |
| 34 | + └── qml/ |
| 35 | + └── Main.qml |
| 36 | +``` |
| 37 | + |
| 38 | +This project will use CMake to call Cargo, which in turn will build the project. |
| 39 | + |
| 40 | +{{< alert title="About CMake and Cargo" color="info" >}} |
| 41 | + |
| 42 | +This is **not** the traditional way of building a Rust project: technically, only Cargo is needed to build it, usually with `cargo build` and `cargo run`. |
| 43 | + |
| 44 | +For desktop applications however, CMake (or an equivalent like [Meson](https://mesonbuild.com/) used by GNOME or [Just](https://just.systems/man/en/introduction.html) used by COSMIC) is needed to install because Cargo lacks the necessary features to install GUI desktop applications. |
| 45 | + |
| 46 | +{{< /alert >}} |
| 47 | + |
| 48 | +The project will be called `kirigami_rust` and it will generate an executable called `kirigami_hello`. |
| 49 | + |
| 50 | +{{< alert title="💡 Tip" color="success" >}} |
| 51 | + |
| 52 | +You can quickly create this file structure with: `mkdir -p kirigami_rust/src/qml/`. |
| 53 | + |
| 54 | +{{< /alert >}} |
| 55 | + |
| 56 | +### org.kde.kirigami_rust.desktop {#desktop-file} |
| 57 | + |
| 58 | +The primary purpose of [Desktop Entry files](https://specifications.freedesktop.org/desktop-entry-spec/latest/) is to show your app on the application launcher on Linux. Another reason to have them is to have window icons on Wayland, as they are required to tell the compositor "this window goes with this icon". |
| 59 | + |
| 60 | +It must follow a [reverse-DNS naming scheme](https://en.wikipedia.org/wiki/Reverse_domain_name_notation) followed by the `.desktop` extension such as `org.kde.kirigami_rust.desktop`: |
| 61 | + |
| 62 | +{{< readfile file="/content/docs/getting-started/kirigami/setup-rust/org.kde.kirigami_rust.desktop" highlight="ini" >}} |
| 63 | + |
| 64 | +### CMakeLists.txt {#cmakelists} |
| 65 | + |
| 66 | +The `CMakeLists.txt` file is going to be used to run Cargo and to install the necessary files together with our application. It also provides certain quality of life features, such as making sure that Kirigami is installed during compilation and to signal Linux distributions to install the necessary dependencies with the application. |
| 67 | + |
| 68 | +{{< readfile file="/content/docs/getting-started/kirigami/setup-rust/CMakeLists.txt" highlight="cmake" >}} |
| 69 | + |
| 70 | +The first thing we do is add KDE's [Extra CMake Modules (ECM)](https://api.kde.org/ecm/manual/ecm.7.html) to our project so we can use [ecm_find_qml_module](https://api.kde.org/ecm/module/ECMFindQmlModule.html) to check that Kirigami is installed when trying to build the application, and if it's not, fail immediately. Another useful ECM feature is [ECMUninstallTarget](https://api.kde.org/ecm/module/ECMUninstallTarget.html), which allows to easily uninstall the application with CMake if desired. |
| 71 | + |
| 72 | +We also use CMake's [find_package()](https://cmake.org/cmake/help/latest/command/find_package.html) to make sure we have [qqc2-desktop-style](https://invent.kde.org/frameworks/qqc2-desktop-style), KDE's QML style for the desktop. This is one of the two reasons we use CMake in this tutorial. |
| 73 | + |
| 74 | +Typically Rust projects are built with Cargo, and it won't be different here. We create a target that will simply run Cargo when run, and mark it with `ALL` so it builds by default. Cargo will build the executable inside CMake's binary directory (typically `build/`). |
| 75 | + |
| 76 | +For more information about CMake, targets, and the binary directory, see [Building KDE software manually](/docs/getting-started/building/cmake-build). |
| 77 | + |
| 78 | +After this, we simply install the `kirigami_rust` executable generated by Cargo in the binary directory and install it to the `BINDIR`, which is usually `/usr/bin`, `/usr/local/bin` or `~/.local/bin`. We also install the necessary desktop file to `APPDIR`, which is usually `/usr/share/applications` or `~/.local/share/applications`. This is the second reason we use CMake in this tutorial. |
| 79 | + |
| 80 | +For more information about where KDE software is installed, see [Building KDE software manually: The install step](/docs/getting-started/building/cmake-build/#install). |
| 81 | + |
| 82 | +Now that CMake has been taken care of, let's look at the files we are going to spend the majority of our time working with. |
| 83 | + |
| 84 | +### Cargo.toml {#cargo-toml} |
| 85 | + |
| 86 | +Next we have a very straightforward `Cargo.toml`: |
| 87 | + |
| 88 | +{{< readfile file="/docs/getting-started/kirigami/setup-rust/Cargo.toml" highlight="toml" >}} |
| 89 | + |
| 90 | +It consists of project metadata and a list of dependencies that will be pulled automatically by Cargo, namely `cxx` and `cxx-qt`, which are necessary to run Qt applications written in Rust. |
| 91 | + |
| 92 | +### build.rs {#build-rs} |
| 93 | + |
| 94 | +Where in C++ you'd typically register QML elements with [QML_ELEMENT](https://doc.qt.io/qt-6/qtqml-cppintegration-definetypes.html) and [ecm_add_qml_module](https://api.kde.org/ecm/module/ECMQmlModule.html) using [declarative registration](https://www.qt.io/blog/qml-type-registration-in-qt-5.15), with Rust you'll need to declare it in a [build script build.rs](https://doc.rust-lang.org/cargo/reference/build-scripts.html) file: |
| 95 | + |
| 96 | +{{< readfile file="/docs/getting-started/kirigami/setup-rust/build.rs" highlight="rust" >}} |
| 97 | + |
| 98 | +This is necessary to make the QML file available in the entrypoint for our application, `main.rs`. |
| 99 | + |
| 100 | +### src/main.rs {#main-rs} |
| 101 | + |
| 102 | +The file `kirigami_rust/src/main.rs` initializes the project and then loads the QML file, which will consist of the user interface for the application. |
| 103 | + |
| 104 | +{{< readfile file="/content/docs/getting-started/kirigami/setup-rust/src/main.rs" highlight="rust" emphasize="12-13 17 28-30" >}} |
| 105 | + |
| 106 | +The first part that is marked with the [#[cxx_qt::bridge]](https://kdab.github.io/cxx-qt/book/bridge/index.html) Rust macro just creates a dummy QObject out of a dummy Rust struct. This is needed just to complete the use of [QmlModule](https://docs.rs/cxx-qt-build/latest/cxx_qt_build/struct.QmlModule.html) in the previous build script `build.rs`. This will play a larger part in a future tutorial teaching how to expose Rust code to QML, but for now you can ignore it. |
| 107 | + |
| 108 | +After this starts the important part: |
| 109 | + |
| 110 | +Lines 12-13 import the needed Qt libraries exposed through cxx-qt. |
| 111 | + |
| 112 | +We first create a new instance of a `QApplication`, then perform a few integrations in lines 20-26. |
| 113 | + |
| 114 | +Then comes the part that actually creates the application window: |
| 115 | + |
| 116 | +{{< readfile file="/content/docs/getting-started/kirigami/setup-rust/src/main.rs" highlight="rust" start=28 lines=3 >}} |
| 117 | + |
| 118 | +The long URL `qrc:/qt/qml/org/kde/tutorial/src/qml/Main.qml` corresponds to the `Main.qml` file according to the [Qt Resource System](https://doc.qt.io/qt-6/resources.html), and it follows this scheme: `<resource_prefix><import_URI><QML_dir><file>`. |
| 119 | + |
| 120 | +In other words: the default resource prefix `qrc:/qt/qml/` + the import URI `org/kde/tutorial` (set in `build.rs`, separated by slashes instead of dots) + the QML dir `src/qml/` + the QML file `Main.qml`. |
| 121 | + |
| 122 | +### src/qml/Main.qml {#main-qml} |
| 123 | + |
| 124 | +{{< readfile file="/content/docs/getting-started/kirigami/setup-rust/src/qml/Main.qml" highlight="qml" >}} |
| 125 | + |
| 126 | +Here's where we will be handling our application's frontend. |
| 127 | + |
| 128 | +If you know some Javascript, then much of QML will seem familiar to you (though it does have its own peculiarities). [Qt's documentation](https://doc.qt.io/qt-6/qtqml-index.html) has an extensive amount of material on this language if you feel like trying something on your own. Over the course of these tutorials we will be focusing much of our attention on our QML code, where we can use Kirigami to get the most out of it. |
| 129 | + |
| 130 | +For now, let's focus on `Main.qml`. First we [import](https://doc.qt.io/qt-6/qtqml-syntax-imports.html) a number of important modules: |
| 131 | + |
| 132 | +- [QtQuick](https://doc.qt.io/qt-6/qtquick-index.html), the standard library used in QML applications. |
| 133 | +- [QtQuick Controls](https://doc.qt.io/qt-6/qtquickcontrols-index.html), which provides a number of standard controls we can use to make our applications interactive. |
| 134 | +- [QtQuick Layouts](https://doc.qt.io/qt-6/qtquicklayouts-index.html), which provides tools for placing components within the application window. |
| 135 | +- [Kirigami](docs:kirigami2), which provides a number of components suited for creating applications that work across devices of different shapes and sizes. |
| 136 | + |
| 137 | +{{< alert title="Note" color="info">}} |
| 138 | + |
| 139 | +Putting the QtQuick Controls and Kirigami imports into separate namespaces using the `as` keyword is a best practice that ensures no components with the same name can conflict. You might see different names for QtQuick Controls in the wild, such as "QQC" or "QQC2". We will be using "Controls" in this tutorial for clarity. |
| 140 | + |
| 141 | +{{< /alert >}} |
| 142 | + |
| 143 | +We then come to our base element, [Kirigami.ApplicationWindow](docs:kirigami2;ApplicationWindow), which provides some basic features needed for all Kirigami applications. This is the window that will contain each of our pages, the main sections of our UI. |
| 144 | + |
| 145 | +We then set the window's `id` property to "root". IDs are useful because they let us uniquely reference a component, even if we have several of the same type. |
| 146 | + |
| 147 | +We also set the window `title` property to "Hello World". |
| 148 | + |
| 149 | +We then set the first page of our page stack. Most Kirigami applications are organised as a stack of pages, each page containing related components suited to a specific task. For now, we are keeping it simple, and sticking to a single page. [pageStack](docs:kirigami2;AbstractApplicationWindow::pageStack) is an initially empty stack of pages provided by [Kirigami.ApplicationWindow](docs:kirigami2;ApplicationWindow), and with `pageStack.initialPage: Kirigami.Page {...}` we set the first page presented upon loading the application to a [Kirigami.Page](docs:kirigami2;Page). This page will contain all our content. |
| 150 | + |
| 151 | +Finally, we include in our page a [Controls.Label](docs:qtquickcontrols;QtQuick.Controls.Label) that lets us place text on our page. We use `anchors.centerIn: parent` to center our label horizontally and vertically within our parent element. In this case, the parent component of our label is [Kirigami.Page](docs:kirigami2;Page). The last thing we need to do is set its text: `text: "Hello World!"`. |
| 152 | + |
| 153 | +## Compiling and installing the application {#build} |
| 154 | + |
| 155 | +You should find the generated executable `kirigami_hello` under `build/debug/kirigami_hello` and you may run it directly or with `cargo run`, but it will lack a Window icon. To address this, we'll install the application first. |
| 156 | + |
| 157 | +Run the following: |
| 158 | + |
| 159 | +```bash |
| 160 | +cmake -B build --install-prefix ~/.local |
| 161 | +cmake --build build/ |
| 162 | +cmake --install build/ |
| 163 | +``` |
| 164 | + |
| 165 | +With the first command, CMake will search for Kirigami and qqc2-desktop-style. |
| 166 | + |
| 167 | +With the second command, CMake will build the `kirigami_rust` target, which just calls `cargo build --target-dir build/`. This step will take a while to complete, but the next time you repeat the second CMake command it will be faster or you will not need to compile at all. |
| 168 | + |
| 169 | +In the third step, CMake will install the executable `kirigami_hello` under `~/.local/bin/kirigami_hello` and the desktop file under `~/.local/share/applications`, and a new entry named "Kirigami Tutorial in Rust" will appear on your menu. |
| 170 | + |
| 171 | +Open the menu entry and voilà! Now you will see your very first Kirigami app appear before your very own eyes. |
| 172 | + |
| 173 | + |
| 174 | + |
| 175 | +To run the new QML application in mobile mode, you can use `QT_QUICK_CONTROLS_MOBILE=1`: |
| 176 | + |
| 177 | +```bash |
| 178 | +QT_QUICK_CONTROLS_MOBILE=1 kirigami_hello |
| 179 | +``` |
| 180 | + |
| 181 | +If you have compiled the project manually with CMake and for some reason you'd like to uninstall the project, you can run: |
| 182 | + |
| 183 | +```bash |
| 184 | +cmake --build build/ --target uninstall |
| 185 | +``` |
| 186 | + |
0 commit comments