diff --git a/repos/gems/recipes/src/mixer_gui_qt6/content.mk b/repos/gems/recipes/src/mixer_gui_qt6/content.mk
new file mode 100644
index 0000000000..ad5460f053
--- /dev/null
+++ b/repos/gems/recipes/src/mixer_gui_qt6/content.mk
@@ -0,0 +1,17 @@
+MIRROR_FROM_REP_DIR := src/app/mixer_gui_qt6
+
+content: $(MIRROR_FROM_REP_DIR) LICENSE
+
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+MIRROR_FROM_OS := include/mixer
+
+content: $(MIRROR_FROM_OS)
+
+$(MIRROR_FROM_OS):
+ mkdir -p $(dir $@)
+ cp -r $(GENODE_DIR)/repos/os/$@ $(dir $@)
+
+LICENSE:
+ cp $(GENODE_DIR)/LICENSE $@
diff --git a/repos/gems/recipes/src/mixer_gui_qt6/hash b/repos/gems/recipes/src/mixer_gui_qt6/hash
new file mode 100644
index 0000000000..f05c20c295
--- /dev/null
+++ b/repos/gems/recipes/src/mixer_gui_qt6/hash
@@ -0,0 +1 @@
+2024-08-08 e0c80c1e04f8b05725ba904c9bd0f45d619e6d7b
diff --git a/repos/gems/recipes/src/mixer_gui_qt6/used_apis b/repos/gems/recipes/src/mixer_gui_qt6/used_apis
new file mode 100644
index 0000000000..ca22d1e4af
--- /dev/null
+++ b/repos/gems/recipes/src/mixer_gui_qt6/used_apis
@@ -0,0 +1,10 @@
+base
+libc
+mesa
+os
+qoost
+qt6_base
+qt6_component
+report_session
+stdcxx
+vfs
diff --git a/repos/gems/recipes/src/test-tiled_wm_qt6/content.mk b/repos/gems/recipes/src/test-tiled_wm_qt6/content.mk
new file mode 100644
index 0000000000..ede8c8dd04
--- /dev/null
+++ b/repos/gems/recipes/src/test-tiled_wm_qt6/content.mk
@@ -0,0 +1,9 @@
+MIRROR_FROM_REP_DIR := src/test/tiled_wm_qt6
+
+content: $(MIRROR_FROM_REP_DIR) LICENSE
+
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+LICENSE:
+ cp $(GENODE_DIR)/LICENSE $@
diff --git a/repos/gems/recipes/src/test-tiled_wm_qt6/hash b/repos/gems/recipes/src/test-tiled_wm_qt6/hash
new file mode 100644
index 0000000000..93ac717c66
--- /dev/null
+++ b/repos/gems/recipes/src/test-tiled_wm_qt6/hash
@@ -0,0 +1 @@
+2024-08-07 2a2c41fe5c6449c94e1346d9b7aeb6c525c7647f
diff --git a/repos/gems/recipes/src/test-tiled_wm_qt6/used_apis b/repos/gems/recipes/src/test-tiled_wm_qt6/used_apis
new file mode 100644
index 0000000000..d06f65433f
--- /dev/null
+++ b/repos/gems/recipes/src/test-tiled_wm_qt6/used_apis
@@ -0,0 +1,11 @@
+base
+libc
+mesa
+os
+qoost
+qt6_base
+qt6_component
+report_session
+stdcxx
+timer_session
+vfs
diff --git a/repos/gems/run/mixer_gui_qt6_test.run b/repos/gems/run/mixer_gui_qt6_test.run
new file mode 100644
index 0000000000..62542e1225
--- /dev/null
+++ b/repos/gems/run/mixer_gui_qt6_test.run
@@ -0,0 +1,83 @@
+source ${genode_dir}/repos/libports/run/qt6_common.inc
+
+import_from_depot [depot_user]/src/dynamic_rom \
+ [depot_user]/src/mixer_gui_qt6
+
+#
+# Generate config
+#
+
+install_config {
+
+
+ } [qt6_parent_provides] {
+
+
+
+
+
+ } [qt6_start_nodes] {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2018-01-01 00:01
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+build_boot_image [qt6_boot_modules]
+
+run_genode_until forever
+
+# vi: set ft=tcl :
diff --git a/repos/gems/run/tiled_wm_qt6.run b/repos/gems/run/tiled_wm_qt6.run
new file mode 100644
index 0000000000..fc6426f35a
--- /dev/null
+++ b/repos/gems/run/tiled_wm_qt6.run
@@ -0,0 +1,228 @@
+source ${genode_dir}/repos/libports/run/qt6_common.inc
+
+import_from_depot [depot_user]/src/qt6_component \
+ [depot_user]/src/qt6_textedit \
+ [depot_user]/src/dynamic_rom \
+ [depot_user]/src/test-tiled_wm_qt6
+
+#
+# Generate config
+#
+
+proc qt6_layouter_config { } {
+ return { }
+}
+
+proc qt6_decorator_binary { } { return "themed_decorator" }
+
+proc qt6_decorator_config { } {
+ return {
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+}
+
+install_config {
+
+ } [qt6_parent_provides] {
+
+
+
+
+ } [qt6_start_nodes] {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2018-01-01 00:01
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2018-01-01 00:01
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2018-01-01 00:01
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2018-01-01 00:01
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2018-01-01 00:01
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+build_boot_image [qt6_boot_modules]
+
+append qemu_args " -device nec-usb-xhci,id=xhci -device usb-tablet"
+
+run_genode_until forever
+
+# vi: set ft=tcl :
diff --git a/repos/gems/src/app/mixer_gui_qt6/main.cpp b/repos/gems/src/app/mixer_gui_qt6/main.cpp
new file mode 100644
index 0000000000..a14cb22bb8
--- /dev/null
+++ b/repos/gems/src/app/mixer_gui_qt6/main.cpp
@@ -0,0 +1,131 @@
+/*
+ * \brief Mixer frontend
+ * \author Josef Soentgen
+ * \date 2015-10-15
+ */
+
+/*
+ * Copyright (C) 2015-2020 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+
+/* Qt includes */
+#include
+#include
+#include
+
+/* qt6_component includes */
+#include
+
+/* application includes */
+#include "main_window.h"
+
+
+enum { SIGNAL_EP_STACK_SIZE = 16*1024 };
+
+
+struct Report_handler
+{
+ QMember proxy;
+
+ Genode::Attached_rom_dataspace channels_rom;
+
+ Genode::Entrypoint sig_ep;
+ Genode::Signal_handler channels_handler;
+
+ Genode::Blockade _report_blockade { };
+
+ bool window_connected { false };
+
+ void _report(char const *data, size_t size)
+ {
+ Genode::Xml_node node(data, size);
+ proxy->report_changed(&_report_blockade, &node);
+
+ /* wait until the report was handled */
+ _report_blockade.block();
+ }
+
+ void _handle_channels()
+ {
+ if (!window_connected)
+ return;
+
+ channels_rom.update();
+
+ if (channels_rom.valid())
+ _report(channels_rom.local_addr(), channels_rom.size());
+ }
+
+ Report_handler(Genode::Env &env)
+ :
+ channels_rom(env, "channel_list"),
+ sig_ep(env, SIGNAL_EP_STACK_SIZE, "signal ep",
+ Genode::Affinity::Location()),
+ channels_handler(sig_ep, *this, &Report_handler::_handle_channels)
+ {
+ channels_rom.sigh(channels_handler);
+ }
+
+ void connect_window(Main_window *win)
+ {
+ QObject::connect(proxy, SIGNAL(report_changed(void *,void const*)),
+ win, SLOT(report_changed(void *, void const*)),
+ Qt::QueuedConnection);
+
+ window_connected = true;
+ }
+};
+
+
+static inline void load_stylesheet()
+{
+ QFile file(":style.qss");
+ if (!file.open(QFile::ReadOnly)) {
+ qWarning() << "Warning:" << file.errorString()
+ << "opening file" << file.fileName();
+ return;
+ }
+
+ qApp->setStyleSheet(QLatin1String(file.readAll()));
+}
+
+
+void Libc::Component::construct(Libc::Env &env)
+{
+ Libc::with_libc([&] {
+
+ qpa_init(env);
+
+ int argc = 1;
+ char const *argv[] = { "mixer_gui_qt", 0 };
+
+ Report_handler *report_handler;
+ try { report_handler = new Report_handler(env); }
+ catch (...) {
+ Genode::error("Could not create Report_handler");
+ return -1;
+ }
+
+ QApplication app(argc, (char**)argv);
+
+ load_stylesheet();
+
+ QMember main_window(env);
+ main_window->show();
+
+ report_handler->connect_window(main_window);
+
+ app.connect(&app, SIGNAL(lastWindowClosed()), SLOT(quit()));
+
+ exit(app.exec());
+ });
+}
diff --git a/repos/gems/src/app/mixer_gui_qt6/main_window.cpp b/repos/gems/src/app/mixer_gui_qt6/main_window.cpp
new file mode 100644
index 0000000000..f4b16e3ab5
--- /dev/null
+++ b/repos/gems/src/app/mixer_gui_qt6/main_window.cpp
@@ -0,0 +1,463 @@
+/*
+ * \brief Main window of the mixer frontend
+ * \author Josef Soentgen
+ * \date 2015-10-15
+ */
+
+/*
+ * Copyright (C) 2015-2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+#include
+
+/* Qt includes */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* application includes */
+#include "main_window.h"
+
+
+/************
+ ** helper **
+ ************/
+
+using Channel = Mixer::Channel;
+
+static struct Names {
+ char const *name;
+ Channel::Number number;
+} names[] = {
+ { "left", Channel::Number::LEFT },
+ { "front left", Channel::Number::LEFT },
+ { "right", Channel::Number::RIGHT },
+ { "front right", Channel::Number::RIGHT },
+ { nullptr, Channel::Number::MAX_CHANNELS }
+};
+
+
+static char const *channel_string_from_number(Channel::Number ch)
+{
+ for (Names *n = names; n->name; ++n)
+ if (ch == n->number)
+ return n->name;
+ return nullptr;
+}
+
+
+/* keep sorted! */
+static struct Types {
+ char const *name;
+ Channel::Type type;
+} types[] = {
+ { "invalid", Channel::Type::TYPE_INVALID },
+ { "input", Channel::Type::INPUT },
+ { "output", Channel::Type::OUTPUT }
+};
+
+
+static char const *type_to_string(Channel::Type t) { return types[t].name; }
+
+
+class Channel_widget : public Compound_widget,
+ public Genode::List::Element
+{
+ Q_OBJECT
+
+ private:
+
+ Channel::Number _number;
+ Channel::Type _type;
+
+ QCheckBox _muted_checkbox;
+ QSlider _slider { Qt::Vertical };
+ QHBoxLayout _slider_hbox;
+
+ Q_SIGNALS:
+
+ void channel_changed();
+
+ public:
+
+ Channel_widget(Channel::Type type, Channel::Number number)
+ :
+ _number(number), _type(type),
+ _muted_checkbox("mute")
+ {
+ _slider.setMinimum(Channel::Volume_level::MIN);
+ _slider.setMaximum(Channel::Volume_level::MAX);
+
+ _slider_hbox.addStretch();
+ _slider_hbox.addWidget(&_slider, Qt::AlignCenter);
+ _slider_hbox.addStretch();
+
+ _layout->addLayout(&_slider_hbox);
+ _layout->addWidget(&_muted_checkbox);
+
+ connect(&_slider, SIGNAL(sliderReleased()),
+ this, SIGNAL(channel_changed()));
+ connect(&_muted_checkbox, SIGNAL(clicked(bool)),
+ this, SIGNAL(channel_changed()));
+ }
+
+ Channel::Number number() const { return _number; }
+ Channel::Type type() const { return _type; }
+ int volume() const { return _slider.value(); }
+ void volume(int v) { _slider.setValue(v); }
+ bool muted() const { return _muted_checkbox.checkState() == Qt::Checked; }
+ void muted(bool v) { _muted_checkbox.setChecked(v); }
+};
+
+
+class Client_widget : public Compound_widget,
+ public Genode::List::Element
+{
+ Q_OBJECT
+
+ public:
+
+ bool valid { true };
+
+ void _sorted_insert(Channel_widget *cw)
+ {
+ Channel::Number const nr = cw->number();
+
+ Channel_widget const *last = nullptr;
+ Channel_widget const *w = _list.first();
+ for (; w; w = w->next()) {
+ if (w->number() > nr)
+ break;
+ last = w;
+ }
+ _list.insert(cw, last);
+ }
+
+ private:
+
+ Genode::List _list;
+ Channel::Label _label;
+
+ QLabel _name;
+ QHBoxLayout _hlayout;
+
+ static char const *_strip_label(Channel::Label const &label)
+ {
+ char const * str = label.string();
+ int pos = 0;
+ for (int i = 0; str[i]; i++)
+ if (str[i] == '>') pos = i+1;
+
+ return str+pos;
+ }
+
+ Q_SIGNALS:
+
+ void client_changed();
+
+ public:
+
+ Client_widget(Channel::Label const &label)
+ :
+ _label(label),
+ _name(_strip_label(_label))
+ {
+ setFrameStyle(QFrame::Panel | QFrame::Raised);
+ setLineWidth(4);
+ setToolTip(_label.string());
+
+ _name.setAlignment(Qt::AlignCenter);
+ _name.setContentsMargins(0, 0, 0, 5);
+
+ _layout->addWidget(&_name);
+ _layout->addLayout(&_hlayout);
+ _layout->setContentsMargins(10, 10, 10, 10);
+ }
+
+ ~Client_widget()
+ {
+ while (Channel_widget *ch = _list.first()) {
+ disconnect(ch, SIGNAL(channel_changed()));
+ _hlayout.removeWidget(ch);
+ _list.remove(ch);
+ delete ch;
+ }
+ }
+
+ Channel::Label const &label() const { return _label; }
+
+ Channel_widget* lookup_channel(Channel::Number const number)
+ {
+ for (Channel_widget *ch = _list.first(); ch; ch = ch->next())
+ if (number == ch->number())
+ return ch;
+ return nullptr;
+ }
+
+ Channel_widget* add_channel(Channel::Type const type,
+ Channel::Number const number)
+ {
+ Channel_widget *ch = new Channel_widget(type, number);
+ connect(ch, SIGNAL(channel_changed()),
+ this, SIGNAL(client_changed()));
+
+ _sorted_insert(ch);
+ _hlayout.addWidget(ch);
+
+ return ch;
+ }
+
+ Channel_widget const* first_channel() const { return _list.first(); }
+
+ void only_show_first()
+ {
+ Channel_widget *cw = _list.first();
+ while ((cw = cw->next())) cw->hide();
+ }
+
+ bool combined_control() const
+ {
+ /*
+ * Having a seperate volume control widget for each channel is
+ * nice-to-have but for now it is unnecessary. We therefore disable
+ * it the hardcoded way.
+ */
+ return true;
+ }
+};
+
+
+class Client_widget_registry : public QObject
+{
+ Q_OBJECT
+
+ private:
+
+ Genode::List _list;
+
+ void _remove_destroy(Client_widget *c)
+ {
+ disconnect(c, SIGNAL(client_changed()));
+ _list.remove(c);
+ delete c;
+ }
+
+ Q_SIGNALS:
+
+ void registry_changed();
+
+ public:
+
+ Client_widget_registry() : QObject() { }
+
+ Client_widget* first() { return _list.first(); }
+
+ Client_widget* lookup(Channel::Label const &label)
+ {
+ for (Client_widget *c = _list.first(); c; c = c->next()) {
+ if (label == c->label())
+ return c;
+ }
+ return nullptr;
+ }
+
+ Client_widget* alloc_insert(Channel::Label const &label)
+ {
+ Client_widget *c = lookup(label);
+ if (c == nullptr) {
+ c = new Client_widget(label);
+ connect(c, SIGNAL(client_changed()),
+ this, SIGNAL(registry_changed()));
+ _list.insert(c);
+ }
+ return c;
+ }
+
+ void invalidate_all()
+ {
+ for (Client_widget *c = _list.first(); c; c = c->next())
+ c->valid = false;
+ }
+
+ void remove_invalid()
+ {
+ for (Client_widget *c = _list.first(); c; c = c->next())
+ if (c->valid == false) _remove_destroy(c);
+ }
+};
+
+
+static Client_widget_registry *client_registry()
+{
+ static Client_widget_registry inst;
+ return &inst;
+}
+
+
+static char const * const config_file = "/config/mixer.config";
+
+
+static int write_config(char const *file, char const *data, size_t length)
+{
+ if (length == 0) return 0;
+
+ QFile mixer_file(file);
+ if (!mixer_file.open(QIODevice::WriteOnly)) {
+ Genode::error("could not open '", file, "'");
+ return -1;
+ }
+
+ mixer_file.write(data, length);
+ mixer_file.close();
+
+ return 0;
+}
+
+
+void Main_window::_update_config()
+{
+ char xml_data[2048];
+ size_t xml_used = 0;
+
+ try {
+ Genode::Xml_generator xml(xml_data, sizeof(xml_data), "config", [&] {
+
+ xml.node("default", [&] {
+ xml.attribute("out_volume", _default_out_volume);
+ xml.attribute("volume", _default_volume);
+ xml.attribute("muted", _default_muted);
+ });
+
+ xml.node("channel_list", [&] {
+ for (Client_widget const *c = client_registry()->first(); c; c = c->next()) {
+ bool const combined = c->combined_control();
+
+ static int vol = 0;
+ static bool muted = true;
+ if (combined) {
+ Channel_widget const *w = c->first_channel();
+ vol = w->volume();
+ muted = w->muted();
+ }
+
+ for (Channel_widget const *w = c->first_channel(); w; w = w->next()) {
+ Channel::Number const nr = w->number();
+ xml.node("channel", [&] {
+ xml.attribute("type", type_to_string(w->type()));
+ xml.attribute("label", c->label().string());
+ xml.attribute("name", channel_string_from_number(nr));
+ xml.attribute("number", nr);
+ xml.attribute("volume", combined ? vol : w->volume());
+ xml.attribute("muted", combined ? muted : w->muted());
+ });
+
+ if (_verbose)
+ Genode::log("label: '", c->label(), "' "
+ "volume: ", combined ? vol : w->volume(), " "
+ "muted: ", combined ? muted : w->muted());
+ }
+ }
+ });
+ });
+ xml_used = xml.used();
+
+ } catch (...) { Genode::warning("could generate 'mixer.config'"); }
+
+ write_config(config_file, xml_data, xml_used);
+}
+
+
+void Main_window::_update_clients(Genode::Xml_node &channels)
+{
+ for (Client_widget *c = client_registry()->first(); c; c = c->next())
+ _layout->removeWidget(c);
+
+ client_registry()->invalidate_all();
+
+ channels.for_each_sub_node("channel", [&] (Genode::Xml_node const &node) {
+ try {
+ Channel ch(node);
+
+ Client_widget *c = client_registry()->lookup(ch.label);
+ if (c == nullptr)
+ c = client_registry()->alloc_insert(ch.label);
+
+ Channel_widget *w = c->lookup_channel(ch.number);
+ if (w == nullptr)
+ w = c->add_channel(ch.type, ch.number);
+
+ w->volume(ch.volume);
+ w->muted(ch.muted);
+
+ if (c->combined_control()) c->only_show_first();
+ else w->show();
+
+ c->valid = true;
+
+ _layout->addWidget(c);
+ resize(sizeHint());
+ } catch (Channel::Invalid_channel) { Genode::warning("invalid channel node"); }
+ });
+
+ client_registry()->remove_invalid();
+}
+
+
+/**
+ * Gets called from the Genode to Qt proxy object when the report was
+ * updated with a pointer to the XML document.
+ */
+void Main_window::report_changed(void *l, void const *p)
+{
+ Genode::Blockade &blockade = *reinterpret_cast(l);
+ Genode::Xml_node &node = *((Genode::Xml_node*)p);
+
+ if (node.has_type("channel_list"))
+ _update_clients(node);
+
+ blockade.wakeup();
+}
+
+
+Main_window::Main_window(Genode::Env &env)
+:
+ _default_out_volume(0),
+ _default_volume(0),
+ _default_muted(true)
+{
+ connect(client_registry(), SIGNAL(registry_changed()),
+ this, SLOT(_update_config()));
+
+ using namespace Genode;
+
+ Attached_rom_dataspace const config(env, "config");
+ _verbose = config.xml().attribute_value("verbose", false);
+ config.xml().with_sub_node("default",
+ [&] (Xml_node const &node) {
+ _default_out_volume = node.attribute_value("out_volume", 0L);
+ _default_volume = node.attribute_value("volume", 0L);
+ _default_muted = node.attribute_value("muted", 1L);
+ },
+ [&] { warning("no node found, fallback is 'muted=1'"); }
+ );
+}
+
+
+Main_window::~Main_window()
+{
+ disconnect(client_registry(), SIGNAL(registry_changed()));
+}
+
+#include "main_window.moc"
diff --git a/repos/gems/src/app/mixer_gui_qt6/main_window.h b/repos/gems/src/app/mixer_gui_qt6/main_window.h
new file mode 100644
index 0000000000..e6fc7d3806
--- /dev/null
+++ b/repos/gems/src/app/mixer_gui_qt6/main_window.h
@@ -0,0 +1,75 @@
+/*
+ * \brief Main window of the mixer Qt frontend
+ * \author Josef Soentgen
+ * \date 2015-10-15
+ */
+
+/*
+ * Copyright (C) 2015-2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef _MAIN_WINDOW_H_
+#define _MAIN_WINDOW_H_
+
+/* Genode includes */
+#include
+#include
+
+/* Qt includes */
+#include
+#include
+#include
+
+/* Qoost includes */
+#include
+#include
+
+/* application includes */
+
+
+/**
+ * This class proxies Genode signals to Qt signals
+ */
+struct Report_proxy : QObject
+{
+ Q_OBJECT
+
+ Q_SIGNALS:
+
+ void report_changed(void *, void const *);
+};
+
+
+class Main_window : public Compound_widget
+{
+ Q_OBJECT
+
+ private:
+
+ int _default_out_volume;
+ int _default_volume;
+ bool _default_muted;
+
+ bool _verbose;
+
+ void _update_clients(Genode::Xml_node &);
+
+ private Q_SLOTS:
+
+ void _update_config();
+
+ public Q_SLOTS:
+
+ void report_changed(void *, void const *);
+
+ public:
+
+ Main_window(Genode::Env &);
+
+ ~Main_window();
+};
+
+#endif /* _MAIN_WINDOW_H_ */
diff --git a/repos/gems/src/app/mixer_gui_qt6/mixer_gui_qt.pro b/repos/gems/src/app/mixer_gui_qt6/mixer_gui_qt.pro
new file mode 100644
index 0000000000..0a65816850
--- /dev/null
+++ b/repos/gems/src/app/mixer_gui_qt6/mixer_gui_qt.pro
@@ -0,0 +1,7 @@
+QT += core gui widgets
+TEMPLATE = app
+CONFIG += c++2a
+SOURCES += main.cpp \
+ main_window.cpp
+HEADERS += main_window.h
+RESOURCES = style.qrc
diff --git a/repos/gems/src/app/mixer_gui_qt6/style.qrc b/repos/gems/src/app/mixer_gui_qt6/style.qrc
new file mode 100644
index 0000000000..8a44d74480
--- /dev/null
+++ b/repos/gems/src/app/mixer_gui_qt6/style.qrc
@@ -0,0 +1,6 @@
+
+
+
+style.qss
+
+
diff --git a/repos/gems/src/app/mixer_gui_qt6/style.qss b/repos/gems/src/app/mixer_gui_qt6/style.qss
new file mode 100644
index 0000000000..c045aaaaa1
--- /dev/null
+++ b/repos/gems/src/app/mixer_gui_qt6/style.qss
@@ -0,0 +1,5 @@
+Main_window { min-width: 100; min-height: 100px; }
+
+Client_widget QFrame {
+ padding: 5px;
+}
diff --git a/repos/gems/src/app/mixer_gui_qt6/target.mk b/repos/gems/src/app/mixer_gui_qt6/target.mk
new file mode 100644
index 0000000000..67b904b809
--- /dev/null
+++ b/repos/gems/src/app/mixer_gui_qt6/target.mk
@@ -0,0 +1,12 @@
+QMAKE_PROJECT_FILE = $(PRG_DIR)/mixer_gui_qt.pro
+
+QMAKE_TARGET_BINARIES = mixer_gui_qt
+
+QT6_PORT_LIBS = libQt6Core libQt6Gui libQt6Widgets
+
+LIBS = qt6_qmake base libc libm mesa stdcxx qoost
+
+QT6_COMPONENT_LIB_SO =
+
+QT6_GENODE_LIBS_APP += ld.lib.so
+qmake_prepared.tag: $(addprefix build_dependencies/lib/,$(QT6_GENODE_LIBS_APP))
diff --git a/repos/gems/src/test/tiled_wm_qt6/app/app.cpp b/repos/gems/src/test/tiled_wm_qt6/app/app.cpp
new file mode 100644
index 0000000000..8d12ce9e32
--- /dev/null
+++ b/repos/gems/src/test/tiled_wm_qt6/app/app.cpp
@@ -0,0 +1,44 @@
+/*
+ * \brief Tiled-WM test: example application widget
+ * \author Christian Helmuth
+ * \date 2018-09-28
+ */
+
+/*
+ * Copyright (C) 2018 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* Qt includes */
+#include
+
+/* local includes */
+#include "app.h"
+
+
+App::App(QString name)
+{
+ _name->setText("This is " + name + " an example application for the tiled-WM test.");
+ _entry->setPlaceholderText("Placeholder text");
+
+ _layout->addWidget(new Spacer(), 1);
+ _layout->addWidget(_name);
+ _layout->addWidget(new Spacer(), 1);
+ _layout->addWidget(_entry);
+ _layout->addWidget(new Spacer(), 1);
+
+ for (int i = 0; i < 3; ++i) {
+ QLabel *l = new QLabel(QString("QLabel No." + QString::number(i)));
+ l->setToolTip(QString::number(i) + " is just a number.");
+ _layout->addWidget(l);
+ }
+
+ _layout->addWidget(new Spacer(), 1);
+}
+
+
+App::~App()
+{
+}
diff --git a/repos/gems/src/test/tiled_wm_qt6/app/app.h b/repos/gems/src/test/tiled_wm_qt6/app/app.h
new file mode 100644
index 0000000000..328bd8a2a8
--- /dev/null
+++ b/repos/gems/src/test/tiled_wm_qt6/app/app.h
@@ -0,0 +1,46 @@
+/*
+ * \brief TIled-WM test: example application widget
+ * \author Christian Helmuth
+ * \date 2018-09-28
+ */
+
+/*
+ * Copyright (C) 2018 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef _TEST__TILED_WM__APP__APP_H_
+#define _TEST__TILED_WM__APP__APP_H_
+
+/* Qt includes */
+#include
+#include
+#include
+#include
+
+/* Qoost includes */
+#include
+#include
+
+/* local includes */
+#include
+
+
+class App : public Compound_widget
+{
+ Q_OBJECT
+
+ private:
+
+ QMember _name;
+ QMember _entry;
+
+ public:
+
+ App(QString name);
+ ~App();
+};
+
+#endif /* _TEST__TILED_WM__APP__APP_H_ */
diff --git a/repos/gems/src/test/tiled_wm_qt6/app/app.pro b/repos/gems/src/test/tiled_wm_qt6/app/app.pro
new file mode 100644
index 0000000000..0953a7bf26
--- /dev/null
+++ b/repos/gems/src/test/tiled_wm_qt6/app/app.pro
@@ -0,0 +1,7 @@
+TEMPLATE = app
+TARGET = test-tiled_wm-app
+QT = core gui widgets
+CONFIG += c++2a
+SOURCES += main.cpp app.cpp
+HEADERS += app.h ../util.h
+RESOURCES = app.qrc
diff --git a/repos/gems/src/test/tiled_wm_qt6/app/app.qrc b/repos/gems/src/test/tiled_wm_qt6/app/app.qrc
new file mode 100644
index 0000000000..cb8c387b6f
--- /dev/null
+++ b/repos/gems/src/test/tiled_wm_qt6/app/app.qrc
@@ -0,0 +1,8 @@
+
+
+
+ ../style.qss
+
+
+
+
diff --git a/repos/gems/src/test/tiled_wm_qt6/app/main.cpp b/repos/gems/src/test/tiled_wm_qt6/app/main.cpp
new file mode 100644
index 0000000000..ec6bee0d19
--- /dev/null
+++ b/repos/gems/src/test/tiled_wm_qt6/app/main.cpp
@@ -0,0 +1,55 @@
+/*
+ * \brief Tiled-WM test: example application
+ * \author Christian Helmuth
+ * \date 2018-09-26
+ */
+
+/*
+ * Copyright (C) 2018 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* Genode includes */
+#include
+
+/* local includes */
+#include
+#include "app.h"
+
+
+struct Main
+{
+ Libc::Env &env;
+
+ Genode::Attached_rom_dataspace config { env, "config" };
+
+ QApplication &app { qt6_initialization(env) };
+
+ QMember widget { name_from_config() };
+
+ QString name_from_config()
+ {
+ Name name = config.xml().attribute_value("name", Name("no name"));
+
+ return QString(name.string());
+ }
+
+ Main(Libc::Env &env) : env(env)
+ {
+ widget->show();
+ }
+};
+
+
+void Libc::Component::construct(Libc::Env &env)
+{
+ Libc::with_libc([&] {
+
+ static Main main { env };
+
+ exit(main.app.exec());
+ });
+}
+
diff --git a/repos/gems/src/test/tiled_wm_qt6/app/target.mk b/repos/gems/src/test/tiled_wm_qt6/app/target.mk
new file mode 100644
index 0000000000..dc1efc32de
--- /dev/null
+++ b/repos/gems/src/test/tiled_wm_qt6/app/target.mk
@@ -0,0 +1,4 @@
+QMAKE_PROJECT_FILE = $(PRG_DIR)/app.pro
+QMAKE_TARGET_BINARIES = test-tiled_wm-app
+
+include $(PRG_DIR)/../target.inc
diff --git a/repos/gems/src/test/tiled_wm_qt6/manager/main.cc b/repos/gems/src/test/tiled_wm_qt6/manager/main.cc
new file mode 100644
index 0000000000..e809f680b6
--- /dev/null
+++ b/repos/gems/src/test/tiled_wm_qt6/manager/main.cc
@@ -0,0 +1,210 @@
+/*
+ * \brief Tiled-WM test: GUI manager
+ * \author Christian Helmuth
+ * \date 2018-09-26
+ *
+ * GUI manager implements the user-visible display state machine.
+ */
+
+/*
+ * Copyright (C) 2018 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+#include
+
+
+using Name = Genode::String<32>;
+
+
+namespace Test { struct Manager; }
+
+struct Test::Manager
+{
+ Genode::Env &env;
+
+ Genode::Attached_rom_dataspace content_request_rom { env, "content_request" };
+ Genode::Attached_rom_dataspace overlay_request_rom { env, "overlay_request" };
+
+ Genode::Signal_handler content_request_handler {
+ env.ep(), *this, &Manager::handle_content_request };
+ Genode::Signal_handler overlay_request_handler {
+ env.ep(), *this, &Manager::handle_overlay_request };
+
+ Genode::Reporter apps_report { env, "apps" };
+ Genode::Reporter overlay_report { env, "overlay" };
+
+ Genode::Reporter layout_rules_report { env, "rules", "layout_rules" };
+
+ struct App {
+ char const *label;
+ char const *name;
+ bool visible;
+ } apps[3] {
+ { "test-tiled_wm-app-1", "app1", true },
+ { "test-tiled_wm-app-2", "app2", false },
+ { "textedit", "textedit", false }
+ };
+
+ bool overlay_visible { false };
+
+ void report_apps();
+ void report_overlay();
+ void report_layout_rules();
+
+ void handle_content_request();
+ void handle_overlay_request();
+
+ Manager(Genode::Env &env);
+};
+
+
+void Test::Manager::handle_content_request()
+{
+ content_request_rom.update();
+
+ Name requested_app =
+ content_request_rom.xml().attribute_value("name", Name());
+
+ if (!requested_app.valid()) return;
+
+ App *found = nullptr;
+ for (App &app : apps) {
+ if (requested_app != app.name) continue;
+ found = &app;
+ break;
+ }
+ if (!found || found->visible) return;
+
+ for (App &app : apps) {
+ if (&app == found) {
+ app.visible = true;
+ } else {
+ app.visible = false;
+ }
+ }
+
+ report_apps();
+ report_layout_rules();
+}
+
+
+void Test::Manager::handle_overlay_request()
+{
+ overlay_request_rom.update();
+
+ bool const request_visible =
+ overlay_request_rom.xml().attribute_value("visible", false);
+
+ if (request_visible == overlay_visible) return;
+
+ overlay_visible = request_visible;
+
+ report_overlay();
+ report_layout_rules();
+}
+
+
+void Test::Manager::report_apps()
+{
+ Genode::Reporter::Xml_generator xml(apps_report, [&] () {
+ for (App &app : apps) {
+ xml.node("app", [&] () {
+ xml.attribute("name", app.name);
+ xml.attribute("visible", app.visible);
+ });
+ }
+ });
+}
+
+
+void Test::Manager::report_overlay()
+{
+ Genode::Reporter::Xml_generator xml(overlay_report, [&] () {
+ xml.attribute("visible", overlay_visible);
+ });
+}
+
+
+void Test::Manager::report_layout_rules()
+{
+ Genode::Reporter::Xml_generator xml(layout_rules_report, [&] () {
+ xml.node("screen", [&] () {
+ xml.node("column", [&] () {
+ xml.attribute("name", "screen");
+ xml.attribute("layer", "1");
+ xml.node("row", [&] () {
+ xml.attribute("name", "panel");
+ xml.attribute("layer", "2");
+ xml.attribute("height", "24");
+ });
+ xml.node("row", [&] () {
+ xml.attribute("name", "content");
+ xml.attribute("layer", "4");
+ xml.node("column", [&] () {
+ xml.attribute("weight", "2");
+ });
+ xml.node("column", [&] () {
+ xml.attribute("name", "overlay");
+ xml.attribute("layer", "3");
+ xml.attribute("weight", "1");
+ });
+ });
+ });
+ });
+ xml.node("assign", [&] () {
+ xml.attribute("label_prefix", "test-tiled_wm-panel");
+ xml.attribute("target", "panel");
+ });
+ xml.node("assign", [&] () {
+ xml.attribute("label_prefix", "test-tiled_wm-overlay");
+ xml.attribute("target", "overlay");
+ if (!overlay_visible)
+ xml.attribute("visible", false);
+ });
+
+ /* debug */
+ if (false) {
+ xml.node("assign", [&] () {
+ xml.attribute("label_prefix", "");
+ xml.attribute("target", "screen");
+ xml.attribute("xpos", "any");
+ xml.attribute("ypos", "any");
+ });
+ }
+
+ for (App &app : apps) {
+ xml.node("assign", [&] () {
+ xml.attribute("label_prefix", app.label);
+ xml.attribute("target", "content");
+ if (!app.visible)
+ xml.attribute("visible", "false");
+ });
+ }
+ });
+}
+
+
+Test::Manager::Manager(Genode::Env &env) : env(env)
+{
+ apps_report.enabled(true);
+ overlay_report.enabled(true);
+ layout_rules_report.enabled(true);
+
+ content_request_rom.sigh(content_request_handler);
+ overlay_request_rom.sigh(overlay_request_handler);
+
+ report_apps();
+ report_overlay();
+ report_layout_rules();
+}
+
+
+void Component::construct(Genode::Env &env) { static Test::Manager manager(env); }
diff --git a/repos/gems/src/test/tiled_wm_qt6/manager/target.mk b/repos/gems/src/test/tiled_wm_qt6/manager/target.mk
new file mode 100644
index 0000000000..de4d67ed8b
--- /dev/null
+++ b/repos/gems/src/test/tiled_wm_qt6/manager/target.mk
@@ -0,0 +1,3 @@
+TARGET = test-tiled_wm-manager
+SRC_CC = main.cc
+LIBS = base
diff --git a/repos/gems/src/test/tiled_wm_qt6/overlay/main.cpp b/repos/gems/src/test/tiled_wm_qt6/overlay/main.cpp
new file mode 100644
index 0000000000..73b5e25484
--- /dev/null
+++ b/repos/gems/src/test/tiled_wm_qt6/overlay/main.cpp
@@ -0,0 +1,43 @@
+/*
+ * \brief Tiled-WM test: example overlay
+ * \author Christian Helmuth
+ * \date 2018-09-28
+ */
+
+/*
+ * Copyright (C) 2018 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* local includes */
+#include
+#include "overlay.h"
+
+
+struct Main
+{
+ Libc::Env &env;
+
+ QApplication &app { qt6_initialization(env) };
+
+ QMember widget { };
+
+ Main(Libc::Env &env) : env(env)
+ {
+ widget->show();
+ }
+};
+
+
+void Libc::Component::construct(Libc::Env &env)
+{
+ Libc::with_libc([&] {
+
+ static Main main { env };
+
+ exit(main.app.exec());
+ });
+}
+
diff --git a/repos/gems/src/test/tiled_wm_qt6/overlay/overlay.cpp b/repos/gems/src/test/tiled_wm_qt6/overlay/overlay.cpp
new file mode 100644
index 0000000000..dc02b10c9a
--- /dev/null
+++ b/repos/gems/src/test/tiled_wm_qt6/overlay/overlay.cpp
@@ -0,0 +1,36 @@
+/*
+ * \brief Tiled-WM test: overlay widget
+ * \author Christian Helmuth
+ * \date 2018-09-28
+ */
+
+/*
+ * Copyright (C) 2018 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* Qt includes */
+#include
+
+/* local includes */
+#include "overlay.h"
+
+
+Overlay::Overlay()
+{
+ _label->setText("WiFi overlay");
+ _entry->setEchoMode(QLineEdit::Password);
+
+ _layout->addWidget(new Spacer(), 1);
+ _layout->addWidget(_label);
+ _layout->addWidget(new Spacer(), 1);
+ _layout->addWidget(_entry);
+ _layout->addWidget(new Spacer(), 1);
+}
+
+
+Overlay::~Overlay()
+{
+}
diff --git a/repos/gems/src/test/tiled_wm_qt6/overlay/overlay.h b/repos/gems/src/test/tiled_wm_qt6/overlay/overlay.h
new file mode 100644
index 0000000000..ac880c498d
--- /dev/null
+++ b/repos/gems/src/test/tiled_wm_qt6/overlay/overlay.h
@@ -0,0 +1,46 @@
+/*
+ * \brief Tiled-WM test: overlay widget
+ * \author Christian Helmuth
+ * \date 2018-09-28
+ */
+
+/*
+ * Copyright (C) 2018 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef _TEST__TILED_WM__OVERLAY__OVERLAY_H_
+#define _TEST__TILED_WM__OVERLAY__OVERLAY_H_
+
+/* Qt includes */
+#include
+#include
+#include
+#include
+
+/* Qoost includes */
+#include
+#include
+
+/* local includes */
+#include
+
+
+class Overlay : public Compound_widget
+{
+ Q_OBJECT
+
+ private:
+
+ QMember _label;
+ QMember _entry;
+
+ public:
+
+ Overlay();
+ ~Overlay();
+};
+
+#endif /* _TEST__TILED_WM__OVERLAY__OVERLAY_H_ */
diff --git a/repos/gems/src/test/tiled_wm_qt6/overlay/overlay.pro b/repos/gems/src/test/tiled_wm_qt6/overlay/overlay.pro
new file mode 100644
index 0000000000..5f06b5e8ea
--- /dev/null
+++ b/repos/gems/src/test/tiled_wm_qt6/overlay/overlay.pro
@@ -0,0 +1,7 @@
+TEMPLATE = app
+TARGET = test-tiled_wm-overlay
+QT = core gui widgets
+CONFIG += c++2a
+SOURCES += main.cpp overlay.cpp
+HEADERS += overlay.h ../util.h
+RESOURCES = overlay.qrc
diff --git a/repos/gems/src/test/tiled_wm_qt6/overlay/overlay.qrc b/repos/gems/src/test/tiled_wm_qt6/overlay/overlay.qrc
new file mode 100644
index 0000000000..cb8c387b6f
--- /dev/null
+++ b/repos/gems/src/test/tiled_wm_qt6/overlay/overlay.qrc
@@ -0,0 +1,8 @@
+
+
+
+ ../style.qss
+
+
+
+
diff --git a/repos/gems/src/test/tiled_wm_qt6/overlay/target.mk b/repos/gems/src/test/tiled_wm_qt6/overlay/target.mk
new file mode 100644
index 0000000000..a967ebe17b
--- /dev/null
+++ b/repos/gems/src/test/tiled_wm_qt6/overlay/target.mk
@@ -0,0 +1,4 @@
+QMAKE_PROJECT_FILE = $(PRG_DIR)/overlay.pro
+QMAKE_TARGET_BINARIES = test-tiled_wm-overlay
+
+include $(PRG_DIR)/../target.inc
diff --git a/repos/gems/src/test/tiled_wm_qt6/panel/main.cpp b/repos/gems/src/test/tiled_wm_qt6/panel/main.cpp
new file mode 100644
index 0000000000..7e222cf69b
--- /dev/null
+++ b/repos/gems/src/test/tiled_wm_qt6/panel/main.cpp
@@ -0,0 +1,46 @@
+/*
+ * \brief Tiled-WM test: panel
+ * \author Christian Helmuth
+ * \date 2018-09-26
+ *
+ * Panel is a Qt6-based example panel at the bottom of the screen.
+ */
+
+/*
+ * Copyright (C) 2018 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* local includes */
+#include "panel.h"
+
+
+struct Main
+{
+ Libc::Env &env;
+
+ Genode::Entrypoint signal_ep { env, 0x4000, "signal ep",
+ Genode::Affinity::Location() };
+
+ QApplication &app { qt6_initialization(env) };
+
+ QMember widget { env, signal_ep };
+
+ Main(Libc::Env &env) : env(env)
+ {
+ widget->show();
+ }
+};
+
+
+void Libc::Component::construct(Libc::Env &env)
+{
+ Libc::with_libc([&] {
+
+ static Main main { env };
+
+ exit(main.app.exec());
+ });
+}
diff --git a/repos/gems/src/test/tiled_wm_qt6/panel/panel.cpp b/repos/gems/src/test/tiled_wm_qt6/panel/panel.cpp
new file mode 100644
index 0000000000..c45d20cfdc
--- /dev/null
+++ b/repos/gems/src/test/tiled_wm_qt6/panel/panel.cpp
@@ -0,0 +1,148 @@
+/*
+ * \brief Tiled-WM test: panel widget
+ * \author Christian Helmuth
+ * \date 2018-09-28
+ */
+
+/*
+ * Copyright (C) 2018 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* Qt includes */
+#include
+
+/* local includes */
+#include "panel.h"
+
+
+void Panel_button::_clicked() { Q_EMIT clicked(text()); if (text() == "Panel") showMenu(); }
+void Panel_button::_toggled(bool checked) { Q_EMIT toggled(checked, text()); }
+
+
+Panel_button::Panel_button(QString label)
+{
+ if (!label.isNull()) {
+ setText(label);
+ }
+
+ setCheckable(true);
+ setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
+
+ _layout->addWidget(_icon, 0, Qt::AlignCenter);
+
+ if (label == "Panel") {
+ _menu->addAction("Action");
+ setMenu(_menu);
+ }
+
+ connect(this, SIGNAL(clicked()), SLOT(_clicked()));
+ connect(this, SIGNAL(toggled(bool)), SLOT(_toggled(bool)));
+}
+
+
+Panel_button::~Panel_button() { }
+
+
+void App_bar::_app_button(QAbstractButton *b, bool checked)
+{
+ if (!checked) return;
+
+ if (Panel_button *button = qobject_cast(b)) {
+ Name name { button->text().toUtf8().constData() };
+
+ Genode::Reporter::Xml_generator xml(_content_request, [&] () {
+ xml.attribute("name", name);
+ });
+ }
+}
+
+
+void App_bar::_handle_apps()
+{
+ /* empty bar before adding current apps */
+ while (QLayoutItem *item = _layout->takeAt(0)) {
+ if (Panel_button *button = qobject_cast(item->widget())) {
+ _button_group->removeButton(button);
+ button->deleteLater();
+ }
+ delete item;
+ }
+
+ _apps.update();
+
+ Panel_button *visible_app_button = nullptr;
+
+ _apps.xml().for_each_sub_node("app", [&] (Genode::Xml_node node) {
+ QString const name { node.attribute_value("name", Name("no name")).string() };
+ bool const visible { node.attribute_value("visible", false) };
+ Panel_button *button { new Panel_button(name) };
+
+ if (visible) visible_app_button = button;
+
+ _button_group->addButton(button);
+ _layout->addWidget(button);
+ });
+
+ if (visible_app_button) visible_app_button->setChecked(true);
+}
+
+
+App_bar::App_bar(Genode::Env &env, Genode::Entrypoint &sig_ep)
+:
+ _apps(env, "apps"), _content_request(env, "content_request"),
+ _apps_proxy(sig_ep)
+{
+ _content_request.enabled(true);
+
+ _button_group->setExclusive(true);
+
+ _handle_apps();
+
+ _apps.sigh(*_apps_proxy);
+
+ connect(_apps_proxy, SIGNAL(signal()), SLOT(_handle_apps()));
+ connect(_button_group, SIGNAL(buttonToggled(QAbstractButton *, bool)),
+ SLOT(_app_button(QAbstractButton *, bool)));
+}
+
+
+App_bar::~App_bar() { }
+
+
+void Panel::_wifi_toggled(bool checked)
+{
+ Genode::Reporter::Xml_generator xml(_overlay_request, [&] () {
+ xml.attribute("visible", checked);
+ });
+}
+
+
+Panel::Panel(Genode::Env &env, Genode::Entrypoint &sig_ep)
+:
+ _overlay(env, "overlay"), _overlay_request(env, "overlay_request"),
+ _panel_button("Panel"), _app_bar(env, sig_ep)
+{
+ _layout->addWidget(_panel_button);
+ _layout->addWidget(new Spacer(), 1);
+ _layout->addWidget(_app_bar);
+ _layout->addWidget(new Spacer(), 1);
+ _layout->addWidget(_wifi_button);
+
+ _panel_button->setCheckable(false);
+ _panel_button->setToolTip("This panel is just an example.");
+
+ _wifi_button->setObjectName("wifi");
+ _wifi_button->setToolTip("Open WiFi overlay");
+
+ _overlay_request.enabled(true);
+
+ _wifi_toggled(_wifi_button->isChecked());
+
+ connect(_wifi_button, SIGNAL(toggled(bool)), SLOT(_wifi_toggled(bool)));
+}
+
+
+Panel::~Panel() { }
diff --git a/repos/gems/src/test/tiled_wm_qt6/panel/panel.h b/repos/gems/src/test/tiled_wm_qt6/panel/panel.h
new file mode 100644
index 0000000000..033e790893
--- /dev/null
+++ b/repos/gems/src/test/tiled_wm_qt6/panel/panel.h
@@ -0,0 +1,111 @@
+/*
+ * \brief Tiled-WM test: panel widget
+ * \author Christian Helmuth
+ * \date 2018-09-27
+ */
+
+/*
+ * Copyright (C) 2018 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef _TEST__TILED_WM__PANEL__PANEL_H_
+#define _TEST__TILED_WM__PANEL__PANEL_H_
+
+/* Qt includes */
+#include
+#include
+#include
+#include
+#include
+
+/* Qoost includes */
+#include
+#include
+
+/* Genode includes */
+#include
+#include
+
+/* local includes */
+#include
+#include /* build-dir copy of qoost/icon.h works around missing "vtable for Icon" */
+
+
+class Panel_button : public Compound_widget
+{
+ Q_OBJECT
+
+ private:
+
+ QMember _icon;
+ QMember _menu;
+
+ private Q_SLOTS:
+
+ void _clicked();
+ void _toggled(bool);
+
+ public:
+
+ Panel_button(QString label = QString());
+ ~Panel_button();
+
+ Q_SIGNALS:
+
+ void clicked(QString label);
+ void toggled(bool checked, QString label);
+};
+
+
+class App_bar : public Compound_widget
+{
+ Q_OBJECT
+
+ private:
+
+ Genode::Attached_rom_dataspace _apps;
+ Genode::Reporter _content_request;
+
+ QMember _button_group;
+ QMember _apps_proxy;
+
+ private Q_SLOTS:
+
+ void _handle_apps();
+ void _app_button(QAbstractButton *, bool);
+
+ public:
+
+ App_bar(Genode::Env &, Genode::Entrypoint &);
+ ~App_bar();
+};
+
+
+
+class Panel : public Compound_widget
+{
+ Q_OBJECT
+
+ private:
+
+ Genode::Attached_rom_dataspace _overlay;
+ Genode::Reporter _overlay_request;
+
+ QMember _panel_button;
+ QMember _app_bar;
+ QMember _wifi_button;
+
+ private Q_SLOTS:
+
+ void _wifi_toggled(bool);
+
+ public:
+
+ Panel(Genode::Env &, Genode::Entrypoint &);
+ ~Panel();
+};
+
+#endif /* _TEST__TILED_WM__PANEL__PANEL_H_ */
diff --git a/repos/gems/src/test/tiled_wm_qt6/panel/panel.pro b/repos/gems/src/test/tiled_wm_qt6/panel/panel.pro
new file mode 100644
index 0000000000..40b1fe3d5a
--- /dev/null
+++ b/repos/gems/src/test/tiled_wm_qt6/panel/panel.pro
@@ -0,0 +1,7 @@
+TEMPLATE = app
+TARGET = test-tiled_wm-panel
+QT = core gui widgets
+CONFIG += c++2a
+SOURCES += main.cpp panel.cpp
+HEADERS += panel.h icon.h ../util.h
+RESOURCES = panel.qrc
diff --git a/repos/gems/src/test/tiled_wm_qt6/panel/panel.qrc b/repos/gems/src/test/tiled_wm_qt6/panel/panel.qrc
new file mode 100644
index 0000000000..9092a358d6
--- /dev/null
+++ b/repos/gems/src/test/tiled_wm_qt6/panel/panel.qrc
@@ -0,0 +1,9 @@
+
+
+
+ ../style.qss
+ wifi.png
+
+
+
+
diff --git a/repos/gems/src/test/tiled_wm_qt6/panel/target.mk b/repos/gems/src/test/tiled_wm_qt6/panel/target.mk
new file mode 100644
index 0000000000..65c17170aa
--- /dev/null
+++ b/repos/gems/src/test/tiled_wm_qt6/panel/target.mk
@@ -0,0 +1,6 @@
+QMAKE_PROJECT_FILE = $(PRG_DIR)/panel.pro
+QMAKE_TARGET_BINARIES = test-tiled_wm-panel
+
+qmake_prepared.tag: icon.h
+
+include $(PRG_DIR)/../target.inc
diff --git a/repos/gems/src/test/tiled_wm_qt6/panel/wifi.png b/repos/gems/src/test/tiled_wm_qt6/panel/wifi.png
new file mode 100644
index 0000000000..502591d38e
Binary files /dev/null and b/repos/gems/src/test/tiled_wm_qt6/panel/wifi.png differ
diff --git a/repos/gems/src/test/tiled_wm_qt6/style.qss b/repos/gems/src/test/tiled_wm_qt6/style.qss
new file mode 100644
index 0000000000..067e94aabd
--- /dev/null
+++ b/repos/gems/src/test/tiled_wm_qt6/style.qss
@@ -0,0 +1,22 @@
+Panel, Overlay, App { min-width: 100px; min-height: 100px; }
+
+QFrame { padding: 5px; }
+QLabel { color: white; }
+/*QPushButton { border: none; outline: none; }*/
+
+Panel {
+ background-color: rgb(51, 93, 128);
+}
+
+Panel_button Icon { qproperty-iconSize: 18px; }
+Panel_button#wifi Icon { qproperty-iconFile: url(:/wifi.png); }
+
+Overlay {
+ background-color: rgba(25, 69, 105, 100);
+}
+
+App {
+ background-color: rgb(96, 130, 159);
+}
+
+/* vi: set ft=css : */
diff --git a/repos/gems/src/test/tiled_wm_qt6/target.inc b/repos/gems/src/test/tiled_wm_qt6/target.inc
new file mode 100644
index 0000000000..f12d5ce31d
--- /dev/null
+++ b/repos/gems/src/test/tiled_wm_qt6/target.inc
@@ -0,0 +1,25 @@
+QT6_PORT_LIBS = libQt6Core libQt6Gui libQt6Widgets
+
+LIBS = qt6_qmake base libc libm mesa stdcxx qoost
+
+QT6_COMPONENT_LIB_SO =
+
+QT6_GENODE_LIBS_APP += ld.lib.so
+qmake_prepared.tag: $(addprefix build_dependencies/lib/,$(QT6_GENODE_LIBS_APP))
+
+INC_DIR += $(PRG_DIR)/..
+
+#
+# We need Qt headers in a local directory for MOC to work correctly
+#
+
+# icon.h from the qoost API package
+ICON_H = $(call select_from_repositories,include/qoost/icon.h)
+
+# fall-back to the qoost port directory if that fails
+ifeq ($(ICON_H),)
+ICON_H := $(call select_from_ports,qoost)/include/qoost/icon.h
+endif
+
+icon.h: $(ICON_H)
+ $(VERBOSE)cp $(ICON_H) .
diff --git a/repos/gems/src/test/tiled_wm_qt6/util.h b/repos/gems/src/test/tiled_wm_qt6/util.h
new file mode 100644
index 0000000000..ff3a054311
--- /dev/null
+++ b/repos/gems/src/test/tiled_wm_qt6/util.h
@@ -0,0 +1,116 @@
+/*
+ * \brief Tiled-WM test: utilities
+ * \author Christian Helmuth
+ * \date 2018-09-26
+ */
+
+/*
+ * Copyright (C) 2018-2020 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef _TEST__TILED_WM__UTIL_H_
+#define _TEST__TILED_WM__UTIL_H_
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+
+/* Qt includes */
+#include
+#include
+#include
+#include
+#include
+
+/* Qoost includes */
+#include
+
+/* Libc includes */
+#include
+
+/* qt6_component includes */
+#include
+
+using Name = Genode::String<32>;
+
+
+/*
+ * Genode signal to queued Qt signal proxy
+ */
+class Genode_signal_proxy : public QObject,
+ public Genode::Signal_handler
+{
+ Q_OBJECT
+
+ public:
+
+ Genode_signal_proxy(Genode::Entrypoint &sig_ep)
+ :
+ Genode::Signal_handler(
+ sig_ep, *this, &Genode_signal_proxy::handle_genode_signal)
+ {
+ connect(this, SIGNAL(internal_signal()),
+ this, SIGNAL(signal()),
+ Qt::QueuedConnection);
+ }
+
+ /* called by signal handler / emits internal signal in context of
+ * signal-entrypoint thread */
+ void handle_genode_signal() { Q_EMIT internal_signal(); }
+
+ Q_SIGNALS:
+
+ /* internal_signal() is Qt::QueuedConnection to signal() */
+ void internal_signal();
+
+ /* finally signal() is emitted in the context of the Qt main thread */
+ void signal();
+};
+
+
+/*
+ * Qt initialization
+ */
+
+static inline QApplication & qt6_initialization(Libc::Env &env)
+{
+ qpa_init(env);
+
+ char const *argv[] = { "qt6_app", 0 };
+ int argc = sizeof(argv)/sizeof(*argv);
+
+ static QApplication app(argc, (char**)argv);
+
+ QFile file(":style.qss");
+ if (!file.open(QFile::ReadOnly)) {
+ qWarning() << "Warning:" << file.errorString()
+ << "opening file" << file.fileName();
+ } else {
+ qApp->setStyleSheet(QLatin1String(file.readAll()));
+ }
+
+ app.connect(&app, SIGNAL(lastWindowClosed()), SLOT(quit()));
+
+ return app;
+}
+
+
+/*
+ * Widget utilities
+ */
+
+struct Spacer : QFrame
+{
+ Q_OBJECT public:
+
+ Spacer(QString const &style_id = "") { setObjectName(style_id); }
+
+ ~Spacer() { }
+};
+
+#endif /* _TEST__TILED_WM__UTIL_H_ */
diff --git a/repos/libports/include/qt6_component/qpa_init.h b/repos/libports/include/qt6_component/qpa_init.h
new file mode 100644
index 0000000000..a15cc4845f
--- /dev/null
+++ b/repos/libports/include/qt6_component/qpa_init.h
@@ -0,0 +1,60 @@
+/*
+ * \brief QPA plugin initialization
+ * \author Christian Prochaska
+ * \date 2020-06-28
+ */
+
+/*
+ * Copyright (C) 2020 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef _INCLUDE__QPA_INIT_H_
+#define _INCLUDE__QPA_INIT_H_
+
+/* Genode includes */
+#include
+
+/* libc includes */
+#include /* 'dlopen' */
+#include /* 'fprintf' */
+#include /* 'exit' */
+#include /* 'access' */
+
+/**
+ * Initialize the QPA plugin
+ *
+ * When Qt loads the plugin again, it will get the same handle.
+ */
+static inline void qpa_init(Genode::Env &env)
+{
+ char const *qpa_plugin = "/qt/plugins/platforms/libqgenode.lib.so";
+
+ void *qpa_plugin_handle = nullptr;
+
+ /* check existence with 'access()' first to avoid ld error messages */
+ if (access(qpa_plugin, F_OK) == 0)
+ qpa_plugin_handle = dlopen(qpa_plugin, RTLD_LAZY);
+
+ if (qpa_plugin_handle) {
+
+ typedef void (*initialize_qpa_plugin_t)(Genode::Env &);
+
+ initialize_qpa_plugin_t initialize_qpa_plugin =
+ (initialize_qpa_plugin_t) dlsym(qpa_plugin_handle,
+ "initialize_qpa_plugin");
+
+ if (!initialize_qpa_plugin) {
+ fprintf(stderr, "Could not find 'initialize_qpa_plugin' \
+ function in QPA plugin\n");
+ dlclose(qpa_plugin_handle);
+ exit(1);
+ }
+
+ initialize_qpa_plugin(env);
+ }
+}
+
+#endif /* _INCLUDE__QPA_INIT_H_ */
diff --git a/repos/libports/lib/import/import-qt6.inc b/repos/libports/lib/import/import-qt6.inc
new file mode 100644
index 0000000000..0ed9eba9e2
--- /dev/null
+++ b/repos/libports/lib/import/import-qt6.inc
@@ -0,0 +1,87 @@
+QT_TOOLS_DIR = /usr/local/genode/tool/23.05/qt6
+
+ifeq ($(filter-out $(SPECS),arm),)
+QT_PLATFORM = genode-arm-g++
+else ifeq ($(filter-out $(SPECS),arm_64),)
+QT_PLATFORM = genode-aarch64-g++
+else ifeq ($(filter-out $(SPECS),x86_32),)
+QT_PLATFORM = genode-x86_32-g++
+else ifeq ($(filter-out $(SPECS),x86_64),)
+QT_PLATFORM = genode-x86_64-g++
+else
+$(error Error: unsupported platform)
+endif
+
+ifeq ($(CONTRIB_DIR),)
+QT_DIR = $(call select_from_repositories,src/lib/qt6)
+QT_API_DIR = $(call select_from_repositories,mkspecs)/..
+abi_symbol_path = $(wildcard $(call select_from_repositories,lib/symbols/$1))
+else
+QT_PORT_DIR := $(call select_from_ports,qt6)
+QT_DIR = $(QT_PORT_DIR)/src/lib/qt6
+QT_API_DIR = $(QT_DIR)/genode/api
+abi_symbol_path = $(wildcard $(addprefix $(QT_API_DIR)/lib/symbols/,$1))
+endif
+
+ifeq ($(VERBOSE),)
+MAKE_VERBOSE="1"
+else
+QT6_OUTPUT_FILTER = > /dev/null
+endif
+
+#
+# Genode libraries to be linked to Qt applications and libraries
+#
+
+QT6_COMPONENT_LIB_SO ?= qt6_component.lib.so
+QT6_GENODE_LIBS_COMMON += libc.lib.so libm.lib.so stdcxx.lib.so
+QT6_GENODE_LIBS_APP += $(QT6_GENODE_LIBS_COMMON) $(QT6_COMPONENT_LIB_SO)
+QT6_GENODE_LIBS_SHLIB += $(QT6_GENODE_LIBS_COMMON)
+
+#
+# common 'build_dependencies' rules
+#
+
+build_dependencies:
+ $(VERBOSE)mkdir -p $@
+
+build_dependencies/include: build_dependencies
+ $(VERBOSE)mkdir -p $@
+ $(VERBOSE)ln -snf $(QT_API_DIR)/include/* $@/
+
+build_dependencies/lib: build_dependencies
+ $(VERBOSE)mkdir -p $@
+
+build_dependencies/lib/%.lib.so: build_dependencies/lib
+ $(VERBOSE)ln -sf $(BUILD_BASE_DIR)/var/libcache/$*/$*.abi.so $@
+
+build_dependencies/lib/%.lib.a: build_dependencies/lib
+ $(VERBOSE)ln -sf $(BUILD_BASE_DIR)/var/libcache/$*/$*.lib.a $@
+
+#
+# rules for generating .lib.so files from port symbol files
+#
+
+lib_name = $(notdir $(1:.lib.so=))
+abi_name = $(notdir $(1:.abi.so=))
+abi_path = build_dependencies/abi/$(call abi_name,$1)/$(call abi_name,$1).abi.so
+so_path = build_dependencies/lib/$(call lib_name,$1).lib.so
+
+BUILD_DEPENDENCIES_QT6_SO_FILES := $(foreach L,$(QT6_PORT_LIBS),$(call so_path,$L))
+BUILD_DEPENDENCIES_QT6_ABI_FILES := $(foreach L,$(QT6_PORT_LIBS),$(call abi_path,$L))
+
+$(BUILD_DEPENDENCIES_QT6_ABI_FILES):
+ $(VERBOSE)mkdir -p $(dir $@)
+ $(VERBOSE)$(MAKE) -C $(dir $@) -f $(BASE_DIR)/mk/abi.mk \
+ SYMBOLS=$(call abi_symbol_path,$(call abi_name,$@)) \
+ LIB=$(call abi_name,$@) \
+ BUILD_BASE_DIR=$(BUILD_BASE_DIR) \
+ SHELL=$(SHELL)
+
+$(BUILD_DEPENDENCIES_QT6_SO_FILES): $(BUILD_DEPENDENCIES_QT6_ABI_FILES)
+
+.PHONY: qt6_so_files
+
+qt6_so_files: $(BUILD_DEPENDENCIES_QT6_SO_FILES)
+ $(VERBOSE)for l in $(QT6_PORT_LIBS); do \
+ ln -sf ../abi/$$l/$$l.abi.so build_dependencies/lib/$$l.lib.so; done
diff --git a/repos/libports/lib/import/import-qt6_cmake.mk b/repos/libports/lib/import/import-qt6_cmake.mk
new file mode 100644
index 0000000000..2f150e17c6
--- /dev/null
+++ b/repos/libports/lib/import/import-qt6_cmake.mk
@@ -0,0 +1,142 @@
+#
+# The following externally defined variables are evaluated:
+#
+# CMAKE_LISTS_DIR: path to the CMakeLists.txt file
+# CMAKE_TARGET_BINARIES binaries to be stripped and linked into 'bin' and 'debug' directories
+# QT6_PORT_LIBS: Qt6 libraries used from port (for example libQt6Core)
+# QT6_COMPONENT_LIB_SO: if defined empty, disables linking with qt6_component.lib.so
+#
+
+include $(call select_from_repositories,lib/import/import-qt6.inc)
+
+#
+# flags to be passed to CMake
+#
+
+GENODE_CMAKE_CFLAGS += \
+ -D__FreeBSD__=12 \
+ -D__GENODE__ \
+ -ffunction-sections \
+ -fno-strict-aliasing \
+ $(CC_OPT_NOSTDINC) \
+ $(CC_MARCH) \
+ $(CC_OPT_PIC) \
+ $(filter-out -I.,$(INCLUDES)) \
+ -I$(CURDIR)/build_dependencies/mkspecs/$(QT_PLATFORM)
+
+GENODE_CMAKE_LFLAGS_APP += \
+ $(addprefix $(LD_OPT_PREFIX),$(LD_MARCH)) \
+ $(addprefix $(LD_OPT_PREFIX),$(LD_OPT_GC_SECTIONS)) \
+ $(addprefix $(LD_OPT_PREFIX),$(LD_OPT_ALIGN_SANE)) \
+ $(addprefix $(LD_OPT_PREFIX),--dynamic-list=$(BASE_DIR)/src/ld/genode_dyn.dl) \
+ $(LD_OPT_NOSTDLIB) \
+ -Wl,-Ttext=0x01000000 \
+ $(CC_MARCH) \
+ -Wl,--dynamic-linker=$(DYNAMIC_LINKER).lib.so \
+ -Wl,--eh-frame-hdr \
+ -Wl,-rpath-link=. \
+ -Wl,-T -Wl,$(LD_SCRIPT_DYN) \
+ -L$(CURDIR)/build_dependencies/lib \
+ -Wl,--whole-archive \
+ -Wl,--start-group \
+ $(addprefix -l:,$(QT6_GENODE_LIBS_APP)) \
+ $(shell $(CC) $(CC_MARCH) -print-libgcc-file-name) \
+ -Wl,--end-group \
+ -Wl,--no-whole-archive
+
+GENODE_CMAKE_LFLAGS_SHLIB += \
+ $(LD_OPT_NOSTDLIB) \
+ -Wl,-shared \
+ -Wl,--eh-frame-hdr \
+ $(addprefix $(LD_OPT_PREFIX),$(LD_MARCH)) \
+ $(addprefix $(LD_OPT_PREFIX),$(LD_OPT_GC_SECTIONS)) \
+ $(addprefix $(LD_OPT_PREFIX),$(LD_OPT_ALIGN_SANE)) \
+ -Wl,-T -Wl,$(LD_SCRIPT_SO) \
+ $(addprefix $(LD_OPT_PREFIX),--entry=0x0) \
+ -L$(CURDIR)/build_dependencies/lib \
+ -Wl,--whole-archive \
+ -Wl,--start-group \
+ $(addprefix -l:,$(QT6_GENODE_LIBS_SHLIB)) \
+ $(shell $(CC) $(CC_MARCH) -print-libgcc-file-name) \
+ -l:ldso_so_support.lib.a \
+ -Wl,--end-group \
+ -Wl,--no-whole-archive
+
+##
+## prepare a directory named 'build_dependencies' where CMake can find needed files
+##
+
+build_dependencies/lib/cmake: build_dependencies/lib
+ $(VERBOSE)ln -snf $(QT_API_DIR)/lib/cmake $@
+
+build_dependencies/metatypes: build_dependencies
+ $(VERBOSE)ln -snf $(QT_API_DIR)/metatypes $@
+
+build_dependencies/mkspecs: build_dependencies
+ $(VERBOSE)ln -snf $(QT_API_DIR)/mkspecs $@
+
+cmake_prepared.tag: \
+ build_dependencies/include \
+ build_dependencies/lib/cmake \
+ build_dependencies/lib/libc.lib.so \
+ build_dependencies/lib/libm.lib.so \
+ build_dependencies/lib/egl.lib.so \
+ build_dependencies/lib/mesa.lib.so \
+ build_dependencies/lib/qt6_component.lib.so \
+ build_dependencies/lib/stdcxx.lib.so \
+ build_dependencies/lib/ldso_so_support.lib.a \
+ build_dependencies/metatypes \
+ build_dependencies/mkspecs
+ $(VERBOSE)touch $@
+
+.PHONY: build_with_cmake
+
+# 'make' called by CMake uses '/bin/sh', which does not understand '-o pipefail'
+unexport .SHELLFLAGS
+
+build_with_cmake: cmake_prepared.tag qt6_so_files
+ $(VERBOSE)cmake \
+ -G "Unix Makefiles" \
+ -DCMAKE_PREFIX_PATH="$(CURDIR)/build_dependencies" \
+ -DCMAKE_MODULE_PATH="$(CURDIR)/build_dependencies/lib/cmake/Modules" \
+ -DCMAKE_SYSTEM_NAME="Genode" \
+ -DCMAKE_AR="$(AR)" \
+ -DCMAKE_C_COMPILER="$(CC)" \
+ -DCMAKE_C_FLAGS="$(GENODE_CMAKE_CFLAGS)" \
+ -DCMAKE_CXX_COMPILER="$(CXX)" \
+ -DCMAKE_CXX_FLAGS="$(GENODE_CMAKE_CFLAGS)" \
+ -DCMAKE_EXE_LINKER_FLAGS="$(GENODE_CMAKE_LFLAGS_APP)" \
+ -DCMAKE_SHARED_LINKER_FLAGS="$(GENODE_CMAKE_LFLAGS_SHLIB)" \
+ -DCMAKE_MODULE_LINKER_FLAGS="$(GENODE_CMAKE_LFLAGS_SHLIB)" \
+ --no-warn-unused-cli \
+ $(CMAKE_LISTS_DIR) \
+ $(QT6_OUTPUT_FILTER)
+
+ $(VERBOSE)$(MAKE) VERBOSE=$(MAKE_VERBOSE)
+
+#
+# Not every CMake project has an 'install' target, so execute
+# this target only if a binary to be installed has "install/" in
+# its path.
+#
+ifneq ($(findstring install/,$(CMAKE_TARGET_BINARIES)),)
+ $(VERBOSE)$(MAKE) VERBOSE=$(MAKE_VERBOSE) DESTDIR=install install
+endif
+
+ $(VERBOSE)for cmake_target_binary in $(CMAKE_TARGET_BINARIES); do \
+ $(OBJCOPY) --only-keep-debug $${cmake_target_binary} $${cmake_target_binary}.debug; \
+ $(STRIP) $${cmake_target_binary} -o $${cmake_target_binary}.stripped; \
+ $(OBJCOPY) --add-gnu-debuglink=$${cmake_target_binary}.debug $${cmake_target_binary}.stripped; \
+ ln -sf $(CURDIR)/$${cmake_target_binary}.stripped $(PWD)/bin/`basename $${cmake_target_binary}`; \
+ ln -sf $(CURDIR)/$${cmake_target_binary}.stripped $(PWD)/debug/`basename $${cmake_target_binary}`; \
+ ln -sf $(CURDIR)/$${cmake_target_binary}.debug $(PWD)/debug/; \
+ done
+
+BUILD_ARTIFACTS += $(notdir $(CMAKE_TARGET_BINARIES))
+
+#
+# build applications with CMake
+#
+TARGET ?= $(CMAKE_LISTS_DIR).cmake_target
+.PHONY: $(TARGET)
+$(TARGET): build_with_cmake $(QT6_EXTRA_TARGET_DEPS)
diff --git a/repos/libports/lib/import/import-qt6_qmake.mk b/repos/libports/lib/import/import-qt6_qmake.mk
new file mode 100644
index 0000000000..f0bac79932
--- /dev/null
+++ b/repos/libports/lib/import/import-qt6_qmake.mk
@@ -0,0 +1,176 @@
+#
+# The following externally defined variables are evaluated:
+#
+# QMAKE_PROJECT_FILE: path to the qmake project file (for applications with target.mk)
+# QMAKE_TARGET_BINARIES binaries to be stripped and linked into 'bin' and 'debug' directories
+# QT6_PORT_LIBS: Qt6 libraries used from port (for example libQt6Core)
+# QT6_COMPONENT_LIB_SO: if defined empty, disables linking with qt6_component.lib.so
+#
+
+include $(call select_from_repositories,lib/import/import-qt6.inc)
+
+QMAKE = build_dependencies/bin/qmake
+
+#
+# flags to be passed to qmake via env.sh and mkspecs/common/genode.conf
+#
+
+GENODE_QMAKE_CFLAGS += \
+ -D__FreeBSD__=12 \
+ -D__GENODE__ \
+ -ffunction-sections \
+ -fno-strict-aliasing \
+ $(CC_OPT_NOSTDINC) \
+ $(CC_MARCH) \
+ $(CC_OPT_PIC) \
+ $(filter-out -I.,$(INCLUDES)) \
+ -I$(CURDIR)/build_dependencies/include/QtCore/spec/$(QT_PLATFORM)
+
+GENODE_QMAKE_LFLAGS_APP += \
+ $(addprefix $(LD_OPT_PREFIX),$(LD_MARCH)) \
+ $(addprefix $(LD_OPT_PREFIX),$(LD_OPT_GC_SECTIONS)) \
+ $(addprefix $(LD_OPT_PREFIX),$(LD_OPT_ALIGN_SANE)) \
+ $(addprefix $(LD_OPT_PREFIX),--dynamic-list=$(BASE_DIR)/src/ld/genode_dyn.dl) \
+ $(LD_OPT_NOSTDLIB) \
+ -Wl,-Ttext=0x01000000 \
+ $(CC_MARCH) \
+ -Wl,--dynamic-linker=$(DYNAMIC_LINKER).lib.so \
+ -Wl,--eh-frame-hdr \
+ -Wl,-rpath-link=. \
+ -Wl,-T -Wl,$(LD_SCRIPT_DYN) \
+ -L$(CURDIR)/build_dependencies/lib \
+ -Wl,--whole-archive \
+ -Wl,--start-group \
+ $(addprefix -l:,$(QT6_GENODE_LIBS_APP)) \
+ -Wl,--end-group \
+ -Wl,--no-whole-archive
+
+GENODE_QMAKE_LFLAGS_SHLIB += \
+ $(LD_OPT_NOSTDLIB) \
+ -Wl,-shared \
+ -Wl,--eh-frame-hdr \
+ $(addprefix $(LD_OPT_PREFIX),$(LD_MARCH)) \
+ $(addprefix $(LD_OPT_PREFIX),$(LD_OPT_GC_SECTIONS)) \
+ $(addprefix $(LD_OPT_PREFIX),$(LD_OPT_ALIGN_SANE)) \
+ -Wl,-T -Wl,$(LD_SCRIPT_SO) \
+ $(addprefix $(LD_OPT_PREFIX),--entry=0x0) \
+ -L$(CURDIR)/build_dependencies/lib \
+ -Wl,--whole-archive \
+ -Wl,--start-group \
+ $(addprefix -l:,$(QT6_GENODE_LIBS_SHLIB)) \
+ -l:ldso_so_support.lib.a \
+ -Wl,--end-group \
+ -Wl,--no-whole-archive
+
+#
+# libgcc must appear on the command line after all other libs
+# (including those added by qmake) and using the QMAKE_LIBS
+# variable achieves this, fortunately
+#
+GENODE_QMAKE_LIBS = \
+ $(shell $(CC) $(CC_MARCH) -print-libgcc-file-name)
+
+ifeq ($(CONTRIB_DIR),)
+GENODE_QMAKE_INCDIR_OPENGL = $(call select_from_repositories,include/GL)/..
+GENODE_QMAKE_INCDIR_EGL = $(call select_from_repositories,include/EGL)/..
+else
+GENODE_QMAKE_INCDIR_OPENGL := $(call select_from_ports,mesa)/include
+GENODE_QMAKE_INCDIR_EGL := $(call select_from_ports,mesa)/include
+endif
+
+GENODE_QMAKE_LIBS_OPENGL = $(CURDIR)/build_dependencies/lib/mesa.lib.so
+GENODE_QMAKE_LIBS_EGL = $(CURDIR)/build_dependencies/lib/egl.lib.so
+
+#
+# export variables for qmake.conf
+#
+
+env.sh:
+ $(VERBOSE)rm -f $@
+ $(VERBOSE)echo "export GENODE_QMAKE_CC='$(CC)'" >> $@
+ $(VERBOSE)echo "export GENODE_QMAKE_CXX='$(CXX)'" >> $@
+ $(VERBOSE)echo "export GENODE_QMAKE_LINK='$(CXX)'" >> $@
+ $(VERBOSE)echo "export GENODE_QMAKE_AR='$(AR)'" >> $@
+ $(VERBOSE)echo "export GENODE_QMAKE_OBJCOPY='$(OBJCOPY)'" >> $@
+ $(VERBOSE)echo "export GENODE_QMAKE_NM='$(NM)'" >> $@
+ $(VERBOSE)echo "export GENODE_QMAKE_STRIP='$(STRIP)'" >> $@
+ $(VERBOSE)echo "export GENODE_QMAKE_CFLAGS='$(GENODE_QMAKE_CFLAGS)'" >> $@
+ $(VERBOSE)echo "export GENODE_QMAKE_LFLAGS_APP='$(GENODE_QMAKE_LFLAGS_APP)'" >> $@
+ $(VERBOSE)echo "export GENODE_QMAKE_LFLAGS_SHLIB='$(GENODE_QMAKE_LFLAGS_SHLIB)'" >> $@
+ $(VERBOSE)echo "export GENODE_QMAKE_LIBS='$(GENODE_QMAKE_LIBS)'" >> $@
+ $(VERBOSE)echo "export GENODE_QMAKE_INCDIR_OPENGL='$(GENODE_QMAKE_INCDIR_OPENGL)'" >> $@
+ $(VERBOSE)echo "export GENODE_QMAKE_LIBS_OPENGL='$(GENODE_QMAKE_LIBS_OPENGL)'" >> $@
+ $(VERBOSE)echo "export GENODE_QMAKE_INCDIR_EGL='$(GENODE_QMAKE_INCDIR_EGL)'" >> $@
+ $(VERBOSE)echo "export GENODE_QMAKE_LIBS_EGL='$(GENODE_QMAKE_LIBS_EGL)'" >> $@
+
+
+#
+# prepare a directory named 'build_dependencies' where qmake can find needed files
+#
+
+build_dependencies/bin: build_dependencies
+ $(VERBOSE)mkdir -p $@
+ $(VERBOSE)ln -sf $(QT_TOOLS_DIR)/bin/* $@/
+
+build_dependencies/lib/libQt6Core.so.6: build_dependencies/lib
+ $(VERBOSE)ln -sf $(QT_TOOLS_DIR)/lib/libQt6Core.so.6 $@
+
+build_dependencies/libexec: build_dependencies
+ $(VERBOSE)mkdir -p $@
+ $(VERBOSE)ln -sf $(QT_TOOLS_DIR)/libexec/* $@/
+
+build_dependencies/mkspecs: build_dependencies
+ $(VERBOSE)mkdir -p $@
+ $(VERBOSE)ln -sf $(QT_API_DIR)/mkspecs/* $@/
+ $(VERBOSE)rm -f $@/modules
+ $(VERBOSE)mkdir $@/modules
+ $(VERBOSE)ln -snf $(QT_API_DIR)/mkspecs/modules/* $@/modules/
+ $(VERBOSE)ln -sf $(QT_PLATFORM)/qconfig.pri $@/
+ $(VERBOSE)ln -sf $(QT_PLATFORM)/qmodule.pri $@/
+
+qmake_prepared.tag: env.sh \
+ build_dependencies/bin \
+ build_dependencies/include \
+ build_dependencies/lib/libQt6Core.so.6 \
+ build_dependencies/lib/libc.lib.so \
+ build_dependencies/lib/libm.lib.so \
+ build_dependencies/lib/egl.lib.so \
+ build_dependencies/lib/mesa.lib.so \
+ build_dependencies/lib/qt6_component.lib.so \
+ build_dependencies/lib/stdcxx.lib.so \
+ build_dependencies/lib/ldso_so_support.lib.a \
+ build_dependencies/libexec \
+ build_dependencies/mkspecs
+ $(VERBOSE)touch $@
+
+.PHONY: build_with_qmake
+
+build_with_qmake: qmake_prepared.tag qt6_so_files
+
+ $(VERBOSE)source env.sh && $(QMAKE) \
+ -spec build_dependencies/mkspecs/$(QT_PLATFORM) \
+ -qtconf build_dependencies/mkspecs/$(QT_PLATFORM)/qt.conf \
+ -nocache \
+ $(QMAKE_PROJECT_FILE) \
+ "CONFIG += force_debug_info" \
+ $(QT6_OUTPUT_FILTER)
+
+ $(VERBOSE)source env.sh && $(MAKE) $(QT6_OUTPUT_FILTER)
+
+ $(VERBOSE)for qmake_target_binary in $(QMAKE_TARGET_BINARIES); do \
+ $(OBJCOPY) --only-keep-debug $${qmake_target_binary} $${qmake_target_binary}.debug; \
+ $(STRIP) $${qmake_target_binary} -o $${qmake_target_binary}.stripped; \
+ $(OBJCOPY) --add-gnu-debuglink=$${qmake_target_binary}.debug $${qmake_target_binary}.stripped; \
+ ln -sf $(CURDIR)/$${qmake_target_binary}.stripped $(PWD)/bin/$${qmake_target_binary}; \
+ ln -sf $(CURDIR)/$${qmake_target_binary}.stripped $(PWD)/debug/$${qmake_target_binary}; \
+ ln -sf $(CURDIR)/$${qmake_target_binary}.debug $(PWD)/debug/; \
+ done
+
+BUILD_ARTIFACTS += $(notdir $(QMAKE_TARGET_BINARIES))
+
+#
+# build applications with qmake
+#
+TARGET ?= $(notdir $(QMAKE_PROJECT_FILE)).qmake_target
+.PHONY: $(TARGET)
+$(TARGET): build_with_qmake $(QT6_EXTRA_TARGET_DEPS)
diff --git a/repos/libports/lib/mk/qt6_base.mk b/repos/libports/lib/mk/qt6_base.mk
new file mode 100644
index 0000000000..f5631041b8
--- /dev/null
+++ b/repos/libports/lib/mk/qt6_base.mk
@@ -0,0 +1,118 @@
+LIBS = qt6_cmake ldso_so_support libc libm stdcxx qt6_component egl mesa base qoost
+
+INSTALL_LIBS = lib/libQt6Concurrent.lib.so \
+ lib/libQt6Core.lib.so \
+ lib/libQt6Gui.lib.so \
+ lib/libQt6Network.lib.so \
+ lib/libQt6OpenGL.lib.so \
+ lib/libQt6OpenGLWidgets.lib.so \
+ lib/libQt6PrintSupport.lib.so \
+ lib/libQt6Sql.lib.so \
+ lib/libQt6Test.lib.so \
+ lib/libQt6Widgets.lib.so \
+ lib/libQt6Xml.lib.so \
+ plugins/platforms/libqgenode.lib.so \
+ plugins/imageformats/libqjpeg.lib.so \
+ plugins/sqldrivers/libqsqlite.lib.so
+
+BUILD_ARTIFACTS = $(notdir $(INSTALL_LIBS)) \
+ qt6_libqgenode.tar \
+ qt6_libqjpeg.tar \
+ qt6_libqsqlite.tar
+
+cmake_prepared.tag: build_dependencies/lib/ld.lib.so
+
+build: cmake_prepared.tag
+
+ @#
+ @# run cmake
+ @#
+
+ $(VERBOSE)cmake \
+ -G "Unix Makefiles" \
+ -DQT_SILENCE_CMAKE_GENERATOR_WARNING=ON \
+ -DCMAKE_SYSTEM_NAME="Genode" \
+ -DCMAKE_AR="$(AR)" \
+ -DCMAKE_C_COMPILER="$(CC)" \
+ -DCMAKE_C_FLAGS="$(GENODE_CMAKE_CFLAGS)" \
+ -DCMAKE_CXX_COMPILER="$(CXX)" \
+ -DCMAKE_CXX_FLAGS="$(GENODE_CMAKE_CFLAGS)" \
+ -DCMAKE_EXE_LINKER_FLAGS="$(GENODE_CMAKE_LFLAGS_APP)" \
+ -DCMAKE_SHARED_LINKER_FLAGS="$(GENODE_CMAKE_LFLAGS_SHLIB)" \
+ -DCMAKE_MODULE_LINKER_FLAGS="$(GENODE_CMAKE_LFLAGS_SHLIB)" \
+ -DQT_QMAKE_TARGET_MKSPEC=$(QT_PLATFORM) \
+ -DCMAKE_INSTALL_PREFIX=/qt \
+ -DQT_HOST_PATH="$(QT_TOOLS_DIR)" \
+ -DBUILD_WITH_PCH=OFF \
+ -DCMAKE_BUILD_TYPE=RelWithDebInfo \
+ -DQT_BUILD_EXAMPLES=OFF \
+ -DQT_QPA_DEFAULT_PLATFORM=genode \
+ -DFEATURE_cxx20=ON \
+ -DFEATURE_relocatable=OFF \
+ -DFEATURE_evdev=OFF \
+ -DFEATURE_icu=OFF \
+ -DFEATURE_system_harfbuzz=OFF \
+ -DFEATURE_backtrace=OFF \
+ -DFEATURE_glib=OFF \
+ -DFEATURE_zstd=OFF \
+ -DFEATURE_system_pcre2=OFF \
+ -DFEATURE_system_zlib=OFF \
+ -DFEATURE_dbus=OFF \
+ -DFEATURE_libudev=OFF \
+ -DFEATURE_opengl_desktop=ON \
+ -DFEATURE_egl=ON \
+ -DFEATURE_xkbcommon=OFF \
+ -DFEATURE_networkinterface=OFF \
+ -DFEATURE_vulkan=OFF \
+ -DFEATURE_reduce_relocations=OFF \
+ -DFEATURE_pkg_config=OFF \
+ $(QT_DIR)/qtbase \
+ $(QT6_OUTPUT_FILTER)
+
+ @#
+ @# build
+ @#
+
+ $(VERBOSE)$(MAKE) VERBOSE=$(MAKE_VERBOSE)
+
+ @#
+ @# install into local 'install' directory
+ @#
+
+ $(VERBOSE)$(MAKE) VERBOSE=$(MAKE_VERBOSE) DESTDIR=install install
+
+ @#
+ @# remove shared library existence checks since many libs are not
+ @# present and not needed at build time
+ @#
+
+ $(VERBOSE)find $(CURDIR)/install/qt/lib/cmake -name "*.cmake" \
+ -exec sed -i "/list(APPEND _IMPORT_CHECK_TARGETS /d" {} \;
+
+ @#
+ @# strip libs and create symlinks in 'bin' and 'debug' directories
+ @#
+
+ $(VERBOSE)for LIB in $(INSTALL_LIBS); do \
+ cd $(CURDIR)/install/qt/$$(dirname $${LIB}) && \
+ $(OBJCOPY) --only-keep-debug $$(basename $${LIB}) $$(basename $${LIB}).debug && \
+ $(STRIP) $$(basename $${LIB}) -o $$(basename $${LIB}).stripped && \
+ $(OBJCOPY) --add-gnu-debuglink=$$(basename $${LIB}).debug $$(basename $${LIB}).stripped; \
+ ln -sf $(CURDIR)/install/qt/$${LIB}.stripped $(PWD)/bin/$$(basename $${LIB}); \
+ ln -sf $(CURDIR)/install/qt/$${LIB}.stripped $(PWD)/debug/$$(basename $${LIB}); \
+ ln -sf $(CURDIR)/install/qt/$${LIB}.debug $(PWD)/debug/; \
+ done
+
+ @#
+ @# create tar archives
+ @#
+
+ $(VERBOSE)tar chf $(PWD)/bin/qt6_libqgenode.tar $(TAR_OPT) --transform='s/\.stripped//' -C install qt/plugins/platforms/libqgenode.lib.so.stripped
+ $(VERBOSE)tar chf $(PWD)/bin/qt6_libqjpeg.tar $(TAR_OPT) --transform='s/\.stripped//' -C install qt/plugins/imageformats/libqjpeg.lib.so.stripped
+ $(VERBOSE)tar chf $(PWD)/bin/qt6_libqsqlite.tar $(TAR_OPT) --transform='s/\.stripped//' -C install qt/plugins/sqldrivers/libqsqlite.lib.so.stripped
+
+.PHONY: build
+
+ifeq ($(called_from_lib_mk),yes)
+all: build
+endif
diff --git a/repos/libports/lib/mk/qt6_cmake.mk b/repos/libports/lib/mk/qt6_cmake.mk
new file mode 100644
index 0000000000..4c6aa44d3a
--- /dev/null
+++ b/repos/libports/lib/mk/qt6_cmake.mk
@@ -0,0 +1,4 @@
+#
+# This is a dummy library description file for the implicit inclusion of
+# import-qt6_cmake.mk.
+#
diff --git a/repos/libports/lib/mk/qt6_component.mk b/repos/libports/lib/mk/qt6_component.mk
new file mode 100644
index 0000000000..41ef3bab29
--- /dev/null
+++ b/repos/libports/lib/mk/qt6_component.mk
@@ -0,0 +1,9 @@
+SRC_CC = qt_component.cc
+
+LIBS = libc
+
+SHARED_LIB = yes
+
+vpath qt_component.cc $(REP_DIR)/src/lib/qt6_component
+
+CC_CXX_WARN_STRICT =
diff --git a/repos/libports/lib/mk/qt6_declarative.mk b/repos/libports/lib/mk/qt6_declarative.mk
new file mode 100644
index 0000000000..80e65b7bb8
--- /dev/null
+++ b/repos/libports/lib/mk/qt6_declarative.mk
@@ -0,0 +1,140 @@
+QT6_PORT_LIBS = libQt6Core libQt6Gui libQt6OpenGL libQt6Network libQt6Sql libQt6Test libQt6Widgets
+
+LIBS = qt6_cmake ldso_so_support libc libm mesa egl qt6_component stdcxx
+
+INSTALL_LIBS = lib/libQt6LabsAnimation.lib.so \
+ lib/libQt6LabsFolderListModel.lib.so \
+ lib/libQt6LabsQmlModels.lib.so \
+ lib/libQt6LabsSettings.lib.so \
+ lib/libQt6LabsSharedImage.lib.so \
+ lib/libQt6LabsWavefrontMesh.lib.so \
+ lib/libQt6Qml.lib.so \
+ lib/libQt6QmlCompiler.lib.so \
+ lib/libQt6QmlCore.lib.so \
+ lib/libQt6QmlLocalStorage.lib.so \
+ lib/libQt6QmlModels.lib.so \
+ lib/libQt6QmlWorkerScript.lib.so \
+ lib/libQt6QmlXmlListModel.lib.so \
+ lib/libQt6Quick.lib.so \
+ lib/libQt6QuickControls2.lib.so \
+ lib/libQt6QuickControls2Impl.lib.so \
+ lib/libQt6QuickDialogs2.lib.so \
+ lib/libQt6QuickDialogs2QuickImpl.lib.so \
+ lib/libQt6QuickDialogs2Utils.lib.so \
+ lib/libQt6QuickEffects.lib.so \
+ lib/libQt6QuickLayouts.lib.so \
+ lib/libQt6QuickParticles.lib.so \
+ lib/libQt6QuickShapes.lib.so \
+ lib/libQt6QuickTemplates2.lib.so \
+ lib/libQt6QuickTest.lib.so \
+ lib/libQt6QuickWidgets.lib.so \
+ qml/Qt/labs/animation/liblabsanimationplugin.lib.so \
+ qml/Qt/labs/folderlistmodel/libqmlfolderlistmodelplugin.lib.so \
+ qml/Qt/labs/platform/libqtlabsplatformplugin.lib.so \
+ qml/Qt/labs/qmlmodels/liblabsmodelsplugin.lib.so \
+ qml/Qt/labs/settings/libqmlsettingsplugin.lib.so \
+ qml/Qt/labs/sharedimage/libsharedimageplugin.lib.so \
+ qml/Qt/labs/wavefrontmesh/libqmlwavefrontmeshplugin.lib.so \
+ qml/QtQml/Base/libqmlplugin.lib.so \
+ qml/QtQml/Models/libmodelsplugin.lib.so \
+ qml/QtQml/WorkerScript/libworkerscriptplugin.lib.so \
+ qml/QtQml/XmlListModel/libqmlxmllistmodelplugin.lib.so \
+ qml/QtQml/libqmlmetaplugin.lib.so \
+ qml/QtQuick/Controls/Basic/libqtquickcontrols2basicstyleplugin.lib.so \
+ qml/QtQuick/Controls/Basic/impl/libqtquickcontrols2basicstyleimplplugin.lib.so \
+ qml/QtQuick/Controls/Fusion/libqtquickcontrols2fusionstyleplugin.lib.so \
+ qml/QtQuick/Controls/Fusion/impl/libqtquickcontrols2fusionstyleimplplugin.lib.so \
+ qml/QtQuick/Controls/Imagine/libqtquickcontrols2imaginestyleplugin.lib.so \
+ qml/QtQuick/Controls/Imagine/impl/libqtquickcontrols2imaginestyleimplplugin.lib.so \
+ qml/QtQuick/Controls/Material/libqtquickcontrols2materialstyleplugin.lib.so \
+ qml/QtQuick/Controls/Material/impl/libqtquickcontrols2materialstyleimplplugin.lib.so \
+ qml/QtQuick/Controls/Universal/libqtquickcontrols2universalstyleplugin.lib.so \
+ qml/QtQuick/Controls/Universal/impl/libqtquickcontrols2universalstyleimplplugin.lib.so \
+ qml/QtQuick/Controls/libqtquickcontrols2plugin.lib.so \
+ qml/QtQuick/Controls/impl/libqtquickcontrols2implplugin.lib.so \
+ qml/QtQuick/Dialogs/libqtquickdialogsplugin.lib.so \
+ qml/QtQuick/Dialogs/quickimpl/libqtquickdialogs2quickimplplugin.lib.so \
+ qml/QtQuick/Effects/libeffectsplugin.lib.so \
+ qml/QtQuick/Layouts/libqquicklayoutsplugin.lib.so \
+ qml/QtQuick/LocalStorage/libqmllocalstorageplugin.lib.so \
+ qml/QtQuick/NativeStyle/libqtquickcontrols2nativestyleplugin.lib.so \
+ qml/QtQuick/Particles/libparticlesplugin.lib.so \
+ qml/QtQuick/Shapes/libqmlshapesplugin.lib.so \
+ qml/QtQuick/Templates/libqtquicktemplates2plugin.lib.so \
+ qml/QtQuick/Window/libquickwindowplugin.lib.so \
+ qml/QtQuick/tooling/libquicktoolingplugin.lib.so \
+ qml/QtQuick/libqtquick2plugin.lib.so \
+ qml/QtTest/libquicktestplugin.lib.so
+
+BUILD_ARTIFACTS = $(notdir $(INSTALL_LIBS)) \
+ qt6_declarative_qml.tar
+
+build: cmake_prepared.tag qt6_so_files
+
+ @#
+ @# run cmake
+ @#
+
+ $(VERBOSE)cmake \
+ -G "Unix Makefiles" \
+ -DCMAKE_PREFIX_PATH="$(CURDIR)/build_dependencies" \
+ -DCMAKE_MODULE_PATH="$(CURDIR)/build_dependencies/lib/cmake/Modules" \
+ -DCMAKE_SYSTEM_NAME="Genode" \
+ -DCMAKE_AR="$(AR)" \
+ -DCMAKE_C_COMPILER="$(CC)" \
+ -DCMAKE_C_FLAGS="$(GENODE_CMAKE_CFLAGS)" \
+ -DCMAKE_CXX_COMPILER="$(CXX)" \
+ -DCMAKE_CXX_FLAGS="$(GENODE_CMAKE_CFLAGS)" \
+ -DCMAKE_EXE_LINKER_FLAGS="$(GENODE_CMAKE_LFLAGS_APP)" \
+ -DCMAKE_SHARED_LINKER_FLAGS="$(GENODE_CMAKE_LFLAGS_SHLIB)" \
+ -DCMAKE_MODULE_LINKER_FLAGS="$(GENODE_CMAKE_LFLAGS_SHLIB)" \
+ -DQT_QMAKE_TARGET_MKSPEC=$(QT_PLATFORM) \
+ -DCMAKE_INSTALL_PREFIX=/qt \
+ $(QT_DIR)/qtdeclarative \
+ $(QT6_OUTPUT_FILTER)
+
+ @#
+ @# build
+ @#
+
+ $(VERBOSE)$(MAKE) VERBOSE=$(MAKE_VERBOSE)
+
+ @#
+ @# install into local 'install' directory
+ @#
+
+ $(VERBOSE)$(MAKE) VERBOSE=$(MAKE_VERBOSE) DESTDIR=install install
+
+ @#
+ @# remove shared library existence checks since many libs are not
+ @# present and not needed at build time
+ @#
+
+ $(VERBOSE)find $(CURDIR)/install/qt/lib/cmake -name "*.cmake" \
+ -exec sed -i "/list(APPEND _IMPORT_CHECK_TARGETS /d" {} \;
+
+ @#
+ @# strip libs and create symlinks in 'bin' and 'debug' directories
+ @#
+
+ $(VERBOSE)for LIB in $(INSTALL_LIBS); do \
+ cd $(CURDIR)/install/qt/$$(dirname $${LIB}) && \
+ $(OBJCOPY) --only-keep-debug $$(basename $${LIB}) $$(basename $${LIB}).debug && \
+ $(STRIP) $$(basename $${LIB}) -o $$(basename $${LIB}).stripped && \
+ $(OBJCOPY) --add-gnu-debuglink=$$(basename $${LIB}).debug $$(basename $${LIB}).stripped; \
+ ln -sf $(CURDIR)/install/qt/$${LIB}.stripped $(PWD)/bin/$$(basename $${LIB}); \
+ ln -sf $(CURDIR)/install/qt/$${LIB}.stripped $(PWD)/debug/$$(basename $${LIB}); \
+ ln -sf $(CURDIR)/install/qt/$${LIB}.debug $(PWD)/debug/; \
+ done
+
+ @#
+ @# create tar archives
+ @#
+
+ $(VERBOSE)tar chf $(PWD)/bin/qt6_declarative_qml.tar $(TAR_OPT) --exclude='*.lib.so' --transform='s/\.stripped//' -C install qt/qml
+
+.PHONY: build
+
+ifeq ($(called_from_lib_mk),yes)
+all: build
+endif
diff --git a/repos/libports/lib/mk/qt6_qmake.mk b/repos/libports/lib/mk/qt6_qmake.mk
new file mode 100644
index 0000000000..01b38ee57f
--- /dev/null
+++ b/repos/libports/lib/mk/qt6_qmake.mk
@@ -0,0 +1,4 @@
+#
+# This is a dummy library description file for the implicit inclusion of
+# import-qt6_qmake.mk.
+#
diff --git a/repos/libports/lib/mk/qt6_shadertools.mk b/repos/libports/lib/mk/qt6_shadertools.mk
new file mode 100644
index 0000000000..1d955844b8
--- /dev/null
+++ b/repos/libports/lib/mk/qt6_shadertools.mk
@@ -0,0 +1,71 @@
+QT6_PORT_LIBS = libQt6Core libQt6Gui
+
+LIBS = qt6_cmake ldso_so_support libc libm egl mesa qt6_component stdcxx
+
+INSTALL_LIBS = lib/libQt6ShaderTools.lib.so
+
+BUILD_ARTIFACTS = $(notdir $(INSTALL_LIBS))
+
+build: cmake_prepared.tag qt6_so_files
+
+ @#
+ @# run cmake
+ @#
+
+ $(VERBOSE)cmake \
+ -G "Unix Makefiles" \
+ -DCMAKE_PREFIX_PATH="$(CURDIR)/build_dependencies" \
+ -DCMAKE_MODULE_PATH="$(CURDIR)/build_dependencies/lib/cmake/Modules" \
+ -DCMAKE_SYSTEM_NAME="Genode" \
+ -DCMAKE_AR="$(AR)" \
+ -DCMAKE_C_COMPILER="$(CC)" \
+ -DCMAKE_C_FLAGS="$(GENODE_CMAKE_CFLAGS)" \
+ -DCMAKE_CXX_COMPILER="$(CXX)" \
+ -DCMAKE_CXX_FLAGS="$(GENODE_CMAKE_CFLAGS)" \
+ -DCMAKE_EXE_LINKER_FLAGS="$(GENODE_CMAKE_LFLAGS_APP)" \
+ -DCMAKE_SHARED_LINKER_FLAGS="$(GENODE_CMAKE_LFLAGS_SHLIB)" \
+ -DCMAKE_MODULE_LINKER_FLAGS="$(GENODE_CMAKE_LFLAGS_SHLIB)" \
+ -DQT_QMAKE_TARGET_MKSPEC=$(QT_PLATFORM) \
+ -DCMAKE_INSTALL_PREFIX=/qt \
+ $(QT_DIR)/qtshadertools \
+ $(QT6_OUTPUT_FILTER)
+
+ @#
+ @# build
+ @#
+
+ $(VERBOSE)$(MAKE) VERBOSE=$(MAKE_VERBOSE)
+
+ @#
+ @# install into local 'install' directory
+ @#
+
+ $(VERBOSE)$(MAKE) VERBOSE=$(MAKE_VERBOSE) DESTDIR=install install
+
+ @#
+ @# remove shared library existence checks since many libs are not
+ @# present and not needed at build time
+ @#
+
+ $(VERBOSE)find $(CURDIR)/install/qt/lib/cmake -name "*.cmake" \
+ -exec sed -i "/list(APPEND _IMPORT_CHECK_TARGETS /d" {} \;
+
+ @#
+ @# strip libs and create symlinks in 'bin' and 'debug' directories
+ @#
+
+ $(VERBOSE)for LIB in $(INSTALL_LIBS); do \
+ cd $(CURDIR)/install/qt/$$(dirname $${LIB}) && \
+ $(OBJCOPY) --only-keep-debug $$(basename $${LIB}) $$(basename $${LIB}).debug && \
+ $(STRIP) $$(basename $${LIB}) -o $$(basename $${LIB}).stripped && \
+ $(OBJCOPY) --add-gnu-debuglink=$$(basename $${LIB}).debug $$(basename $${LIB}).stripped; \
+ ln -sf $(CURDIR)/install/qt/$${LIB}.stripped $(PWD)/bin/$$(basename $${LIB}); \
+ ln -sf $(CURDIR)/install/qt/$${LIB}.stripped $(PWD)/debug/$$(basename $${LIB}); \
+ ln -sf $(CURDIR)/install/qt/$${LIB}.debug $(PWD)/debug/; \
+ done
+
+.PHONY: build
+
+ifeq ($(called_from_lib_mk),yes)
+all: build
+endif
diff --git a/repos/libports/lib/mk/qt6_svg.mk b/repos/libports/lib/mk/qt6_svg.mk
new file mode 100644
index 0000000000..57806e29f0
--- /dev/null
+++ b/repos/libports/lib/mk/qt6_svg.mk
@@ -0,0 +1,71 @@
+QT6_PORT_LIBS = libQt6Core libQt6Gui libQt6Widgets
+
+LIBS = qt6_cmake ldso_so_support libc libm egl mesa qt6_component stdcxx
+
+INSTALL_LIBS = lib/libQt6Svg.lib.so
+
+BUILD_ARTIFACTS = $(notdir $(INSTALL_LIBS))
+
+build: cmake_prepared.tag qt6_so_files
+
+ @#
+ @# run cmake
+ @#
+
+ $(VERBOSE)cmake \
+ -G "Unix Makefiles" \
+ -DCMAKE_PREFIX_PATH="$(CURDIR)/build_dependencies" \
+ -DCMAKE_MODULE_PATH="$(CURDIR)/build_dependencies/lib/cmake/Modules" \
+ -DCMAKE_SYSTEM_NAME="Genode" \
+ -DCMAKE_AR="$(AR)" \
+ -DCMAKE_C_COMPILER="$(CC)" \
+ -DCMAKE_C_FLAGS="$(GENODE_CMAKE_CFLAGS)" \
+ -DCMAKE_CXX_COMPILER="$(CXX)" \
+ -DCMAKE_CXX_FLAGS="$(GENODE_CMAKE_CFLAGS)" \
+ -DCMAKE_EXE_LINKER_FLAGS="$(GENODE_CMAKE_LFLAGS_APP)" \
+ -DCMAKE_SHARED_LINKER_FLAGS="$(GENODE_CMAKE_LFLAGS_SHLIB)" \
+ -DCMAKE_MODULE_LINKER_FLAGS="$(GENODE_CMAKE_LFLAGS_SHLIB)" \
+ -DQT_QMAKE_TARGET_MKSPEC=$(QT_PLATFORM) \
+ -DCMAKE_INSTALL_PREFIX=/qt \
+ $(QT_DIR)/qtsvg \
+ $(QT6_OUTPUT_FILTER)
+
+ @#
+ @# build
+ @#
+
+ $(VERBOSE)$(MAKE) VERBOSE=$(MAKE_VERBOSE)
+
+ @#
+ @# install into local 'install' directory
+ @#
+
+ $(VERBOSE)$(MAKE) VERBOSE=$(MAKE_VERBOSE) DESTDIR=install install
+
+ @#
+ @# remove shared library existence checks since many libs are not
+ @# present and not needed at build time
+ @#
+
+ $(VERBOSE)find $(CURDIR)/install/qt/lib/cmake -name "*.cmake" \
+ -exec sed -i "/list(APPEND _IMPORT_CHECK_TARGETS /d" {} \;
+
+ @#
+ @# strip libs and create symlinks in 'bin' and 'debug' directories
+ @#
+
+ $(VERBOSE)for LIB in $(INSTALL_LIBS); do \
+ cd $(CURDIR)/install/qt/$$(dirname $${LIB}) && \
+ $(OBJCOPY) --only-keep-debug $$(basename $${LIB}) $$(basename $${LIB}).debug && \
+ $(STRIP) $$(basename $${LIB}) -o $$(basename $${LIB}).stripped && \
+ $(OBJCOPY) --add-gnu-debuglink=$$(basename $${LIB}).debug $$(basename $${LIB}).stripped; \
+ ln -sf $(CURDIR)/install/qt/$${LIB}.stripped $(PWD)/bin/$$(basename $${LIB}); \
+ ln -sf $(CURDIR)/install/qt/$${LIB}.stripped $(PWD)/debug/$$(basename $${LIB}); \
+ ln -sf $(CURDIR)/install/qt/$${LIB}.debug $(PWD)/debug/; \
+ done
+
+.PHONY: build
+
+ifeq ($(called_from_lib_mk),yes)
+all: build
+endif
diff --git a/repos/libports/lib/symbols/qt6_component b/repos/libports/lib/symbols/qt6_component
new file mode 100644
index 0000000000..07cbde1abc
--- /dev/null
+++ b/repos/libports/lib/symbols/qt6_component
@@ -0,0 +1,7 @@
+_ZN4Libc9Component9constructERNS_3EnvE T
+#
+# Make sure there is an undefined reference to "main". Because Qt6 apps don't
+# link the posix library (where main is also undefined), we need this so "main"
+# does not get garbage collected during linking.
+#
+main U
diff --git a/repos/libports/ports/qt6-host.hash b/repos/libports/ports/qt6-host.hash
new file mode 100644
index 0000000000..6010c9fc10
--- /dev/null
+++ b/repos/libports/ports/qt6-host.hash
@@ -0,0 +1 @@
+65bfe06368aa913897c75ac819acb9d1efdf367f
diff --git a/repos/libports/ports/qt6-host.port b/repos/libports/ports/qt6-host.port
new file mode 100644
index 0000000000..107b9edb78
--- /dev/null
+++ b/repos/libports/ports/qt6-host.port
@@ -0,0 +1,8 @@
+LICENSE := GPL
+VERSION := 6.6.2
+
+DOWNLOADS := qt6.archive
+
+URL(qt6) := https://download.qt.io/official_releases/qt/6.6/6.6.2/single/qt-everywhere-src-6.6.2.tar.xz
+SHA(qt6) := 3c1e42b3073ade1f7adbf06863c01e2c59521b7cc2349df2f74ecd7ebfcb922d
+DIR(qt6) := src/lib/qt6
diff --git a/repos/libports/ports/qt6.hash b/repos/libports/ports/qt6.hash
new file mode 100644
index 0000000000..b19de305d9
--- /dev/null
+++ b/repos/libports/ports/qt6.hash
@@ -0,0 +1 @@
+22e90c4bc425795166ebec55fd1853311862bc99
diff --git a/repos/libports/ports/qt6.port b/repos/libports/ports/qt6.port
new file mode 100644
index 0000000000..a4f5229ba8
--- /dev/null
+++ b/repos/libports/ports/qt6.port
@@ -0,0 +1,8 @@
+LICENSE := GPL
+VERSION := 6.6.2
+
+DOWNLOADS := qt6.git
+
+URL(qt6) := https://github.com/cproc/qt6.git
+REV(qt6) := issue5325
+DIR(qt6) := src/lib/qt6
diff --git a/repos/libports/recipes/api/qt6_base/content.mk b/repos/libports/recipes/api/qt6_base/content.mk
new file mode 100644
index 0000000000..25745c7270
--- /dev/null
+++ b/repos/libports/recipes/api/qt6_base/content.mk
@@ -0,0 +1,48 @@
+MIRROR_FROM_REP_DIR := lib/import/import-qt6.inc \
+ lib/import/import-qt6_cmake.mk \
+ lib/import/import-qt6_qmake.mk \
+ lib/mk/qt6_cmake.mk \
+ lib/mk/qt6_qmake.mk
+
+content: $(MIRROR_FROM_REP_DIR)
+
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6)
+API_DIR := $(PORT_DIR)/src/lib/qt6/genode/api
+
+MIRROR_FROM_PORT_DIR := include \
+ metatypes \
+ mkspecs \
+ lib/cmake \
+
+MIRROR_SYMBOLS := lib/symbols/libQt6Concurrent \
+ lib/symbols/libQt6Core \
+ lib/symbols/libQt6Gui \
+ lib/symbols/libQt6Network \
+ lib/symbols/libQt6OpenGL \
+ lib/symbols/libQt6OpenGLWidgets \
+ lib/symbols/libQt6PrintSupport \
+ lib/symbols/libQt6Sql \
+ lib/symbols/libQt6Test \
+ lib/symbols/libQt6Widgets \
+ lib/symbols/libQt6Xml \
+ lib/symbols/libqgenode
+
+content: $(MIRROR_FROM_PORT_DIR)
+
+$(MIRROR_FROM_PORT_DIR):
+ cp -r $(API_DIR)/$@ $@
+
+content: $(MIRROR_SYMBOLS)
+
+$(MIRROR_SYMBOLS):
+ mkdir -p lib/symbols
+ cp $(API_DIR)/$@ lib/symbols
+
+
+content: LICENSE
+
+LICENSE:
+ cp $(PORT_DIR)/src/lib/qt6/LICENSE.LGPL3 $@
diff --git a/repos/libports/recipes/api/qt6_base/hash b/repos/libports/recipes/api/qt6_base/hash
new file mode 100644
index 0000000000..082e66bc73
--- /dev/null
+++ b/repos/libports/recipes/api/qt6_base/hash
@@ -0,0 +1 @@
+2024-07-20 2e4d78a8311cb2ea12f3318ab8e055eeec6cf44d
diff --git a/repos/libports/recipes/api/qt6_component/content.mk b/repos/libports/recipes/api/qt6_component/content.mk
new file mode 100644
index 0000000000..1ef4b861d8
--- /dev/null
+++ b/repos/libports/recipes/api/qt6_component/content.mk
@@ -0,0 +1,10 @@
+MIRROR_FROM_REP_DIR := include/qt6_component \
+ lib/symbols/qt6_component
+
+content: $(MIRROR_FROM_REP_DIR) LICENSE
+
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+LICENSE:
+ cp $(GENODE_DIR)/LICENSE $@
diff --git a/repos/libports/recipes/api/qt6_component/hash b/repos/libports/recipes/api/qt6_component/hash
new file mode 100644
index 0000000000..1cbf1ff673
--- /dev/null
+++ b/repos/libports/recipes/api/qt6_component/hash
@@ -0,0 +1 @@
+2024-02-25 2ab86f26cd18d37d2313fc1a998103d98e2dc37f
diff --git a/repos/libports/recipes/api/qt6_declarative/content.mk b/repos/libports/recipes/api/qt6_declarative/content.mk
new file mode 100644
index 0000000000..aca3de601a
--- /dev/null
+++ b/repos/libports/recipes/api/qt6_declarative/content.mk
@@ -0,0 +1,39 @@
+PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6)
+
+MIRROR_LIB_SYMBOLS := libQt6LabsAnimation \
+ libQt6LabsFolderListModel \
+ libQt6LabsQmlModels \
+ libQt6LabsSettings \
+ libQt6LabsSharedImage \
+ libQt6LabsWavefrontMesh \
+ libQt6Qml \
+ libQt6QmlCompiler \
+ libQt6QmlCore \
+ libQt6QmlLocalStorage \
+ libQt6QmlModels \
+ libQt6QmlWorkerScript \
+ libQt6QmlXmlListModel \
+ libQt6Quick \
+ libQt6QuickControls2 \
+ libQt6QuickControls2Impl \
+ libQt6QuickDialogs2 \
+ libQt6QuickDialogs2QuickImpl \
+ libQt6QuickDialogs2Utils \
+ libQt6QuickEffects \
+ libQt6QuickLayouts \
+ libQt6QuickParticles \
+ libQt6QuickShapes \
+ libQt6QuickTemplates2 \
+ libQt6QuickTest \
+ libQt6QuickWidgets
+
+content: $(MIRROR_LIB_SYMBOLS)
+
+$(MIRROR_LIB_SYMBOLS):
+ mkdir -p lib/symbols
+ cp $(PORT_DIR)/src/lib/qt6/genode/api/lib/symbols/$@ lib/symbols/
+
+content: LICENSE
+
+LICENSE:
+ cp $(PORT_DIR)/src/lib/qt6/LICENSE.LGPL3 $@
diff --git a/repos/libports/recipes/api/qt6_declarative/hash b/repos/libports/recipes/api/qt6_declarative/hash
new file mode 100644
index 0000000000..50559cce76
--- /dev/null
+++ b/repos/libports/recipes/api/qt6_declarative/hash
@@ -0,0 +1 @@
+2024-08-13 b019a06ae7a5361afab6fbde1d2f81911936adc7
diff --git a/repos/libports/recipes/api/qt6_shadertools/content.mk b/repos/libports/recipes/api/qt6_shadertools/content.mk
new file mode 100644
index 0000000000..8b264b5c17
--- /dev/null
+++ b/repos/libports/recipes/api/qt6_shadertools/content.mk
@@ -0,0 +1,14 @@
+PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6)
+
+MIRROR_LIB_SYMBOLS := libQt6ShaderTools
+
+content: $(MIRROR_LIB_SYMBOLS)
+
+$(MIRROR_LIB_SYMBOLS):
+ mkdir -p lib/symbols
+ cp $(PORT_DIR)/src/lib/qt6/genode/api/lib/symbols/$@ lib/symbols/
+
+content: LICENSE
+
+LICENSE:
+ cp $(PORT_DIR)/src/lib/qt6/LICENSE.LGPL3 $@
diff --git a/repos/libports/recipes/api/qt6_shadertools/hash b/repos/libports/recipes/api/qt6_shadertools/hash
new file mode 100644
index 0000000000..50559cce76
--- /dev/null
+++ b/repos/libports/recipes/api/qt6_shadertools/hash
@@ -0,0 +1 @@
+2024-08-13 b019a06ae7a5361afab6fbde1d2f81911936adc7
diff --git a/repos/libports/recipes/api/qt6_svg/content.mk b/repos/libports/recipes/api/qt6_svg/content.mk
new file mode 100644
index 0000000000..a85b1a8c41
--- /dev/null
+++ b/repos/libports/recipes/api/qt6_svg/content.mk
@@ -0,0 +1,14 @@
+PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6)
+
+MIRROR_LIB_SYMBOLS := libQt6Svg
+
+content: $(MIRROR_LIB_SYMBOLS)
+
+$(MIRROR_LIB_SYMBOLS):
+ mkdir -p lib/symbols
+ cp $(PORT_DIR)/src/lib/qt6/genode/api/lib/symbols/$@ lib/symbols/
+
+content: LICENSE
+
+LICENSE:
+ cp $(PORT_DIR)/src/lib/qt6/LICENSE.LGPL3 $@
diff --git a/repos/libports/recipes/api/qt6_svg/hash b/repos/libports/recipes/api/qt6_svg/hash
new file mode 100644
index 0000000000..50559cce76
--- /dev/null
+++ b/repos/libports/recipes/api/qt6_svg/hash
@@ -0,0 +1 @@
+2024-08-13 b019a06ae7a5361afab6fbde1d2f81911936adc7
diff --git a/repos/libports/recipes/raw/qt6_dejavusans/content.mk b/repos/libports/recipes/raw/qt6_dejavusans/content.mk
new file mode 100644
index 0000000000..2570abca6b
--- /dev/null
+++ b/repos/libports/recipes/raw/qt6_dejavusans/content.mk
@@ -0,0 +1,14 @@
+content: qt6_dejavusans.tar LICENSE
+
+PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6)
+
+qt/lib/fonts/DejaVuSans.ttf:
+ mkdir -p $(dir $@)
+ cp $(PORT_DIR)/src/lib/qt6/qtbase/src/3rdparty/wasm/$(notdir $@) $@
+
+qt6_dejavusans.tar: qt/lib/fonts/DejaVuSans.ttf
+ tar --owner=0 --group=0 --numeric-owner --mode='go=' --mtime='1970-01-01 00:00+00' -cf $@ qt
+ rm -rf qt
+
+LICENSE:
+ cp $(PORT_DIR)/src/lib/qt6/qtbase/src/3rdparty/wasm/DEJAVU-LICENSE $@
diff --git a/repos/libports/recipes/raw/qt6_dejavusans/hash b/repos/libports/recipes/raw/qt6_dejavusans/hash
new file mode 100644
index 0000000000..0ed5fe15ec
--- /dev/null
+++ b/repos/libports/recipes/raw/qt6_dejavusans/hash
@@ -0,0 +1 @@
+2024-08-07 38b1c2c107e85224612d1997f05e80e65b1e70f0
diff --git a/repos/libports/recipes/raw/qt6_samegame/content.mk b/repos/libports/recipes/raw/qt6_samegame/content.mk
new file mode 100644
index 0000000000..1aa147c3ff
--- /dev/null
+++ b/repos/libports/recipes/raw/qt6_samegame/content.mk
@@ -0,0 +1,32 @@
+content: qt6_samegame.tar
+
+PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6)
+
+SAMEGAME3_RESOURCES := samegame.qml \
+ Dialog.qml \
+ Button.qml \
+ Block.qml \
+ samegame.js
+
+SAMEGAME_RESOURCES := background.jpg \
+ blueStone.png \
+ greenStone.png \
+ redStone.png
+
+samegame:
+ mkdir -p $@
+
+samegame/pics:
+ mkdir -p $@
+
+$(addprefix samegame/, $(SAMEGAME3_RESOURCES)): samegame
+ cp $(PORT_DIR)/src/lib/qt6/qtdeclarative/examples/quick/tutorials/samegame/samegame3/$(notdir $@) $@
+
+$(addprefix samegame/pics/, $(SAMEGAME_RESOURCES)): samegame/pics
+ cp $(PORT_DIR)/src/lib/qt6/qtdeclarative/examples/quick/tutorials/samegame/samegame3/pics/$(notdir $@) $@
+
+
+qt6_samegame.tar: $(addprefix samegame/, $(SAMEGAME3_RESOURCES)) \
+ $(addprefix samegame/pics/, $(SAMEGAME_RESOURCES))
+ tar --owner=0 --group=0 --numeric-owner --mode='go=' --mtime='1970-01-01 00:00+00' -cf $@ -C samegame .
+ rm -rf samegame/
diff --git a/repos/libports/recipes/raw/qt6_samegame/hash b/repos/libports/recipes/raw/qt6_samegame/hash
new file mode 100644
index 0000000000..0e125d8716
--- /dev/null
+++ b/repos/libports/recipes/raw/qt6_samegame/hash
@@ -0,0 +1 @@
+2024-08-14 d1e0a594a9f6c6ed6f6ce1b54afd2ac9ef8c86dd
diff --git a/repos/libports/recipes/src/qt6_base/api b/repos/libports/recipes/src/qt6_base/api
new file mode 100644
index 0000000000..6bcef21597
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_base/api
@@ -0,0 +1 @@
+qt6_base
diff --git a/repos/libports/recipes/src/qt6_base/content.mk b/repos/libports/recipes/src/qt6_base/content.mk
new file mode 100644
index 0000000000..cab57805c3
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_base/content.mk
@@ -0,0 +1,29 @@
+MIRROR_FROM_REP_DIR := lib/mk/qt6_base.mk
+
+content: $(MIRROR_FROM_REP_DIR)
+
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6)
+
+MIRROR_FROM_PORT_DIR := src/lib/qt6/qtbase
+
+content: $(MIRROR_FROM_PORT_DIR)
+
+$(MIRROR_FROM_PORT_DIR):
+ mkdir -p $(dir $@)
+ cp -r $(PORT_DIR)/$@ $(dir $@)
+
+MIRROR_FROM_OS := include/pointer/shape_report.h
+
+content: $(MIRROR_FROM_OS)
+
+$(MIRROR_FROM_OS):
+ mkdir -p $(dir $@)
+ cp -r $(GENODE_DIR)/repos/os/$@ $(dir $@)
+
+content: LICENSE
+
+LICENSE:
+ cp $(PORT_DIR)/src/lib/qt6/LICENSE.LGPL3 $@
diff --git a/repos/libports/recipes/src/qt6_base/hash b/repos/libports/recipes/src/qt6_base/hash
new file mode 100644
index 0000000000..bd05fba264
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_base/hash
@@ -0,0 +1 @@
+2024-08-07 a283d25ca59402458edd6637d3f6d6d0110462a1
diff --git a/repos/libports/recipes/src/qt6_base/used_apis b/repos/libports/recipes/src/qt6_base/used_apis
new file mode 100644
index 0000000000..e006826f9b
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_base/used_apis
@@ -0,0 +1,15 @@
+base
+blit
+expat
+framebuffer_session
+gui_session
+input_session
+libc
+mesa
+os
+qoost
+qt6_component
+report_session
+so
+stdcxx
+timer_session
diff --git a/repos/libports/recipes/src/qt6_calculatorform/content.mk b/repos/libports/recipes/src/qt6_calculatorform/content.mk
new file mode 100644
index 0000000000..58558b9945
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_calculatorform/content.mk
@@ -0,0 +1,20 @@
+MIRROR_FROM_REP_DIR := src/app/qt6/examples/calculatorform
+
+content: $(MIRROR_FROM_REP_DIR) LICENSE
+
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6)
+
+MIRROR_FROM_PORT_DIR := src/lib/qt6/qttools/examples/designer/calculatorform
+
+content: $(MIRROR_FROM_PORT_DIR)
+
+$(MIRROR_FROM_PORT_DIR):
+ mkdir -p $(dir $@)
+ cp -r $(PORT_DIR)/$@ $(dir $@)
+
+LICENSE:
+ cp $(PORT_DIR)/src/lib/qt6/LICENSE.GPL3 $@
+
diff --git a/repos/libports/recipes/src/qt6_calculatorform/hash b/repos/libports/recipes/src/qt6_calculatorform/hash
new file mode 100644
index 0000000000..7b433ece2e
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_calculatorform/hash
@@ -0,0 +1 @@
+2024-08-07 13465c2fe1317113b33085babc73e5f87501867a
diff --git a/repos/libports/recipes/src/qt6_calculatorform/used_apis b/repos/libports/recipes/src/qt6_calculatorform/used_apis
new file mode 100644
index 0000000000..6de755219a
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_calculatorform/used_apis
@@ -0,0 +1,6 @@
+libc
+mesa
+qt6_base
+qt6_component
+so
+stdcxx
diff --git a/repos/libports/recipes/src/qt6_component/api b/repos/libports/recipes/src/qt6_component/api
new file mode 100644
index 0000000000..1f0f2d4134
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_component/api
@@ -0,0 +1 @@
+qt6_component
diff --git a/repos/libports/recipes/src/qt6_component/content.mk b/repos/libports/recipes/src/qt6_component/content.mk
new file mode 100644
index 0000000000..5387729e2a
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_component/content.mk
@@ -0,0 +1,10 @@
+MIRROR_FROM_REP_DIR := lib/mk/qt6_component.mk \
+ src/lib/qt6_component/qt_component.cc
+
+content: $(MIRROR_FROM_REP_DIR) LICENSE
+
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+LICENSE:
+ cp $(GENODE_DIR)/LICENSE $@
diff --git a/repos/libports/recipes/src/qt6_component/hash b/repos/libports/recipes/src/qt6_component/hash
new file mode 100644
index 0000000000..4e3bd353bd
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_component/hash
@@ -0,0 +1 @@
+2024-06-19 57ef88b3254475486e091dc8f0f954d2f9528cba
diff --git a/repos/libports/recipes/src/qt6_component/used_apis b/repos/libports/recipes/src/qt6_component/used_apis
new file mode 100644
index 0000000000..24ad7bab4c
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_component/used_apis
@@ -0,0 +1,3 @@
+base
+libc
+so
diff --git a/repos/libports/recipes/src/qt6_declarative/api b/repos/libports/recipes/src/qt6_declarative/api
new file mode 100644
index 0000000000..b591c921bf
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_declarative/api
@@ -0,0 +1 @@
+qt6_declarative
diff --git a/repos/libports/recipes/src/qt6_declarative/content.mk b/repos/libports/recipes/src/qt6_declarative/content.mk
new file mode 100644
index 0000000000..c57fc46e9e
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_declarative/content.mk
@@ -0,0 +1,21 @@
+MIRROR_FROM_REP_DIR := lib/mk/qt6_declarative.mk
+
+content: $(MIRROR_FROM_REP_DIR)
+
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6)
+
+MIRROR_FROM_PORT_DIR := src/lib/qt6/qtdeclarative
+
+content: $(MIRROR_FROM_PORT_DIR)
+
+$(MIRROR_FROM_PORT_DIR):
+ mkdir -p $(dir $@)
+ cp -r $(PORT_DIR)/$@ $(dir $@)
+
+content: LICENSE
+
+LICENSE:
+ cp $(PORT_DIR)/src/lib/qt6/LICENSE.LGPL3 $@
diff --git a/repos/libports/recipes/src/qt6_declarative/hash b/repos/libports/recipes/src/qt6_declarative/hash
new file mode 100644
index 0000000000..523638d2d8
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_declarative/hash
@@ -0,0 +1 @@
+2024-08-13 0823c7e39fe4c746ee577f1067992139bb73e731
diff --git a/repos/libports/recipes/src/qt6_declarative/used_apis b/repos/libports/recipes/src/qt6_declarative/used_apis
new file mode 100644
index 0000000000..6de755219a
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_declarative/used_apis
@@ -0,0 +1,6 @@
+libc
+mesa
+qt6_base
+qt6_component
+so
+stdcxx
diff --git a/repos/libports/recipes/src/qt6_launchpad/content.mk b/repos/libports/recipes/src/qt6_launchpad/content.mk
new file mode 100644
index 0000000000..e6695ba638
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_launchpad/content.mk
@@ -0,0 +1,27 @@
+MIRROR_FROM_REP_DIR := src/app/qt6/qt_launchpad
+
+content: $(MIRROR_FROM_REP_DIR) LICENSE
+
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+MIRROR_FROM_DEMO := include/launchpad \
+ lib/mk/launchpad.mk \
+ src/lib/launchpad
+
+content: $(MIRROR_FROM_DEMO)
+
+$(MIRROR_FROM_DEMO):
+ mkdir -p $(dir $@)
+ cp -r $(GENODE_DIR)/repos/demo/$@ $(dir $@)
+
+MIRROR_FROM_OS := include/init/child_policy.h
+
+content: $(MIRROR_FROM_OS)
+
+$(MIRROR_FROM_OS):
+ mkdir -p $(dir $@)
+ cp -r $(GENODE_DIR)/repos/os/$@ $(dir $@)
+
+LICENSE:
+ cp $(GENODE_DIR)/LICENSE $@
diff --git a/repos/libports/recipes/src/qt6_launchpad/hash b/repos/libports/recipes/src/qt6_launchpad/hash
new file mode 100644
index 0000000000..3cdfe0efb3
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_launchpad/hash
@@ -0,0 +1 @@
+2024-08-07 1299305e19d2c766c212224b796691fb690a740e
diff --git a/repos/libports/recipes/src/qt6_launchpad/used_apis b/repos/libports/recipes/src/qt6_launchpad/used_apis
new file mode 100644
index 0000000000..81aee10293
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_launchpad/used_apis
@@ -0,0 +1,9 @@
+base
+libc
+mesa
+os
+qt6_base
+qt6_component
+stdcxx
+timer_session
+vfs
diff --git a/repos/libports/recipes/src/qt6_openglwindow/content.mk b/repos/libports/recipes/src/qt6_openglwindow/content.mk
new file mode 100644
index 0000000000..36bdfa04b4
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_openglwindow/content.mk
@@ -0,0 +1,20 @@
+MIRROR_FROM_REP_DIR := src/app/qt6/examples/openglwindow
+
+content: $(MIRROR_FROM_REP_DIR) LICENSE
+
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6)
+
+MIRROR_FROM_PORT_DIR := src/lib/qt6/qtbase/examples/opengl/openglwindow
+
+content: $(MIRROR_FROM_PORT_DIR)
+
+$(MIRROR_FROM_PORT_DIR):
+ mkdir -p $(dir $@)
+ cp -r $(PORT_DIR)/$@ $(dir $@)
+
+LICENSE:
+ cp $(PORT_DIR)/src/lib/qt6/LICENSE.GPL3 $@
+
diff --git a/repos/libports/recipes/src/qt6_openglwindow/hash b/repos/libports/recipes/src/qt6_openglwindow/hash
new file mode 100644
index 0000000000..24ed7ddfd2
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_openglwindow/hash
@@ -0,0 +1 @@
+2024-08-07 5ef331819960c41bda9d050f7dd8c7f73b76d134
diff --git a/repos/libports/recipes/src/qt6_openglwindow/used_apis b/repos/libports/recipes/src/qt6_openglwindow/used_apis
new file mode 100644
index 0000000000..8d31aa5904
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_openglwindow/used_apis
@@ -0,0 +1,5 @@
+libc
+mesa
+qt6_base
+qt6_component
+stdcxx
diff --git a/repos/libports/recipes/src/qt6_samegame/content.mk b/repos/libports/recipes/src/qt6_samegame/content.mk
new file mode 100644
index 0000000000..fd58d14375
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_samegame/content.mk
@@ -0,0 +1,9 @@
+MIRROR_FROM_REP_DIR := src/app/qt6/examples/samegame
+
+content: $(MIRROR_FROM_REP_DIR) LICENSE
+
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+LICENSE:
+ cp $(GENODE_DIR)/LICENSE $@
diff --git a/repos/libports/recipes/src/qt6_samegame/hash b/repos/libports/recipes/src/qt6_samegame/hash
new file mode 100644
index 0000000000..ad162f74e7
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_samegame/hash
@@ -0,0 +1 @@
+2024-08-14 eadc4679251c14144de7ea807f2ffe25d96d437b
diff --git a/repos/libports/recipes/src/qt6_samegame/used_apis b/repos/libports/recipes/src/qt6_samegame/used_apis
new file mode 100644
index 0000000000..b1d6b3d61d
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_samegame/used_apis
@@ -0,0 +1,6 @@
+libc
+mesa
+qt6_base
+qt6_component
+qt6_declarative
+stdcxx
diff --git a/repos/libports/recipes/src/qt6_shadertools/api b/repos/libports/recipes/src/qt6_shadertools/api
new file mode 100644
index 0000000000..f5686a6e90
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_shadertools/api
@@ -0,0 +1 @@
+qt6_shadertools
diff --git a/repos/libports/recipes/src/qt6_shadertools/content.mk b/repos/libports/recipes/src/qt6_shadertools/content.mk
new file mode 100644
index 0000000000..fd1de80eb7
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_shadertools/content.mk
@@ -0,0 +1,21 @@
+MIRROR_FROM_REP_DIR := lib/mk/qt6_shadertools.mk
+
+content: $(MIRROR_FROM_REP_DIR)
+
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6)
+
+MIRROR_FROM_PORT_DIR := src/lib/qt6/qtshadertools
+
+content: $(MIRROR_FROM_PORT_DIR)
+
+$(MIRROR_FROM_PORT_DIR):
+ mkdir -p $(dir $@)
+ cp -r $(PORT_DIR)/$@ $(dir $@)
+
+content: LICENSE
+
+LICENSE:
+ cp $(PORT_DIR)/src/lib/qt6/LICENSE.LGPL3 $@
diff --git a/repos/libports/recipes/src/qt6_shadertools/hash b/repos/libports/recipes/src/qt6_shadertools/hash
new file mode 100644
index 0000000000..523638d2d8
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_shadertools/hash
@@ -0,0 +1 @@
+2024-08-13 0823c7e39fe4c746ee577f1067992139bb73e731
diff --git a/repos/libports/recipes/src/qt6_shadertools/used_apis b/repos/libports/recipes/src/qt6_shadertools/used_apis
new file mode 100644
index 0000000000..6de755219a
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_shadertools/used_apis
@@ -0,0 +1,6 @@
+libc
+mesa
+qt6_base
+qt6_component
+so
+stdcxx
diff --git a/repos/libports/recipes/src/qt6_svg/api b/repos/libports/recipes/src/qt6_svg/api
new file mode 100644
index 0000000000..bbff0895a6
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_svg/api
@@ -0,0 +1 @@
+qt6_svg
diff --git a/repos/libports/recipes/src/qt6_svg/content.mk b/repos/libports/recipes/src/qt6_svg/content.mk
new file mode 100644
index 0000000000..b3c35bbefb
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_svg/content.mk
@@ -0,0 +1,21 @@
+MIRROR_FROM_REP_DIR := lib/mk/qt6_svg.mk
+
+content: $(MIRROR_FROM_REP_DIR)
+
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6)
+
+MIRROR_FROM_PORT_DIR := src/lib/qt6/qtsvg
+
+content: $(MIRROR_FROM_PORT_DIR)
+
+$(MIRROR_FROM_PORT_DIR):
+ mkdir -p $(dir $@)
+ cp -r $(PORT_DIR)/$@ $(dir $@)
+
+content: LICENSE
+
+LICENSE:
+ cp $(PORT_DIR)/src/lib/qt6/LICENSE.LGPL3 $@
diff --git a/repos/libports/recipes/src/qt6_svg/hash b/repos/libports/recipes/src/qt6_svg/hash
new file mode 100644
index 0000000000..523638d2d8
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_svg/hash
@@ -0,0 +1 @@
+2024-08-13 0823c7e39fe4c746ee577f1067992139bb73e731
diff --git a/repos/libports/recipes/src/qt6_svg/used_apis b/repos/libports/recipes/src/qt6_svg/used_apis
new file mode 100644
index 0000000000..6de755219a
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_svg/used_apis
@@ -0,0 +1,6 @@
+libc
+mesa
+qt6_base
+qt6_component
+so
+stdcxx
diff --git a/repos/libports/recipes/src/qt6_testqstring/content.mk b/repos/libports/recipes/src/qt6_testqstring/content.mk
new file mode 100644
index 0000000000..523366684d
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_testqstring/content.mk
@@ -0,0 +1,20 @@
+MIRROR_FROM_REP_DIR := src/app/qt6/examples/testqstring
+
+content: $(MIRROR_FROM_REP_DIR) LICENSE
+
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6)
+
+MIRROR_FROM_PORT_DIR := src/lib/qt6/qtbase/examples/qtestlib/tutorial1
+
+content: $(MIRROR_FROM_PORT_DIR)
+
+$(MIRROR_FROM_PORT_DIR):
+ mkdir -p $(dir $@)
+ cp -r $(PORT_DIR)/$@ $(dir $@)
+
+LICENSE:
+ cp $(PORT_DIR)/src/lib/qt6/LICENSE.GPL3 $@
+
diff --git a/repos/libports/recipes/src/qt6_testqstring/hash b/repos/libports/recipes/src/qt6_testqstring/hash
new file mode 100644
index 0000000000..0f0b4fc8ce
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_testqstring/hash
@@ -0,0 +1 @@
+2024-08-07 a6f3e57ad6f391a7eef8f2911f811cf93536642f
diff --git a/repos/libports/recipes/src/qt6_testqstring/used_apis b/repos/libports/recipes/src/qt6_testqstring/used_apis
new file mode 100644
index 0000000000..8d31aa5904
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_testqstring/used_apis
@@ -0,0 +1,5 @@
+libc
+mesa
+qt6_base
+qt6_component
+stdcxx
diff --git a/repos/libports/recipes/src/qt6_tetrix/content.mk b/repos/libports/recipes/src/qt6_tetrix/content.mk
new file mode 100644
index 0000000000..71a175a68e
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_tetrix/content.mk
@@ -0,0 +1,19 @@
+MIRROR_FROM_REP_DIR := src/app/qt6/examples/tetrix
+
+content: $(MIRROR_FROM_REP_DIR) LICENSE
+
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6)
+
+MIRROR_FROM_PORT_DIR := src/lib/qt6/qtbase/tests/manual/examples/widgets/widgets/tetrix
+
+content: $(MIRROR_FROM_PORT_DIR)
+
+$(MIRROR_FROM_PORT_DIR):
+ mkdir -p $(dir $@)
+ cp -r $(PORT_DIR)/$@ $(dir $@)
+
+LICENSE:
+ cp $(PORT_DIR)/src/lib/qt6/LICENSE.GPL3 $@
diff --git a/repos/libports/recipes/src/qt6_tetrix/hash b/repos/libports/recipes/src/qt6_tetrix/hash
new file mode 100644
index 0000000000..95662716fc
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_tetrix/hash
@@ -0,0 +1 @@
+2024-08-07 42ea3fbbeadb46071c09e416c1116b906e2247d9
diff --git a/repos/libports/recipes/src/qt6_tetrix/used_apis b/repos/libports/recipes/src/qt6_tetrix/used_apis
new file mode 100644
index 0000000000..8d31aa5904
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_tetrix/used_apis
@@ -0,0 +1,5 @@
+libc
+mesa
+qt6_base
+qt6_component
+stdcxx
diff --git a/repos/libports/recipes/src/qt6_textedit/content.mk b/repos/libports/recipes/src/qt6_textedit/content.mk
new file mode 100644
index 0000000000..e94a734523
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_textedit/content.mk
@@ -0,0 +1,20 @@
+MIRROR_FROM_REP_DIR := src/app/qt6/examples/textedit
+
+content: $(MIRROR_FROM_REP_DIR) LICENSE
+
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+PORT_DIR := $(call port_dir,$(REP_DIR)/ports/qt6)
+
+MIRROR_FROM_PORT_DIR := src/lib/qt6/qtbase/tests/manual/examples/widgets/richtext/textedit
+
+content: $(MIRROR_FROM_PORT_DIR)
+
+$(MIRROR_FROM_PORT_DIR):
+ mkdir -p $(dir $@)
+ cp -r $(PORT_DIR)/$@ $(dir $@)
+
+LICENSE:
+ cp $(PORT_DIR)/src/lib/qt6/LICENSE.GPL3 $@
+
diff --git a/repos/libports/recipes/src/qt6_textedit/hash b/repos/libports/recipes/src/qt6_textedit/hash
new file mode 100644
index 0000000000..0bece7d3d2
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_textedit/hash
@@ -0,0 +1 @@
+2024-08-07 a11f92ce22effe833e0fd13973453703d5334ab9
diff --git a/repos/libports/recipes/src/qt6_textedit/used_apis b/repos/libports/recipes/src/qt6_textedit/used_apis
new file mode 100644
index 0000000000..8d31aa5904
--- /dev/null
+++ b/repos/libports/recipes/src/qt6_textedit/used_apis
@@ -0,0 +1,5 @@
+libc
+mesa
+qt6_base
+qt6_component
+stdcxx
diff --git a/repos/libports/recipes/src/test-qt6_core/content.mk b/repos/libports/recipes/src/test-qt6_core/content.mk
new file mode 100644
index 0000000000..a849fe401c
--- /dev/null
+++ b/repos/libports/recipes/src/test-qt6_core/content.mk
@@ -0,0 +1,10 @@
+MIRROR_FROM_REP_DIR := src/test/qt6/qt_core
+
+content: $(MIRROR_FROM_REP_DIR) LICENSE
+
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+LICENSE:
+ cp $(GENODE_DIR)/LICENSE $@
+
diff --git a/repos/libports/recipes/src/test-qt6_core/hash b/repos/libports/recipes/src/test-qt6_core/hash
new file mode 100644
index 0000000000..804e139e07
--- /dev/null
+++ b/repos/libports/recipes/src/test-qt6_core/hash
@@ -0,0 +1 @@
+2024-07-20 59cc52a2dabf907628828096f75dbe793db7a005
diff --git a/repos/libports/recipes/src/test-qt6_core/used_apis b/repos/libports/recipes/src/test-qt6_core/used_apis
new file mode 100644
index 0000000000..b470f3d9eb
--- /dev/null
+++ b/repos/libports/recipes/src/test-qt6_core/used_apis
@@ -0,0 +1,5 @@
+libc
+qt6_base
+qt6_component
+so
+stdcxx
diff --git a/repos/libports/recipes/src/test-qt6_core_cmake/content.mk b/repos/libports/recipes/src/test-qt6_core_cmake/content.mk
new file mode 100644
index 0000000000..e07646772a
--- /dev/null
+++ b/repos/libports/recipes/src/test-qt6_core_cmake/content.mk
@@ -0,0 +1,10 @@
+MIRROR_FROM_REP_DIR := src/test/qt6/qt_core_cmake
+
+content: $(MIRROR_FROM_REP_DIR) LICENSE
+
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+LICENSE:
+ cp $(GENODE_DIR)/LICENSE $@
+
diff --git a/repos/libports/recipes/src/test-qt6_core_cmake/hash b/repos/libports/recipes/src/test-qt6_core_cmake/hash
new file mode 100644
index 0000000000..804e139e07
--- /dev/null
+++ b/repos/libports/recipes/src/test-qt6_core_cmake/hash
@@ -0,0 +1 @@
+2024-07-20 59cc52a2dabf907628828096f75dbe793db7a005
diff --git a/repos/libports/recipes/src/test-qt6_core_cmake/used_apis b/repos/libports/recipes/src/test-qt6_core_cmake/used_apis
new file mode 100644
index 0000000000..b470f3d9eb
--- /dev/null
+++ b/repos/libports/recipes/src/test-qt6_core_cmake/used_apis
@@ -0,0 +1,5 @@
+libc
+qt6_base
+qt6_component
+so
+stdcxx
diff --git a/repos/libports/recipes/src/test-qt6_quick/content.mk b/repos/libports/recipes/src/test-qt6_quick/content.mk
new file mode 100644
index 0000000000..01c4dfd908
--- /dev/null
+++ b/repos/libports/recipes/src/test-qt6_quick/content.mk
@@ -0,0 +1,9 @@
+MIRROR_FROM_REP_DIR := src/test/qt6/qt_quick
+
+content: $(MIRROR_FROM_REP_DIR) LICENSE
+
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+LICENSE:
+ cp $(GENODE_DIR)/LICENSE $@
diff --git a/repos/libports/recipes/src/test-qt6_quick/hash b/repos/libports/recipes/src/test-qt6_quick/hash
new file mode 100644
index 0000000000..dc0f2fd7d8
--- /dev/null
+++ b/repos/libports/recipes/src/test-qt6_quick/hash
@@ -0,0 +1 @@
+2024-06-19 1eaefde3aacba9ea759e624a8fb1925378079540
diff --git a/repos/libports/recipes/src/test-qt6_quick/used_apis b/repos/libports/recipes/src/test-qt6_quick/used_apis
new file mode 100644
index 0000000000..b1d6b3d61d
--- /dev/null
+++ b/repos/libports/recipes/src/test-qt6_quick/used_apis
@@ -0,0 +1,6 @@
+libc
+mesa
+qt6_base
+qt6_component
+qt6_declarative
+stdcxx
diff --git a/repos/libports/run/qt6.run b/repos/libports/run/qt6.run
new file mode 100644
index 0000000000..017aa4defd
--- /dev/null
+++ b/repos/libports/run/qt6.run
@@ -0,0 +1,82 @@
+source ${genode_dir}/repos/libports/run/qt6_common.inc
+
+import_from_depot [depot_user]/src/qt6_component \
+ [depot_user]/src/qt6_calculatorform \
+ [depot_user]/src/qt6_launchpad \
+ [depot_user]/src/qt6_tetrix
+
+install_config {
+
+
+ } [qt6_parent_provides] {
+
+
+
+
+
+ } [qt6_start_nodes] {
+
+
+
+
+
+
+
+ 2018-01-01 00:01
+
+
+
+
+
+
+
+
+
+
+
+ 2018-01-01 00:01
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2018-01-01 00:01
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+build_boot_image [qt6_boot_modules]
+
+run_genode_until forever
diff --git a/repos/libports/run/qt6_calculatorform.run b/repos/libports/run/qt6_calculatorform.run
new file mode 100644
index 0000000000..98ff83c4fd
--- /dev/null
+++ b/repos/libports/run/qt6_calculatorform.run
@@ -0,0 +1,46 @@
+source ${genode_dir}/repos/libports/run/qt6_common.inc
+
+import_from_depot [depot_user]/src/qt6_calculatorform \
+ [depot_user]/src/qt6_component
+
+install_config {
+
+
+ } [qt6_parent_provides] {
+
+
+
+
+
+ } [qt6_start_nodes] {
+
+
+
+
+
+
+ 2018-01-01 00:01
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+build_boot_image [qt6_boot_modules]
+
+run_genode_until forever
diff --git a/repos/libports/run/qt6_common.inc b/repos/libports/run/qt6_common.inc
new file mode 100644
index 0000000000..b30cfb9919
--- /dev/null
+++ b/repos/libports/run/qt6_common.inc
@@ -0,0 +1,331 @@
+create_boot_directory
+
+import_from_depot [depot_user]/pkg/[drivers_interactive_pkg] \
+ [depot_user]/pkg/themed_wm \
+ [depot_user]/raw/qt6_dejavusans \
+ [depot_user]/src/[base_src] \
+ [depot_user]/src/expat \
+ [depot_user]/src/global_keys_handler \
+ [depot_user]/src/init \
+ [depot_user]/src/libdrm \
+ [depot_user]/src/libc \
+ [depot_user]/src/mesa \
+ [depot_user]/src/nitpicker \
+ [depot_user]/src/qt6_base \
+ [depot_user]/src/report_rom \
+ [depot_user]/src/rom_filter \
+ [depot_user]/src/stdcxx \
+ [depot_user]/src/vfs \
+ [depot_user]/src/vfs_gpu \
+ [depot_user]/src/vfs_pipe
+
+#
+# Configuration
+#
+
+proc qt6_layouter_config { } {
+ return {
+
+
+
+
+
+
+ }
+}
+
+proc qt6_decorator_binary { } { return "decorator" }
+
+proc qt6_decorator_config { } {
+ return {
+
+
+
+ }
+}
+
+proc qt6_parent_provides { } {
+
+ set parent_provides { }
+
+ append parent_provides {
+
+
+
+
+
+
+
+
+ }
+
+ return $parent_provides
+}
+
+#
+# Keyboard layout - this function can be overridden in a run script
+#
+proc language_chargen { } { return "en_us" }
+
+exec mkdir -p bin
+exec cp -f [genode_dir]/repos/os/src/server/event_filter/[language_chargen].chargen bin/
+exec cp -f [genode_dir]/repos/os/src/server/event_filter/special.chargen bin/
+
+set qt6_event_filter_config {
+
+
+
+
+
+ }
+
+set fd [open bin/qt6_event_filter.config w]
+puts $fd $qt6_event_filter_config
+close $fd
+
+
+proc qt6_start_nodes { } {
+
+ set start_nodes { }
+
+ append start_nodes {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ } [qt6_layouter_config] {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ } [qt6_decorator_config] {
+
+
+
+
+
+
+
+
+
+ }
+
+ return $start_nodes
+}
+
+
+proc qt6_boot_modules { } {
+
+ set boot_modules [build_artifacts]
+
+ lappend boot_modules [language_chargen].chargen
+ lappend boot_modules special.chargen
+ lappend boot_modules qt6_event_filter.config
+}
diff --git a/repos/libports/run/qt6_core.run b/repos/libports/run/qt6_core.run
new file mode 100644
index 0000000000..06d9feb98c
--- /dev/null
+++ b/repos/libports/run/qt6_core.run
@@ -0,0 +1,52 @@
+create_boot_directory
+
+import_from_depot [depot_user]/src/[base_src] \
+ [depot_user]/src/init \
+ [depot_user]/src/libc \
+ [depot_user]/src/qt6_base \
+ [depot_user]/src/qt6_component \
+ [depot_user]/src/stdcxx \
+ [depot_user]/src/vfs \
+ [depot_user]/src/zlib \
+ [depot_user]/src/test-qt6_core
+
+install_config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+build_boot_image [build_artifacts]
+
+append qemu_args " -nographic "
+
+run_genode_until "Test done.*\n" 10
diff --git a/repos/libports/run/qt6_core_cmake.run b/repos/libports/run/qt6_core_cmake.run
new file mode 100644
index 0000000000..95f1a980ba
--- /dev/null
+++ b/repos/libports/run/qt6_core_cmake.run
@@ -0,0 +1,52 @@
+create_boot_directory
+
+import_from_depot [depot_user]/src/[base_src] \
+ [depot_user]/src/init \
+ [depot_user]/src/libc \
+ [depot_user]/src/qt6_base \
+ [depot_user]/src/qt6_component \
+ [depot_user]/src/stdcxx \
+ [depot_user]/src/vfs \
+ [depot_user]/src/zlib \
+ [depot_user]/src/test-qt6_core_cmake
+
+install_config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+build_boot_image [build_artifacts]
+
+append qemu_args " -nographic "
+
+run_genode_until "Test done.*\n" 10
diff --git a/repos/libports/run/qt6_openglwindow.run b/repos/libports/run/qt6_openglwindow.run
new file mode 100644
index 0000000000..878e4d6df2
--- /dev/null
+++ b/repos/libports/run/qt6_openglwindow.run
@@ -0,0 +1,46 @@
+source ${genode_dir}/repos/libports/run/qt6_common.inc
+
+import_from_depot [depot_user]/src/qt6_component \
+ [depot_user]/src/qt6_openglwindow
+
+install_config {
+
+
+ } [qt6_parent_provides] {
+
+
+
+
+
+ } [qt6_start_nodes] {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2018-01-01 00:01
+
+
+
+
+
+
+
+
+
+}
+
+build_boot_image [qt6_boot_modules]
+
+run_genode_until forever
diff --git a/repos/libports/run/qt6_quicktest.run b/repos/libports/run/qt6_quicktest.run
new file mode 100644
index 0000000000..abd036e477
--- /dev/null
+++ b/repos/libports/run/qt6_quicktest.run
@@ -0,0 +1,48 @@
+source ${genode_dir}/repos/libports/run/qt6_common.inc
+
+import_from_depot [depot_user]/src/qt6_component \
+ [depot_user]/src/qt6_declarative \
+ [depot_user]/src/test-qt6_quick
+
+install_config {
+
+
+ } [qt6_parent_provides] {
+
+
+
+
+
+ } [qt6_start_nodes] {
+
+
+
+
+
+
+ 2018-01-01 00:01
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+build_boot_image [qt6_boot_modules]
+
+run_genode_until forever
diff --git a/repos/libports/run/qt6_samegame.run b/repos/libports/run/qt6_samegame.run
new file mode 100644
index 0000000000..a93678f944
--- /dev/null
+++ b/repos/libports/run/qt6_samegame.run
@@ -0,0 +1,51 @@
+source ${genode_dir}/repos/libports/run/qt6_common.inc
+
+import_from_depot [depot_user]/raw/qt6_samegame \
+ [depot_user]/src/qt6_component \
+ [depot_user]/src/qt6_declarative \
+ [depot_user]/src/qt6_samegame
+
+install_config {
+
+
+ } [qt6_parent_provides] {
+
+
+
+
+
+ } [qt6_start_nodes] {
+
+
+
+
+
+
+ 2018-01-01 00:01
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+build_boot_image [qt6_boot_modules]
+
+run_genode_until forever
diff --git a/repos/libports/run/qt6_testqstring.run b/repos/libports/run/qt6_testqstring.run
new file mode 100644
index 0000000000..a69ded64ce
--- /dev/null
+++ b/repos/libports/run/qt6_testqstring.run
@@ -0,0 +1,46 @@
+source ${genode_dir}/repos/libports/run/qt6_common.inc
+
+import_from_depot [depot_user]/src/qt6_component \
+ [depot_user]/src/qt6_testqstring
+
+install_config {
+
+
+ } [qt6_parent_provides] {
+
+
+
+
+
+ } [qt6_start_nodes] {
+
+
+
+
+
+
+ 2018-01-01 00:01
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+build_boot_image [qt6_boot_modules]
+
+run_genode_until " Finished testing of TestQString" 30
diff --git a/repos/libports/run/qt6_tetrix.run b/repos/libports/run/qt6_tetrix.run
new file mode 100644
index 0000000000..53081e3338
--- /dev/null
+++ b/repos/libports/run/qt6_tetrix.run
@@ -0,0 +1,46 @@
+source ${genode_dir}/repos/libports/run/qt6_common.inc
+
+import_from_depot [depot_user]/src/qt6_component \
+ [depot_user]/src/qt6_tetrix
+
+install_config {
+
+
+ } [qt6_parent_provides] {
+
+
+
+
+
+ } [qt6_start_nodes] {
+
+
+
+
+
+
+ 2018-01-01 00:01
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+build_boot_image [qt6_boot_modules]
+
+run_genode_until forever
diff --git a/repos/libports/run/qt6_textedit.run b/repos/libports/run/qt6_textedit.run
new file mode 100644
index 0000000000..0a4aef9b99
--- /dev/null
+++ b/repos/libports/run/qt6_textedit.run
@@ -0,0 +1,82 @@
+source ${genode_dir}/repos/libports/run/qt6_common.inc
+
+import_from_depot [depot_user]/src/qt6_component \
+ [depot_user]/src/qt6_textedit \
+ [depot_user]/src/vfs
+
+install_config {
+
+
+ } [qt6_parent_provides] {
+
+
+
+
+
+ } [qt6_start_nodes] {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2018-01-01 00:01
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2018-01-01 00:01
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+build_boot_image [qt6_boot_modules]
+
+run_genode_until forever
diff --git a/repos/libports/src/app/qt6/examples/calculatorform/target.mk b/repos/libports/src/app/qt6/examples/calculatorform/target.mk
new file mode 100644
index 0000000000..0e373cec06
--- /dev/null
+++ b/repos/libports/src/app/qt6/examples/calculatorform/target.mk
@@ -0,0 +1,7 @@
+QMAKE_PROJECT_FILE = $(QT_DIR)/qttools/examples/designer/calculatorform/calculatorform.pro
+
+QMAKE_TARGET_BINARIES = calculatorform
+
+QT6_PORT_LIBS = libQt6Core libQt6Gui libQt6Widgets
+
+LIBS = qt6_qmake libc libm mesa qt6_component stdcxx
diff --git a/repos/libports/src/app/qt6/examples/openglwindow/target.mk b/repos/libports/src/app/qt6/examples/openglwindow/target.mk
new file mode 100644
index 0000000000..83b8167309
--- /dev/null
+++ b/repos/libports/src/app/qt6/examples/openglwindow/target.mk
@@ -0,0 +1,7 @@
+QMAKE_PROJECT_FILE = $(QT_DIR)/qtbase/examples/opengl/openglwindow/openglwindow.pro
+
+QMAKE_TARGET_BINARIES = openglwindow
+
+QT6_PORT_LIBS = libQt6Core libQt6Gui libQt6OpenGL
+
+LIBS = qt6_qmake libc libm mesa qt6_component stdcxx
diff --git a/repos/libports/src/app/qt6/examples/samegame/main.cpp b/repos/libports/src/app/qt6/examples/samegame/main.cpp
new file mode 100644
index 0000000000..33e61d0878
--- /dev/null
+++ b/repos/libports/src/app/qt6/examples/samegame/main.cpp
@@ -0,0 +1,19 @@
+/*
+ * \brief QtQuick 'samegame' example
+ * \author Christian Prochaska
+ * \date 2013-11-26
+ */
+
+#include
+#include
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ QQuickView view;
+ view.setSource(QUrl("/samegame.qml"));
+ view.show();
+
+ return app.exec();
+}
diff --git a/repos/libports/src/app/qt6/examples/samegame/samegame.pro b/repos/libports/src/app/qt6/examples/samegame/samegame.pro
new file mode 100644
index 0000000000..d8c9065bf8
--- /dev/null
+++ b/repos/libports/src/app/qt6/examples/samegame/samegame.pro
@@ -0,0 +1,2 @@
+QT += quick
+SOURCES += main.cpp
diff --git a/repos/libports/src/app/qt6/examples/samegame/target.mk b/repos/libports/src/app/qt6/examples/samegame/target.mk
new file mode 100644
index 0000000000..9e56a6ebda
--- /dev/null
+++ b/repos/libports/src/app/qt6/examples/samegame/target.mk
@@ -0,0 +1,8 @@
+QMAKE_PROJECT_FILE = $(PRG_DIR)/samegame.pro
+
+QMAKE_TARGET_BINARIES = samegame
+
+QT6_PORT_LIBS += libQt6Core libQt6Gui libQt6OpenGL libQt6Network
+QT6_PORT_LIBS += libQt6Qml libQt6QmlModels libQt6Quick
+
+LIBS = qt6_qmake libc libm mesa qt6_component stdcxx
diff --git a/repos/libports/src/app/qt6/examples/testqstring/target.mk b/repos/libports/src/app/qt6/examples/testqstring/target.mk
new file mode 100644
index 0000000000..85e1b6ab92
--- /dev/null
+++ b/repos/libports/src/app/qt6/examples/testqstring/target.mk
@@ -0,0 +1,7 @@
+QMAKE_PROJECT_FILE = $(QT_DIR)/qtbase/examples/qtestlib/tutorial1
+
+QMAKE_TARGET_BINARIES = tutorial1
+
+QT6_PORT_LIBS = libQt6Core libQt6Gui libQt6Test libQt6Widgets
+
+LIBS = qt6_qmake libc libm mesa qt6_component stdcxx
diff --git a/repos/libports/src/app/qt6/examples/tetrix/target.mk b/repos/libports/src/app/qt6/examples/tetrix/target.mk
new file mode 100644
index 0000000000..f74cf04f40
--- /dev/null
+++ b/repos/libports/src/app/qt6/examples/tetrix/target.mk
@@ -0,0 +1,7 @@
+QMAKE_PROJECT_FILE = $(QT_DIR)/qtbase/tests/manual/examples/widgets/widgets/tetrix/tetrix.pro
+
+QMAKE_TARGET_BINARIES = tetrix
+
+QT6_PORT_LIBS = libQt6Core libQt6Gui libQt6Widgets
+
+LIBS = qt6_qmake libc libm mesa qt6_component stdcxx
diff --git a/repos/libports/src/app/qt6/examples/textedit/target.mk b/repos/libports/src/app/qt6/examples/textedit/target.mk
new file mode 100644
index 0000000000..603a5b94e3
--- /dev/null
+++ b/repos/libports/src/app/qt6/examples/textedit/target.mk
@@ -0,0 +1,7 @@
+QMAKE_PROJECT_FILE = $(QT_DIR)/qtbase/tests/manual/examples/widgets/richtext/textedit/textedit.pro
+
+QMAKE_TARGET_BINARIES = textedit
+
+QT6_PORT_LIBS = libQt6Core libQt6Gui libQt6PrintSupport libQt6Widgets
+
+LIBS = qt6_qmake libc libm mesa qt6_component stdcxx
diff --git a/repos/libports/src/app/qt6/qt_launchpad/child_entry.cpp b/repos/libports/src/app/qt6/qt_launchpad/child_entry.cpp
new file mode 100644
index 0000000000..2dfed47080
--- /dev/null
+++ b/repos/libports/src/app/qt6/qt_launchpad/child_entry.cpp
@@ -0,0 +1,33 @@
+/*
+ * \brief Child entry widget implementation
+ * \author Christian Prochaska
+ * \date 2008-04-06
+ */
+
+/*
+ * Copyright (C) 2008 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#include "child_entry.h"
+
+Child_entry::Child_entry(Launchpad_child::Name const &name, int quota_kb,
+ int max_quota_kb, Launchpad &launchpad,
+ Launchpad_child &launchpad_child,
+ QWidget *parent)
+: QWidget(parent), _launchpad(launchpad), _launchpad_child(launchpad_child)
+{
+ ui.setupUi(this);
+
+ ui.nameLabel->setText(name.string());
+ ui.quotaBar->setMaximum(max_quota_kb);
+ ui.quotaBar->setValue(quota_kb);
+}
+
+
+void Child_entry::on_exitButton_clicked()
+{
+ _launchpad.exit_child(_launchpad_child);
+}
diff --git a/repos/libports/src/app/qt6/qt_launchpad/child_entry.h b/repos/libports/src/app/qt6/qt_launchpad/child_entry.h
new file mode 100644
index 0000000000..388fc570c7
--- /dev/null
+++ b/repos/libports/src/app/qt6/qt_launchpad/child_entry.h
@@ -0,0 +1,46 @@
+/*
+ * \brief Child entry widget interface
+ * \author Christian Prochaska
+ * \date 2008-04-06
+ */
+
+/*
+ * Copyright (C) 2008-2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef CHILD_ENTRY_H
+#define CHILD_ENTRY_H
+
+#include
+
+#include
+
+#include "ui_child_entry.h"
+
+class Child_entry : public QWidget
+{
+ Q_OBJECT
+
+ private:
+
+ Ui::Child_entryClass ui;
+
+ Launchpad &_launchpad;
+ Launchpad_child &_launchpad_child;
+
+ private slots:
+
+ void on_exitButton_clicked();
+
+ public:
+
+ Child_entry(Launchpad_child::Name const &name, int quota_kb,
+ int max_quota_kb, Launchpad &launchpad,
+ Launchpad_child &launchpad_child,
+ QWidget *parent = 0);
+};
+
+#endif /* CHILD_ENTRY_H */
diff --git a/repos/libports/src/app/qt6/qt_launchpad/child_entry.ui b/repos/libports/src/app/qt6/qt_launchpad/child_entry.ui
new file mode 100644
index 0000000000..7004ca5096
--- /dev/null
+++ b/repos/libports/src/app/qt6/qt_launchpad/child_entry.ui
@@ -0,0 +1,148 @@
+
+ Child_entryClass
+
+
+
+ 0
+ 0
+ 396
+ 30
+
+
+
+
+ 4
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 100
+ 22
+
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 0
+ 20
+
+
+
+
+ -
+
+
+
+ 240
+ 22
+
+
+
+
+ 240
+ 16777215
+
+
+
+ 0
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 6
+ 30
+
+
+
+
+ -
+
+
+
+ 20
+ 20
+
+
+
+
+ 20
+ 20
+
+
+
+
+ 75
+ true
+
+
+
+ X
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 6
+ 30
+
+
+
+
+
+
+
+
+
+ Kbyte_loadbar
+ QProgressBar
+
+
+
+
+
+
diff --git a/repos/libports/src/app/qt6/qt_launchpad/kbyte_loadbar.cpp b/repos/libports/src/app/qt6/qt_launchpad/kbyte_loadbar.cpp
new file mode 100644
index 0000000000..d931201411
--- /dev/null
+++ b/repos/libports/src/app/qt6/qt_launchpad/kbyte_loadbar.cpp
@@ -0,0 +1,25 @@
+/*
+ * \brief KByte loadbar implementation
+ * \author Christian Prochaska
+ * \date 2008-04-05
+ */
+
+/*
+ * Copyright (C) 2008 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#include "kbyte_loadbar.h"
+
+
+Kbyte_loadbar::Kbyte_loadbar(QWidget *parent)
+: QProgressBar(parent) { }
+
+
+QString Kbyte_loadbar::text() const
+{
+ return QString::number(value()) + " KByte / " +
+ QString::number(maximum()) + " KByte";
+}
diff --git a/repos/libports/src/app/qt6/qt_launchpad/kbyte_loadbar.h b/repos/libports/src/app/qt6/qt_launchpad/kbyte_loadbar.h
new file mode 100644
index 0000000000..94a21c4307
--- /dev/null
+++ b/repos/libports/src/app/qt6/qt_launchpad/kbyte_loadbar.h
@@ -0,0 +1,30 @@
+/*
+ * \brief KByte loadbar interface
+ * \author Christian Prochaska
+ * \date 2008-04-05
+ */
+
+/*
+ * Copyright (C) 2008-2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef KBYTE_LOADBAR_H
+#define KBYTE_LOADBAR_H
+
+#include
+
+class Kbyte_loadbar : public QProgressBar
+{
+ Q_OBJECT
+
+ public:
+
+ Kbyte_loadbar(QWidget *parent = 0);
+
+ virtual QString text() const;
+};
+
+#endif /* KBYTE_LOADBAR_H */
diff --git a/repos/libports/src/app/qt6/qt_launchpad/launch_entry.cpp b/repos/libports/src/app/qt6/qt_launchpad/launch_entry.cpp
new file mode 100644
index 0000000000..b9748f82c9
--- /dev/null
+++ b/repos/libports/src/app/qt6/qt_launchpad/launch_entry.cpp
@@ -0,0 +1,43 @@
+/*
+ * \brief Launcher entry widget implementation
+ * \author Christian Prochaska
+ * \date 2008-04-06
+ */
+
+/*
+ * Copyright (C) 2008 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#include "launch_entry.h"
+
+Launch_entry::Launch_entry(Launchpad_child::Name const &prg_name,
+ Launchpad::Cap_quota caps,
+ unsigned long default_quota,
+ unsigned long max_quota,
+ Launchpad *launchpad,
+ Genode::Dataspace_capability config_ds,
+ QWidget *parent)
+: QWidget(parent),
+ _prg_name(prg_name),
+ _launchpad(launchpad),
+ _config_ds(config_ds),
+ _caps(caps)
+{
+ ui.setupUi(this);
+
+ ui.launchButton->setText(prg_name.string());
+
+ ui.quotaDial->setMaximum(max_quota);
+ ui.quotaDial->setSingleStep(max_quota / 100);
+ ui.quotaDial->setValue(default_quota);
+}
+
+
+void Launch_entry::on_launchButton_clicked()
+{
+ Launchpad::Ram_quota ram_quota = { 1024UL * ui.quotaDial->value() };
+ _launchpad->start_child(_prg_name, _caps, ram_quota, _config_ds);
+}
diff --git a/repos/libports/src/app/qt6/qt_launchpad/launch_entry.h b/repos/libports/src/app/qt6/qt_launchpad/launch_entry.h
new file mode 100644
index 0000000000..0be8e28eae
--- /dev/null
+++ b/repos/libports/src/app/qt6/qt_launchpad/launch_entry.h
@@ -0,0 +1,51 @@
+/*
+ * \brief Launcher entry widget interface
+ * \author Christian Prochaska
+ * \date 2008-04-06
+ */
+
+/*
+ * Copyright (C) 2008-2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef LAUNCH_ENTRY_H
+#define LAUNCH_ENTRY_H
+
+#include
+
+#include
+
+#include "ui_launch_entry.h"
+
+class Launch_entry : public QWidget
+{
+ Q_OBJECT
+
+ private:
+
+ Ui::Launch_entryClass ui;
+
+ Launchpad_child::Name const &_prg_name;
+ Launchpad *_launchpad;
+ Genode::Dataspace_capability _config_ds;
+ Launchpad::Cap_quota _caps;
+
+ private slots:
+
+ void on_launchButton_clicked();
+
+ public:
+
+ Launch_entry(Launchpad_child::Name const &prg_name,
+ Launchpad::Cap_quota caps,
+ unsigned long default_quota,
+ unsigned long max_quota,
+ Launchpad *launchpad,
+ Genode::Dataspace_capability config_ds,
+ QWidget *parent = 0);
+};
+
+#endif /* LAUNCH_ENTRY_H */
diff --git a/repos/libports/src/app/qt6/qt_launchpad/launch_entry.ui b/repos/libports/src/app/qt6/qt_launchpad/launch_entry.ui
new file mode 100644
index 0000000000..dae32b8244
--- /dev/null
+++ b/repos/libports/src/app/qt6/qt_launchpad/launch_entry.ui
@@ -0,0 +1,133 @@
+
+ Launch_entryClass
+
+
+
+ 0
+ 0
+ 396
+ 40
+
+
+
+
+ 4
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+
+ 100
+ 40
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 0
+ 20
+
+
+
+
+ -
+
+
+
+ 240
+ 40
+
+
+
+
+ 240
+ 16777215
+
+
+
+ 0
+
+
+
+ -
+
+
+
+ 40
+ 40
+
+
+
+ 100
+
+
+ false
+
+
+ true
+
+
+
+
+
+
+
+ Kbyte_loadbar
+ QProgressBar
+
+
+
+
+
+
+ quotaDial
+ valueChanged(int)
+ quotaBar
+ setValue(int)
+
+
+ 395
+ 43
+
+
+ 355
+ 43
+
+
+
+
+ quotaDial
+ rangeChanged(int,int)
+ quotaBar
+ setRange(int,int)
+
+
+ 395
+ 30
+
+
+ 355
+ 30
+
+
+
+
+
diff --git a/repos/libports/src/app/qt6/qt_launchpad/main.cpp b/repos/libports/src/app/qt6/qt_launchpad/main.cpp
new file mode 100644
index 0000000000..37981ef615
--- /dev/null
+++ b/repos/libports/src/app/qt6/qt_launchpad/main.cpp
@@ -0,0 +1,106 @@
+/*
+ * \brief Qt Launchpad main program
+ * \author Christian Prochaska
+ * \date 2008-04-05
+ */
+
+/*
+ * Copyright (C) 2008-2020 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* Genode includes */
+#include
+#include
+
+/* Qt includes */
+#include
+#include
+
+/* qt6_component includes */
+#include
+
+/* local includes */
+#include "qt_launchpad.h"
+
+namespace Qt_launchpad_namespace {
+ struct Local_env;
+ using namespace Genode;
+}
+
+struct Qt_launchpad_namespace::Local_env : Genode::Env
+{
+ Genode::Env &genode_env;
+
+ Genode::Entrypoint local_ep { genode_env,
+ 2*1024*sizeof(addr_t),
+ "qt_launchpad_ep",
+ Affinity::Location() };
+
+ Local_env(Env &genode_env) : genode_env(genode_env) { }
+
+ Parent &parent() override { return genode_env.parent(); }
+ Cpu_session &cpu() override { return genode_env.cpu(); }
+ Region_map &rm() override { return genode_env.rm(); }
+ Pd_session &pd() override { return genode_env.pd(); }
+ Entrypoint &ep() override { return local_ep; }
+ Cpu_session_capability cpu_session_cap() override { return genode_env.cpu_session_cap(); }
+ Pd_session_capability pd_session_cap() override { return genode_env.pd_session_cap(); }
+ Id_space &id_space() override { return genode_env.id_space(); }
+
+ Session_capability session(Parent::Service_name const &service_name,
+ Parent::Client::Id id,
+ Parent::Session_args const &session_args,
+ Affinity const &affinity) override
+ {
+ return genode_env.session(service_name, id, session_args, affinity);
+ }
+
+ Session_capability try_session(Parent::Service_name const &service_name,
+ Parent::Client::Id id,
+ Parent::Session_args const &session_args,
+ Affinity const &affinity) override
+ {
+ return genode_env.try_session(service_name, id, session_args, affinity);
+ }
+
+ void upgrade(Parent::Client::Id id, Parent::Upgrade_args const &args) override
+ {
+ return genode_env.upgrade(id, args);
+ }
+
+ void close(Parent::Client::Id id) override { return genode_env.close(id); }
+
+ void exec_static_constructors() override { }
+};
+
+
+void Libc::Component::construct(Libc::Env &env)
+{
+ Libc::with_libc([&] {
+
+ qpa_init(env);
+
+ Qt_launchpad_namespace::Local_env local_env(env);
+
+ int argc = 1;
+ char const *argv[] = { "qt_launchpad", 0 };
+
+ QApplication a(argc, (char**)argv);
+
+ Qt_launchpad launchpad(local_env, env.pd().avail_ram().value);
+
+ Genode::Attached_rom_dataspace config(env, "config");
+
+ try { launchpad.process_config(config.xml()); } catch (...) { }
+
+ launchpad.move(300,100);
+ launchpad.show();
+
+ a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()));
+
+ a.exec();
+ });
+}
diff --git a/repos/libports/src/app/qt6/qt_launchpad/qt_launchpad.cpp b/repos/libports/src/app/qt6/qt_launchpad/qt_launchpad.cpp
new file mode 100644
index 0000000000..5f617c26f1
--- /dev/null
+++ b/repos/libports/src/app/qt6/qt_launchpad/qt_launchpad.cpp
@@ -0,0 +1,130 @@
+/*
+ * \brief Qt Launchpad window implementation
+ * \author Christian Prochaska
+ * \date 2008-04-05
+ */
+
+/*
+ * Copyright (C) 2008-2020 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#include
+
+#include
+
+#include "qt_launchpad.h"
+
+#include "launch_entry.h"
+#include "child_entry.h"
+
+Qt_launchpad::Qt_launchpad(Genode::Env &env, unsigned long initial_quota,
+ QWidget *parent)
+: QMainWindow(parent), Launchpad(env, initial_quota), _env(env)
+{
+ setupUi(this);
+
+ // disable minimize and maximize buttons
+ Qt::WindowFlags flags = windowFlags();
+ flags &= ~Qt::WindowMinMaxButtonsHint;
+ setWindowFlags(flags);
+
+ // put a QScrollArea into launcherDockWidget for scrolling of launcher entries
+ QScrollArea *launcherScrollArea = new QScrollArea;
+ launcherScrollArea->setFrameStyle(QFrame::NoFrame);
+ launcherScrollArea->setWidget(launcherDockWidgetContents);
+
+ launcherDockWidget->setWidget(launcherScrollArea);
+
+ QVBoxLayout *launcherDockWidgetLayout = new QVBoxLayout;
+ launcherDockWidgetLayout->setContentsMargins(2, 2, 2, 2);
+ launcherDockWidgetLayout->setSpacing(2);
+ launcherDockWidgetContents->setLayout(launcherDockWidgetLayout);
+
+ // put a QScrollArea into childrenDockWidget for scrolling of child entries
+ QScrollArea *childrenScrollArea = new QScrollArea;
+ childrenScrollArea->setFrameStyle(QFrame::NoFrame);
+ childrenScrollArea->setWidget(childrenDockWidgetContents);
+
+ childrenDockWidget->setWidget(childrenScrollArea);
+
+ QVBoxLayout *childrenDockWidgetLayout = new QVBoxLayout;
+ childrenDockWidgetLayout->setContentsMargins(2, 2, 2, 2);
+ childrenDockWidgetLayout->setSpacing(2);
+ childrenDockWidgetContents->setLayout(childrenDockWidgetLayout);
+
+ // update the available quota bar every 200ms
+ QTimer *avail_quota_timer = new QTimer(this);
+ connect(avail_quota_timer, SIGNAL(timeout()), this, SLOT(_avail_quota_update()));
+ avail_quota_timer->start(200);
+}
+
+
+void Qt_launchpad::_avail_quota_update()
+{
+ static Genode::size_t _avail = 0;
+
+ Genode::size_t new_avail = _env.pd().avail_ram().value;
+
+ if (new_avail != _avail)
+ quota(new_avail);
+
+ _avail = new_avail;
+}
+
+
+void Qt_launchpad::quota(unsigned long quota)
+{
+ totalQuotaProgressBar->setMaximum(initial_quota() / 1024);
+ totalQuotaProgressBar->setValue(quota / 1024);
+}
+
+
+void Qt_launchpad::add_launcher(Launchpad_child::Name const &binary_name,
+ Cap_quota caps, unsigned long default_quota,
+ Genode::Dataspace_capability config_ds)
+{
+ Launch_entry *launch_entry = new Launch_entry(binary_name,
+ caps,
+ default_quota / 1024,
+ initial_quota() / 1024,
+ this,
+ config_ds);
+ launcherDockWidgetContents->layout()->addWidget(launch_entry);
+ launch_entry->show();
+ launcherDockWidgetContents->adjustSize();
+}
+
+
+void Qt_launchpad::add_child(Launchpad_child::Name const &name,
+ unsigned long quota,
+ Launchpad_child &launchpad_child,
+ Genode::Allocator &)
+{
+ Child_entry *child_entry = new Child_entry(name, quota / 1024,
+ initial_quota() / 1024,
+ *this, launchpad_child);
+ child_entry->setObjectName(QString(name.string()) + "_child_entry");
+ childrenDockWidgetContents->layout()->addWidget(child_entry);
+ child_entry->show();
+ childrenDockWidgetContents->adjustSize();
+}
+
+
+void Qt_launchpad::remove_child(Launchpad_child::Name const &name, Genode::Allocator &)
+{
+ Child_entry *child_entry =
+ childrenDockWidgetContents->findChild(QString(name.string()) + "_child_entry");
+
+ if (!child_entry) {
+ Genode::warning("child entry lookup failed");
+ return;
+ }
+
+ // still in "button clicked" event handler
+ child_entry->deleteLater();
+
+ childrenDockWidgetContents->adjustSize();
+}
diff --git a/repos/libports/src/app/qt6/qt_launchpad/qt_launchpad.h b/repos/libports/src/app/qt6/qt_launchpad/qt_launchpad.h
new file mode 100644
index 0000000000..45d0364fd2
--- /dev/null
+++ b/repos/libports/src/app/qt6/qt_launchpad/qt_launchpad.h
@@ -0,0 +1,54 @@
+/*
+ * \brief Qt Launchpad window interface
+ * \author Christian Prochaska
+ * \date 2008-04-05
+ */
+
+/*
+ * Copyright (C) 2008-2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef QT_LAUNCHPAD_H
+#define QT_LAUNCHPAD_H
+
+#include
+
+#include
+#include "ui_qt_launchpad.h"
+
+class Qt_launchpad : public QMainWindow, public Launchpad, private Ui::Qt_launchpadClass
+{
+ Q_OBJECT
+
+ private:
+
+ Genode::Env &_env;
+
+ private slots:
+
+ void _avail_quota_update();
+
+ public:
+
+ Qt_launchpad(Genode::Env &env, unsigned long initial_quota,
+ QWidget *parent = 0);
+
+ virtual void quota(unsigned long quota) override;
+
+ virtual void add_launcher(Launchpad_child::Name const &binary_name,
+ Cap_quota caps, unsigned long default_quota,
+ Genode::Dataspace_capability config_ds) override;
+
+ virtual void add_child(Launchpad_child::Name const &name,
+ unsigned long quota,
+ Launchpad_child &launchpad_child,
+ Genode::Allocator &alloc) override;
+
+ virtual void remove_child(Launchpad_child::Name const &name,
+ Genode::Allocator &alloc) override;
+};
+
+#endif /* QT_LAUNCHPAD_H */
diff --git a/repos/libports/src/app/qt6/qt_launchpad/qt_launchpad.pro b/repos/libports/src/app/qt6/qt_launchpad/qt_launchpad.pro
new file mode 100644
index 0000000000..4110e3378c
--- /dev/null
+++ b/repos/libports/src/app/qt6/qt_launchpad/qt_launchpad.pro
@@ -0,0 +1,16 @@
+TEMPLATE = app
+TARGET = qt_launchpad
+QT = core gui widgets
+CONFIG += c++2a
+HEADERS += child_entry.h \
+ kbyte_loadbar.h \
+ launch_entry.h \
+ qt_launchpad.h
+SOURCES += child_entry.cpp \
+ kbyte_loadbar.cpp \
+ launch_entry.cpp \
+ main.cpp \
+ qt_launchpad.cpp
+FORMS += child_entry.ui \
+ launch_entry.ui \
+ qt_launchpad.ui
diff --git a/repos/libports/src/app/qt6/qt_launchpad/qt_launchpad.ui b/repos/libports/src/app/qt6/qt_launchpad/qt_launchpad.ui
new file mode 100644
index 0000000000..31e7820af9
--- /dev/null
+++ b/repos/libports/src/app/qt6/qt_launchpad/qt_launchpad.ui
@@ -0,0 +1,152 @@
+
+ Qt_launchpadClass
+
+
+
+ 0
+ 0
+ 410
+ 500
+
+
+
+
+ 410
+ 500
+
+
+
+
+ 410
+ 500
+
+
+
+ Qt Launchpad
+
+
+
+
+
+ 410
+ 0
+
+
+
+ QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable|QDockWidget::NoDockWidgetFeatures
+
+
+ Qt::LeftDockWidgetArea
+
+
+ Status
+
+
+ 1
+
+
+
+
+ 16777215
+ 50
+
+
+
+ -
+
+
+
+ 100
+ 0
+
+
+
+ Quota
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 240
+ 0
+
+
+
+ 0
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+
+ 410
+ 0
+
+
+
+ QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable|QDockWidget::NoDockWidgetFeatures
+
+
+ Qt::LeftDockWidgetArea
+
+
+ Launcher
+
+
+ 1
+
+
+
+
+
+
+ 410
+ 0
+
+
+
+ QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable|QDockWidget::NoDockWidgetFeatures
+
+
+ Qt::LeftDockWidgetArea
+
+
+ Children
+
+
+ 1
+
+
+
+
+
+
+ Kbyte_loadbar
+ QProgressBar
+
+
+
+
+
+
diff --git a/repos/libports/src/app/qt6/qt_launchpad/target.mk b/repos/libports/src/app/qt6/qt_launchpad/target.mk
new file mode 100644
index 0000000000..3af1141ec3
--- /dev/null
+++ b/repos/libports/src/app/qt6/qt_launchpad/target.mk
@@ -0,0 +1,12 @@
+QMAKE_PROJECT_FILE = $(PRG_DIR)/qt_launchpad.pro
+
+QMAKE_TARGET_BINARIES = qt_launchpad
+
+QT6_PORT_LIBS += libQt6Core libQt6Gui libQt6Widgets
+
+LIBS = qt6_qmake base libc libm mesa stdcxx launchpad
+
+QT6_COMPONENT_LIB_SO =
+
+QT6_GENODE_LIBS_APP += ld.lib.so launchpad.lib.a
+qmake_prepared.tag: $(addprefix build_dependencies/lib/,$(QT6_GENODE_LIBS_APP))
diff --git a/repos/libports/src/lib/qt6_component/qt_component.cc b/repos/libports/src/lib/qt6_component/qt_component.cc
new file mode 100644
index 0000000000..7c2ab90d4d
--- /dev/null
+++ b/repos/libports/src/lib/qt6_component/qt_component.cc
@@ -0,0 +1,56 @@
+/*
+ * \brief Entry point for Qt applications with a main() function
+ * \author Christian Prochaska
+ * \date 2017-05-22
+ */
+
+/*
+ * Copyright (C) 2017-2020 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* Genode includes */
+#include
+#include
+
+/* libc includes */
+#include /* 'exit' */
+
+/* qt6_component includes */
+#include
+
+/* initial environment for the FreeBSD libc implementation */
+extern char **environ;
+
+/* provided by the application */
+extern "C" int main(int argc, char **argv, char **envp);
+
+void Libc::Component::construct(Libc::Env &env)
+{
+ Libc::with_libc([&] {
+
+ qpa_init(env);
+
+ int argc = 0;
+ char **argv = nullptr;
+ char **envp = nullptr;
+
+ populate_args_and_env(env, argc, argv, envp);
+
+ /* at least the executable name is required */
+
+ char default_argv0[] { "qt6_component" };
+ char *default_argv[] { default_argv0, nullptr };
+
+ if (argc == 0) {
+ argc = 1;
+ argv = default_argv;
+ }
+
+ environ = envp;
+
+ exit(main(argc, argv, envp));
+ });
+}
diff --git a/repos/libports/src/test/qt6/qt_core/main.cpp b/repos/libports/src/test/qt6/qt_core/main.cpp
new file mode 100644
index 0000000000..1fdc13ba02
--- /dev/null
+++ b/repos/libports/src/test/qt6/qt_core/main.cpp
@@ -0,0 +1,12 @@
+/*
+ * \brief QtCore test
+ * \author Christian Prochaska
+ * \date 2018-01-16
+ */
+
+#include
+
+int main(int argc, char *argv[])
+{
+ qInfo() << "Test done.";
+}
diff --git a/repos/libports/src/test/qt6/qt_core/qt_core.pro b/repos/libports/src/test/qt6/qt_core/qt_core.pro
new file mode 100644
index 0000000000..56cfba2730
--- /dev/null
+++ b/repos/libports/src/test/qt6/qt_core/qt_core.pro
@@ -0,0 +1,4 @@
+TEMPLATE = app
+TARGET = test-qt_core
+QT = core
+SOURCES += main.cpp
diff --git a/repos/libports/src/test/qt6/qt_core/target.mk b/repos/libports/src/test/qt6/qt_core/target.mk
new file mode 100644
index 0000000000..5750afc50a
--- /dev/null
+++ b/repos/libports/src/test/qt6/qt_core/target.mk
@@ -0,0 +1,7 @@
+QMAKE_PROJECT_FILE = $(PRG_DIR)/qt_core.pro
+
+QMAKE_TARGET_BINARIES = test-qt_core
+
+QT6_PORT_LIBS = libQt6Core
+
+LIBS = qt6_qmake libc libm qt6_component stdcxx
diff --git a/repos/libports/src/test/qt6/qt_core_cmake/CMakeLists.txt b/repos/libports/src/test/qt6/qt_core_cmake/CMakeLists.txt
new file mode 100644
index 0000000000..4e9da3ce09
--- /dev/null
+++ b/repos/libports/src/test/qt6/qt_core_cmake/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 3.10.0)
+
+project(test-qt_core_cmake LANGUAGES CXX)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+find_package(Qt6 COMPONENTS Core REQUIRED)
+
+add_executable(test-qt_core_cmake
+ main.cpp
+)
+
+target_link_libraries(test-qt_core_cmake Qt6::Core)
diff --git a/repos/libports/src/test/qt6/qt_core_cmake/main.cpp b/repos/libports/src/test/qt6/qt_core_cmake/main.cpp
new file mode 100644
index 0000000000..1fdc13ba02
--- /dev/null
+++ b/repos/libports/src/test/qt6/qt_core_cmake/main.cpp
@@ -0,0 +1,12 @@
+/*
+ * \brief QtCore test
+ * \author Christian Prochaska
+ * \date 2018-01-16
+ */
+
+#include
+
+int main(int argc, char *argv[])
+{
+ qInfo() << "Test done.";
+}
diff --git a/repos/libports/src/test/qt6/qt_core_cmake/target.mk b/repos/libports/src/test/qt6/qt_core_cmake/target.mk
new file mode 100644
index 0000000000..bda916a57d
--- /dev/null
+++ b/repos/libports/src/test/qt6/qt_core_cmake/target.mk
@@ -0,0 +1,7 @@
+CMAKE_LISTS_DIR = $(PRG_DIR)
+
+CMAKE_TARGET_BINARIES = test-qt_core_cmake
+
+QT6_PORT_LIBS = libQt6Core
+
+LIBS = qt6_cmake libc libm qt6_component stdcxx
diff --git a/repos/libports/src/test/qt6/qt_quick/main.cpp b/repos/libports/src/test/qt6/qt_quick/main.cpp
new file mode 100644
index 0000000000..1cc8f6896a
--- /dev/null
+++ b/repos/libports/src/test/qt6/qt_quick/main.cpp
@@ -0,0 +1,19 @@
+/*
+ * \brief QtQuick test
+ * \author Christian Prochaska
+ * \date 2013-11-26
+ */
+
+#include
+#include
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ QQuickView view;
+ view.setSource(QUrl("qrc:/qt_quick.qml"));
+ view.show();
+
+ return app.exec();
+}
diff --git a/repos/libports/src/test/qt6/qt_quick/qt_quick.pro b/repos/libports/src/test/qt6/qt_quick/qt_quick.pro
new file mode 100644
index 0000000000..0438b3b63b
--- /dev/null
+++ b/repos/libports/src/test/qt6/qt_quick/qt_quick.pro
@@ -0,0 +1,6 @@
+TEMPLATE += app
+TARGET = test-qt_quick
+QT += quick qml
+SOURCES += main.cpp
+RESOURCES += qt_quick.qrc
+CONFIG += debug
diff --git a/repos/libports/src/test/qt6/qt_quick/qt_quick.qml b/repos/libports/src/test/qt6/qt_quick/qt_quick.qml
new file mode 100644
index 0000000000..8ad179ad50
--- /dev/null
+++ b/repos/libports/src/test/qt6/qt_quick/qt_quick.qml
@@ -0,0 +1,32 @@
+/*
+ * QML example from the Qt5 Quick Start Guide
+ *
+ * http://qt-project.org/doc/qt-5.0/qtquick/qtquick-quickstart-essentials.html
+ */
+
+import QtQuick 2.0
+
+Rectangle {
+ width: 200
+ height: 100
+ color: "red"
+
+ Text {
+ anchors.centerIn: parent
+ text: "Hello, World!"
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: parent.color = "blue"
+ }
+
+ focus: true
+ Keys.onPressed: {
+ if (event.key == Qt.Key_Return) {
+ color = "green";
+ event.accepted = true;
+ }
+ }
+}
+
diff --git a/repos/libports/src/test/qt6/qt_quick/qt_quick.qrc b/repos/libports/src/test/qt6/qt_quick/qt_quick.qrc
new file mode 100644
index 0000000000..9c656d58ae
--- /dev/null
+++ b/repos/libports/src/test/qt6/qt_quick/qt_quick.qrc
@@ -0,0 +1,6 @@
+
+
+
+qt_quick.qml
+
+
diff --git a/repos/libports/src/test/qt6/qt_quick/target.mk b/repos/libports/src/test/qt6/qt_quick/target.mk
new file mode 100644
index 0000000000..b778e815d8
--- /dev/null
+++ b/repos/libports/src/test/qt6/qt_quick/target.mk
@@ -0,0 +1,8 @@
+QMAKE_PROJECT_FILE = $(PRG_DIR)/qt_quick.pro
+
+QMAKE_TARGET_BINARIES = test-qt_quick
+
+QT6_PORT_LIBS += libQt6Core libQt6Gui libQt6OpenGL libQt6Network
+QT6_PORT_LIBS += libQt6Qml libQt6QmlModels libQt6Quick
+
+LIBS = qt6_qmake libc libm mesa qt6_component stdcxx
diff --git a/tool/tool_chain_qt6 b/tool/tool_chain_qt6
new file mode 100755
index 0000000000..04c57199b7
--- /dev/null
+++ b/tool/tool_chain_qt6
@@ -0,0 +1,156 @@
+#!/usr/bin/make -f
+#
+# \brief Tool for preparing the Qt6 tool-chain for the Genode OS Framework
+# \author Christian Prochaska
+# \date 2024-07-29
+#
+
+SHELL = bash
+ECHO = @echo -e
+VERBOSE = @
+
+help:
+ $(ECHO)
+ $(ECHO) "Build Qt6 tools for the Genode OS Framework tool chain"
+ $(ECHO)
+ $(ECHO) "--- available commands ---"
+ $(ECHO) "build - build Qt6 tools"
+ $(ECHO) "install - install Qt6 tools to '$(INSTALL_LOCATION)'"
+ $(ECHO) "clean - clean everything except contrib sources"
+ $(ECHO)
+ $(ECHO) "--- available command line options ---"
+ $(ECHO) "MAKE_JOBS=4 - number of parallel make jobs (default: 4)"
+ $(ECHO)
+
+.PHONY: build help install
+
+#
+# Enable parallel build for 2nd-level $(MAKE) by default
+#
+
+MAKE_JOBS ?= 4
+
+#
+# Source, build and install location
+#
+
+GENODE_DIR ?= $(realpath $(dir $(firstword $(MAKEFILE_LIST)))/..)
+CONTRIB_DIR = $(shell $(GENODE_DIR)/tool/ports/current qt6-host)
+QT6_DIR = $(CONTRIB_DIR)/src/lib/qt6
+TOOL_VERSION = 23.05
+BUILD_DIR = $(GENODE_DIR)/build/tool/qt6/$(TOOL_VERSION)
+DEFAULT_INSTALL_LOCATION = /usr/local/genode/tool/$(TOOL_VERSION)/qt6
+INSTALL_LOCATION ?= $(DEFAULT_INSTALL_LOCATION)
+SUDO ?= sudo
+
+$(QT6_DIR):
+ $(VERBOSE)$(GENODE_DIR)/tool/ports/prepare_port qt6-host
+
+$(BUILD_DIR):
+ $(VERBOSE)mkdir -p $@
+
+build: $(BUILD_DIR) $(QT6_DIR)
+
+ $(VERBOSE)cd $(BUILD_DIR) && cmake \
+ -G "Unix Makefiles" \
+ -DQT_SILENCE_CMAKE_GENERATOR_WARNING=ON \
+ -DCMAKE_INSTALL_PREFIX=$(BUILD_DIR)/install \
+ -DBUILD_WITH_PCH=OFF \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DFEATURE_androiddeployqt=OFF \
+ -DFEATURE_dbus=OFF \
+ -DFEATURE_eglfs=OFF \
+ -DFEATURE_fontconfig=OFF \
+ -DFEATURE_freetype=OFF \
+ -DFEATURE_glib=OFF \
+ -DFEATURE_libudev=OFF \
+ -DFEATURE_system_libpng16=OFF \
+ -DFEATURE_system_pcre2=OFF \
+ -DFEATURE_system_zlib=OFF \
+ -DFEATURE_vulkan=OFF \
+ -DQT_FEATURE_brotli=OFF \
+ -DQT_FEATURE_widgets=OFF \
+ -DBUILD_qt3d=OFF \
+ -DBUILD_qt5compat=OFF \
+ -DBUILD_qtactiveqt=OFF \
+ -DBUILD_qtbase=ON \
+ -DBUILD_qtcharts=OFF \
+ -DBUILD_qtcoap=OFF \
+ -DBUILD_qtconnectivity=OFF \
+ -DBUILD_qtdatavis3d=OFF \
+ -DBUILD_qtdeclarative=ON \
+ -DBUILD_qtdoc=OFF \
+ -DBUILD_qtgraphs=OFF \
+ -DBUILD_qtgrpc=OFF \
+ -DBUILD_qthttpserver=OFF \
+ -DBUILD_qtimageformats=OFF \
+ -DBUILD_qtlanguageserver=OFF \
+ -DBUILD_qtlocation=OFF \
+ -DBUILD_qtlottie=OFF \
+ -DBUILD_qtmqtt=OFF \
+ -DBUILD_qtmultimedia=OFF \
+ -DBUILD_qtnetworkauth=OFF \
+ -DBUILD_qtopcua=OFF \
+ -DBUILD_qtpositioning=OFF \
+ -DBUILD_qtquick3d=OFF \
+ -DBUILD_qtquick3dphysics=OFF \
+ -DBUILD_qtquickeffectmaker=OFF \
+ -DBUILD_qtquicktimeline=OFF \
+ -DBUILD_qtremoteobjects=OFF \
+ -DBUILD_qtscxml=OFF \
+ -DBUILD_qtsensors=OFF \
+ -DBUILD_qtserialbus=OFF \
+ -DBUILD_qtserialport=OFF \
+ -DBUILD_qtshadertools=ON \
+ -DBUILD_qtspeech=OFF \
+ -DBUILD_qtsvg=OFF \
+ -DBUILD_qttools=ON \
+ -DBUILD_qttranslations=OFF \
+ -DBUILD_qtvirtualkeyboard=OFF \
+ -DBUILD_qtwayland=OFF \
+ -DBUILD_qtwebchannel=OFF \
+ -DBUILD_qtwebengine=OFF \
+ -DBUILD_qtwebsockets=OFF \
+ -DBUILD_qtwebview=OFF \
+ $(QT6_DIR) \
+
+ $(VERBOSE)cmake \
+ --build $(BUILD_DIR) \
+ --parallel $(MAKE_JOBS)
+
+ $(VERBOSE)cmake \
+ --install $(BUILD_DIR) \
+ --strip
+
+ # build 'gn' for QtWebEngine
+
+ $(VERBOSE)cmake \
+ -B $(BUILD_DIR)/qtwebengine/gn \
+ $(QT6_DIR)/qtwebengine/src/gn \
+ -DCMAKE_INSTALL_PREFIX=$(BUILD_DIR)/install
+
+ $(VERBOSE)cmake \
+ --build $(BUILD_DIR)/qtwebengine/gn \
+ --parallel $(MAKE_JOBS)
+
+ $(VERBOSE)cmake \
+ --install $(BUILD_DIR)/qtwebengine/gn \
+ --strip
+
+ $(VERBOSE)mv $(BUILD_DIR)/install/bin/gn $(BUILD_DIR)/install/libexec/gn
+
+install:
+ $(VERBOSE)$(SUDO) mkdir -p $(INSTALL_LOCATION)
+ $(VERBOSE)$(SUDO) cp -a $(BUILD_DIR)/install/bin $(INSTALL_LOCATION)/
+ $(VERBOSE)$(SUDO) cp -a $(BUILD_DIR)/install/libexec $(INSTALL_LOCATION)/
+ $(VERBOSE)$(SUDO) mkdir -p $(INSTALL_LOCATION)/lib
+ $(VERBOSE)$(SUDO) cp -a $(BUILD_DIR)/install/lib/cmake $(INSTALL_LOCATION)/lib/
+ $(VERBOSE)$(SUDO) cp -a $(BUILD_DIR)/install/lib/libQt6Core.so* $(INSTALL_LOCATION)/lib/
+ $(VERBOSE)$(SUDO) cp -a $(BUILD_DIR)/install/lib/libQt6Gui.so* $(INSTALL_LOCATION)/lib/
+ $(VERBOSE)$(SUDO) cp -a $(BUILD_DIR)/install/lib/libQt6Network.so* $(INSTALL_LOCATION)/lib/
+ $(VERBOSE)$(SUDO) cp -a $(BUILD_DIR)/install/lib/libQt6Qml.so* $(INSTALL_LOCATION)/lib/
+ $(VERBOSE)$(SUDO) cp -a $(BUILD_DIR)/install/lib/libQt6QmlCompiler.so* $(INSTALL_LOCATION)/lib/
+ $(VERBOSE)$(SUDO) cp -a $(BUILD_DIR)/install/lib/libQt6ShaderTools.so* $(INSTALL_LOCATION)/lib/
+
+clean:
+ rm -rf $(BUILD_DIR)