diff --git a/libmalcontent-ui/malcontent-ui.gresource.xml b/libmalcontent-ui/malcontent-ui.gresource.xml
new file mode 100644
index 0000000..8736c19
--- /dev/null
+++ b/libmalcontent-ui/malcontent-ui.gresource.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/libmalcontent-ui/malcontent-ui.h b/libmalcontent-ui/malcontent-ui.h
new file mode 100644
index 0000000..4977a50
--- /dev/null
+++ b/libmalcontent-ui/malcontent-ui.h
@@ -0,0 +1,24 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright © 2020 Endless Mobile, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * - Philip Withnall
+ */
+
+#pragma once
+
diff --git a/libmalcontent-ui/meson.build b/libmalcontent-ui/meson.build
new file mode 100644
index 0000000..ac196c6
--- /dev/null
+++ b/libmalcontent-ui/meson.build
@@ -0,0 +1,93 @@
+libmalcontent_ui_api_version = '0'
+libmalcontent_ui_api_name = 'malcontent-ui-' + libmalcontent_ui_api_version
+
+if not cc.has_function('atexit')
+ error('atexit() needed for generated GResource files')
+endif
+
+resources = gnome.compile_resources(
+ 'resources',
+ 'malcontent-ui.gresource.xml',
+ source_dir: meson.source_root(),
+)
+
+libmalcontent_ui_sources = [
+] + resources
+libmalcontent_ui_headers = [
+ 'malcontent-ui.h',
+]
+libmalcontent_ui_private_headers = [
+]
+
+libmalcontent_ui_public_deps = [
+ dependency('accountsservice', version: '>= 0.6.39'),
+ dependency('gio-2.0', version: '>= 2.44'),
+ dependency('glib-2.0', version: '>= 2.54.2'),
+ dependency('gobject-2.0', version: '>= 2.54'),
+ dependency('gtk+-3.0', version: '>= 3.24'),
+ libmalcontent_dep,
+]
+libmalcontent_ui_private_deps = [
+ dependency('flatpak'),
+]
+
+# FIXME: Would be good to use subdir here: https://github.com/mesonbuild/meson/issues/2969
+libmalcontent_ui_include_subdir = join_paths(libmalcontent_ui_api_name, 'libmalcontent-ui')
+
+libmalcontent_ui = library(libmalcontent_ui_api_name,
+ libmalcontent_ui_sources + libmalcontent_ui_headers + libmalcontent_ui_private_headers,
+ dependencies: libmalcontent_ui_public_deps + libmalcontent_ui_private_deps,
+ include_directories: root_inc,
+ install: true,
+ version: meson.project_version(),
+ soversion: libmalcontent_ui_api_version,
+)
+libmalcontent_ui_dep = declare_dependency(
+ link_with: libmalcontent_ui,
+ include_directories: root_inc,
+)
+
+# Public library bits.
+install_headers(libmalcontent_ui_headers,
+ subdir: libmalcontent_ui_include_subdir,
+)
+
+pkgconfig.generate(libmalcontent_ui,
+ subdirs: libmalcontent_ui_api_name,
+ version: meson.project_version(),
+ name: 'libmalcontent-ui',
+ filebase: libmalcontent_ui_api_name,
+ description: 'Library providing widgets for parental control settings.',
+ libraries: libmalcontent_ui_public_deps,
+ libraries_private: libmalcontent_ui_private_deps,
+)
+
+gnome.generate_gir(libmalcontent_ui,
+ sources: libmalcontent_ui_sources + libmalcontent_ui_headers + libmalcontent_ui_private_headers,
+ nsversion: libmalcontent_ui_api_version,
+ namespace: 'MalcontentUi',
+ symbol_prefix: 'mct_',
+ identifier_prefix: 'Mct',
+ export_packages: 'libmalcontent-ui',
+ includes: ['AccountsService-1.0', 'Gio-2.0', 'GObject-2.0', 'Gtk-3.0'],
+ install: true,
+ dependencies: libmalcontent_ui_dep,
+)
+
+xmllint = find_program('xmllint', required: false)
+if xmllint.found()
+ gtk_prefix = dependency('gtk+-3.0').get_pkgconfig_variable('prefix')
+ test(
+ 'validate-ui', xmllint,
+ args: [
+ '--nonet', '--noblanks', '--noout',
+ '--relaxng', join_paths(gtk_prefix, 'share', 'gtk-3.0', 'gtkbuilder.rng'),
+ files(
+ ),
+ ],
+ suite: ['libmalcontent-ui'],
+ )
+endif
+
+# FIXME: Add tests
+#subdir('tests')
diff --git a/meson.build b/meson.build
index 666d434..301a10b 100644
--- a/meson.build
+++ b/meson.build
@@ -128,6 +128,7 @@ test_env = [
subdir('accounts-service')
subdir('libmalcontent')
+subdir('libmalcontent-ui')
subdir('malcontent-client')
subdir('malcontent-control')
subdir('pam')