diff --git a/Makefile.am b/Makefile.am
index dc045aa7abea116a97989cdafc547d0778ffc734..f388c08fb666d6c0b32fea3b6e331fe798cd5ee4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -305,6 +305,15 @@ dist-hook: ChangeLog
 # Extra dist and distclean rules
 EXTRA_DIST += \
 	lib/screenshooter-marshal.list \
+	meson.build \
+	meson_options.txt \
+	icons/meson.build \
+	lib/meson.build \
+	panel-plugin/meson.build \
+	po/meson.build \
+	protocols/meson.build \
+	src/meson.build \
+	xfce-revision.h.in \
 	$(app_desktop_in_files) \
 	$(panel_desktop_in_files) \
 	$(16icons_DATA) \
diff --git a/configure.ac b/configure.ac
index 68183cb7811e0d97d281cacc982a4b6d6e4e4000..ebc8e0cd4ff9c208e3384a5cecca34466311a3f1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -40,16 +40,16 @@ AC_HEADER_STDC
 dnl ***********************************
 dnl *** Check for required packages ***
 dnl ***********************************
-XDT_CHECK_PACKAGE([LIBXFCE4PANEL], [libxfce4panel-2.0], [4.16.0])
-XDT_CHECK_PACKAGE([LIBXFCE4UTIL], [libxfce4util-1.0], [4.16.0])
-XDT_CHECK_PACKAGE([LIBXFCE4UI], [libxfce4ui-2], [4.16.0])
+XDT_CHECK_PACKAGE([LIBXFCE4PANEL], [libxfce4panel-2.0], [4.18.0])
+XDT_CHECK_PACKAGE([LIBXFCE4UTIL], [libxfce4util-1.0], [4.18.0])
+XDT_CHECK_PACKAGE([LIBXFCE4UI], [libxfce4ui-2], [4.18.0])
 XDT_CHECK_PACKAGE([GTHREAD], [gthread-2.0], [2.42.0])
 XDT_CHECK_PACKAGE([GTK], [gtk+-3.0], [3.24.0])
 XDT_CHECK_PACKAGE([GDK], [gdk-3.0], [3.24.0])
 XDT_CHECK_PACKAGE([GLIB], [glib-2.0], [2.66.0])
 XDT_CHECK_PACKAGE([EXO], [exo-2], [0.12.0])
 XDT_CHECK_PACKAGE([PANGO], [pango], [1.44.0])
-XDT_CHECK_PACKAGE([XFCONF], [libxfconf-0], [4.16.0])
+XDT_CHECK_PACKAGE([XFCONF], [libxfconf-0], [4.18.0])
 
 dnl ***********************************
 dnl *** Check for optional packages ***
diff --git a/icons/meson.build b/icons/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..ace1021bff37a9ba47ce18b63470b2d5efa6e274
--- /dev/null
+++ b/icons/meson.build
@@ -0,0 +1,13 @@
+sizes = [16, 24, 32, 48, 128]
+
+foreach size : sizes
+  install_data(
+    '@0@x@0@'.format(size) / 'org.xfce.screenshooter.png',
+    install_dir: get_option('prefix') / get_option('datadir') / 'icons' / 'hicolor' / '@0@x@0@'.format(size) / 'apps',
+  )
+endforeach
+
+install_data(
+  'scalable' / 'org.xfce.screenshooter.svg',
+  install_dir: get_option('prefix') / get_option('datadir') / 'icons' / 'hicolor' / 'scalable' / 'apps',
+)
diff --git a/lib/meson.build b/lib/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..2b4b58111aee8e64f88237f6ef4ce0772583ede4
--- /dev/null
+++ b/lib/meson.build
@@ -0,0 +1,61 @@
+libscreenshooter_sources = [
+  'libscreenshooter.h',
+  'screenshooter-actions.c',
+  'screenshooter-actions.h',
+  'screenshooter-capture.c',
+  'screenshooter-capture.h',
+  'screenshooter-custom-actions.c',
+  'screenshooter-custom-actions.h',
+  'screenshooter-format.c',
+  'screenshooter-format.h',
+  'screenshooter-dialogs.c',
+  'screenshooter-dialogs.h',
+  'screenshooter-global.h',
+  'screenshooter-utils.c',
+  'screenshooter-utils.h',
+]
+
+libscreenshooter_sources += gnome.genmarshal(
+  'screenshooter-marshal',
+  sources: 'screenshooter-marshal.list',
+  prefix: '_screenshooter_marshal',
+  internal: true,
+  install_header: false,
+)
+
+if enable_x11
+  libscreenshooter_sources += [
+    'screenshooter-capture-x11.c',
+    'screenshooter-capture-x11.h',
+    'screenshooter-utils-x11.c',
+    'screenshooter-utils-x11.h',
+  ]
+endif
+
+if enable_wayland
+  libscreenshooter_sources += wayland_protocols_generated_sources
+  libscreenshooter_sources += [
+    'screenshooter-capture-wayland.c',
+    'screenshooter-capture-wayland.h',
+  ]
+endif
+
+libscreenshooter = static_library(
+  'libscreenshooter',
+  libscreenshooter_sources,
+  include_directories: [
+    include_directories('..'),
+  ],
+  dependencies: [
+    glib,
+    gtk,
+    exo,
+    libxfce4ui,
+    libxfce4util,
+    xfconf,
+    x11_deps,
+    wayland_deps,
+    xfixes,
+  ],
+  install: false,
+)
diff --git a/lib/screenshooter-dialogs.h b/lib/screenshooter-dialogs.h
index da0b86854b70711ca2a51bc8f02d44ceb939e507..a0c863781d0e994d6d4928b8ba32ae4e2296aafc 100644
--- a/lib/screenshooter-dialogs.h
+++ b/lib/screenshooter-dialogs.h
@@ -28,10 +28,6 @@
 #include "screenshooter-global.h"
 #include "screenshooter-actions.h"
 
-#ifdef HAVE_GIO
-#include <gio/gio.h>
-#endif
-
 #include <gtk/gtk.h>
 #include <libxfce4util/libxfce4util.h>
 #include <libxfce4ui/libxfce4ui.h>
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..59b0d0d688f54afeb1405429b30fa46e7942ebf6
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,197 @@
+project(
+  'xfce4-screenshooter',
+  'c',
+  version: '1.11.1-dev',
+  license: 'GPL-2.0-or-later',
+  meson_version: '>= 0.56.0',
+  default_options: [
+    'c_std=gnu11',
+    'buildtype=debugoptimized',
+    'warning_level=2',
+  ]
+)
+
+project_namespace = 'apps'
+pkgdatadir = get_option('prefix') / get_option('datadir') / meson.project_name()
+scriptdir = get_option('prefix') / get_option('libexecdir') / 'xfce4' / 'screenshooter' / 'scripts'
+feature_cflags = []
+
+cc = meson.get_compiler('c')
+gnome = import('gnome')
+i18n = import('i18n')
+
+dependency_versions = {
+  'glib': '>= 2.66.0',
+  'gtk': '>= 3.24.0',
+  'libx11': '>= 1.6.7',
+  'xinput': '>= 1.7.8',
+  'libxext': '>= 1.0.0',
+  'xfixes': '>= 4.0.0',
+  'xfce4': '>= 4.18.0',
+  'wayland': '>= 1.20',
+  'wayland-protocols': '>= 1.25',
+  'wlr-protocols': '>= 0',
+}
+
+glib = dependency('glib-2.0', version: dependency_versions['glib'])
+gtk = dependency('gtk+-3.0', version: dependency_versions['gtk'])
+libxfce4util = dependency('libxfce4util-1.0', version: dependency_versions['xfce4'])
+libxfce4ui = dependency('libxfce4ui-2', version: dependency_versions['xfce4'])
+xfconf = dependency('libxfconf-0', version: dependency_versions['xfce4'])
+libxfce4panel = dependency('libxfce4panel-2.0', version: dependency_versions['xfce4'])
+exo = dependency('exo-2', version: dependency_versions['xfce4'])
+
+# Feature: 'x11'
+libx11 = dependency('x11', version: dependency_versions['libx11'], required: get_option('x11'))
+gdk_x11 = dependency('gdk-x11-3.0', version: dependency_versions['gtk'], required: get_option('x11'))
+xinput = dependency('xi', version: dependency_versions['xinput'], required: get_option('x11'))
+libxext = dependency('xext', version: dependency_versions['libxext'], required: get_option('x11'))
+x11_deps = [libx11, gdk_x11, xinput, libxext]
+
+# Feature: 'wayland'
+gdk_wayland = dependency('gdk-wayland-3.0', version: dependency_versions['gtk'], required: get_option('wayland'))
+wayland_client = dependency('wayland-client', version: dependency_versions['wayland'], required: get_option('wayland'))
+wayland_scanner = dependency('wayland-scanner', version: dependency_versions['wayland'], required: get_option('wayland'), native: true)
+wayland_protocols = dependency('wayland-protocols', version: dependency_versions['wayland-protocols'], required: get_option('wayland'))
+wayland_deps = [gdk_wayland, wayland_client, wayland_scanner, wayland_protocols]
+
+# Optional dependencies
+wlr_protocols = dependency('wlr-protocols', version: dependency_versions['wlr-protocols'], required: false)
+
+enable_x11 = not get_option('x11').disabled()
+foreach dep : x11_deps
+  enable_x11 = enable_x11 and dep.found()
+endforeach
+if enable_x11
+  feature_cflags += '-DENABLE_X11=1'
+
+  xfixes = dependency('xfixes', version: dependency_versions['xfixes'], required: get_option('xfixes'))
+  if xfixes.found()
+    feature_cflags += '-DHAVE_XFIXES=1'
+  endif
+else 
+  xfixes = dependency('', required: false)
+endif
+
+enable_wayland = not get_option('wayland').disabled()
+foreach dep : wayland_deps
+  enable_wayland = enable_wayland and dep.found()
+endforeach
+if enable_wayland
+  feature_cflags += '-DENABLE_WAYLAND=1'
+
+  wayland_scanner_path = wayland_scanner.get_variable(pkgconfig: 'wayland_scanner')
+  wayland_scanner_bin = find_program(wayland_scanner_path, required: true)
+
+  wl_protocols_pkgdatadir = wayland_protocols.get_variable(pkgconfig: 'pkgdatadir')
+
+  if wlr_protocols.found()
+    wlr_protocols_pkgdatadir = wlr_protocols.get_variable(pkgconfig: 'pkgdatadir')
+  else
+    wlr_protocols_pkgdatadir = meson.project_source_root() / 'protocols' / 'wlr-protocols'
+  endif
+endif
+
+if not enable_x11 and not enable_wayland
+  error('At least one of the X11 and Wayland backends must be enabled')
+endif
+
+extra_cflags = []
+extra_cflags_check = [
+  '-Wmissing-declarations',
+  '-Wmissing-noreturn',
+  '-Wold-style-definition',
+  '-Wredundant-decls',
+  '-Wpointer-arith',
+  '-Wcast-align',
+  '-Winit-self',
+  '-Wshadow',
+  '-Wmissing-include-dirs',
+  '-Wundef',
+  '-Wformat',
+  '-Wformat-security',
+  '-Wformat-y2k',
+  '-Wnested-externs',
+  '-Wno-unused-parameter',
+  '-Wno-declaration-after-statement',
+  '-Wno-missing-field-initializers',
+  '-Werror=implicit-function-declaration',
+  '-Wno-error=deprecated-declarations',
+]
+
+optimization = get_option('optimization')
+if get_option('debug') and optimization in ['0', 'g']
+  extra_cflags_check += '-fstack-protector-strong'
+  extra_cflags += [
+    '-DDEBUG=1',
+    '-DDEBUG_TRACE=1',
+    '-DG_ENABLE_DEBUG',
+  ]
+elif optimization in ['3', 'minsize']
+  extra_cflags += [
+    '-DNDEBUG',
+    '-DG_DISABLE_CAST_CHECKS',
+    '-DG_DISABLE_ASSERT',
+  ]
+endif
+
+if dependency_versions.has_key('glib')
+  glib_version_parts = dependency_versions['glib'].split(' ')
+  glib_min_version_parts = glib_version_parts[1].split('.')
+  glib_min_version_define = 'GLIB_VERSION_@0@_@1@'.format(glib_min_version_parts[0], glib_min_version_parts[1])
+  extra_cflags += [
+    '-DGLIB_VERSION_MIN_REQUIRED=@0@'.format(glib_min_version_define),
+    '-DGLIB_VERSION_MAX_ALLOWED=@0@'.format(glib_min_version_define),
+    '-DG_LOG_DOMAIN="@0@"'.format(meson.project_name()),
+    '-DG_LOG_USE_STRUCTURED=1',
+  ]
+endif
+
+version_parts = meson.project_version().split('-dev')[0].split('.')
+version_short = '@0@.@1@'.format(version_parts[0], version_parts[1])
+
+extra_cflags += [
+  '-DPACKAGE="@0@"'.format(meson.project_name()),
+  '-DPACKAGE_NAME="@0@"'.format(meson.project_name()),
+  '-DPACKAGE_VERSION="@0@"'.format(meson.project_version()),
+  '-DVERSION="@0@"'.format(meson.project_version()),
+  '-DVERSION_SHORT="@0@"'.format(version_short),
+  '-DPACKAGE_STRING="@0@ @1@"'.format(meson.project_name(), meson.project_version()),
+  '-DPACKAGE_DATADIR="@0@"'.format(pkgdatadir),
+  '-DPACKAGE_LOCALE_DIR="@0@"'.format(get_option('prefix') / get_option('localedir')),
+  '-DPACKAGE_SCRIPTS_DIR="@0@"'.format(scriptdir),
+  '-DPACKAGE_BUGREPORT="https://gitlab.xfce.org/@0@/@1@/-/issues"'.format(project_namespace, meson.project_name()),
+  '-DGETTEXT_PACKAGE="@0@"'.format(meson.project_name()),
+  '-DPREFIX="@0@"'.format(get_option('prefix')),
+  '-DBINDIR="@0@"'.format(get_option('prefix') / get_option('bindir')),
+  '-DDATADIR="@0@"'.format(get_option('prefix') / get_option('datadir')),
+  '-DINCLUDEDIR="@0@"'.format(get_option('prefix') / get_option('includedir')),
+  '-DLIBDIR="@0@"'.format(get_option('prefix') / get_option('libdir')),
+  '-DLIBEXECDIR="@0@"'.format(get_option('prefix') / get_option('libexecdir')),
+  '-DLOCALEDIR="@0@"'.format(get_option('prefix') / get_option('localedir')),
+  '-DLOCALSTATEDIR="@0@"'.format(get_option('prefix') / get_option('localstatedir')),
+  '-DSBINDIR="@0@"'.format(get_option('prefix') / get_option('sbindir')),
+  '-DSYSCONFDIR="@0@"'.format(get_option('prefix') / get_option('sysconfdir')),
+  '-DHAVE_XFCE_REVISION_H=1',
+]
+
+add_project_arguments(cc.get_supported_arguments(extra_cflags_check), language: 'c')
+add_project_arguments(extra_cflags, language: 'c')
+add_project_arguments(feature_cflags, language: 'c')
+
+xfce_revision_h = vcs_tag(
+  command: ['git', 'rev-parse', '--short', 'HEAD'],
+  fallback: 'UNKNOWN',
+  input: 'xfce-revision.h.in',
+  output: 'xfce-revision.h',
+  replace_string: '@REVISION@',
+)
+
+install_data('imgur-upload.sh', install_dir: scriptdir)
+
+subdir('icons')
+subdir('po')
+subdir('protocols')
+subdir('lib')
+subdir('src')
+subdir('panel-plugin')
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a3ae449f49a60996860d67dbeb038aad77ae1149
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,18 @@
+option(
+  'x11',
+  type: 'feature',
+  value: 'auto',
+  description: 'Support for the X11 windowing system',
+)
+option(
+  'wayland',
+  type: 'feature',
+  value: 'auto',
+  description: 'Support for the Wayland windowing system',
+)
+option(
+  'xfixes',
+  type: 'feature',
+  value: 'auto',
+  description: 'Support for XFIXES  (X11 only)',
+)
diff --git a/panel-plugin/meson.build b/panel-plugin/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..128377a962f9549d1cca3de59bbdbff3a7b3431b
--- /dev/null
+++ b/panel-plugin/meson.build
@@ -0,0 +1,39 @@
+plugin_sources = [
+  'screenshooter-plugin.c'
+]
+
+plugin_install_subdir = 'xfce4' / 'panel' / 'plugins'
+
+shared_module(
+  'screenshooterplugin',
+  plugin_sources,
+  gnu_symbol_visibility: 'hidden',
+  include_directories: [
+    include_directories('..', '..' / 'lib'),
+  ],
+  dependencies: [
+    gtk,
+    glib,
+    libxfce4util,
+    libxfce4ui,
+    libxfce4panel,
+    xfconf,
+    x11_deps,
+    wayland_deps,
+    xfixes,
+  ],
+  link_with: [
+    libscreenshooter,
+  ],
+  install: true,
+  install_dir: get_option('prefix') / get_option('libdir') / plugin_install_subdir,
+)
+
+i18n.merge_file(
+    input: 'screenshooter.desktop.in',
+    output: 'screenshooter.desktop',
+    po_dir: '..' / 'po',
+    type: 'desktop',
+    install: true,
+    install_dir: get_option('prefix') / get_option('datadir') / plugin_install_subdir,
+)
diff --git a/po/meson.build b/po/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..e9b77d79b28d9792022d2856a3cf0dd8110b027b
--- /dev/null
+++ b/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext(meson.project_name(), preset: 'glib')
diff --git a/protocols/meson.build b/protocols/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..bd4fa3bd61a96f42e9828d0f460b31fead282998
--- /dev/null
+++ b/protocols/meson.build
@@ -0,0 +1,25 @@
+if enable_wayland
+  wayland_protocols_generated_sources = []
+
+  protocols = {
+    'wlr-screencopy-unstable-v1': wlr_protocols_pkgdatadir / 'unstable' / 'wlr-screencopy-unstable-v1.xml',
+  }
+
+  foreach name, file : protocols
+    client_header = custom_target(
+      '@0@-client-header'.format(name),
+      input: file,
+      output: '@0@-client.h'.format(name),
+      command: [wayland_scanner_bin, 'client-header', '@INPUT@', '@OUTPUT@'],
+    )
+
+    private_code = custom_target(
+      '@0@-private-code'.format(name),
+      input: file,
+      output: '@0@.c'.format(name),
+      command: [wayland_scanner_bin, 'private-code', '@INPUT@', '@OUTPUT@'],
+    )
+
+    wayland_protocols_generated_sources += [client_header, private_code]
+  endforeach
+endif
diff --git a/src/meson.build b/src/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..5428c93f3e76c4ce60bf818e336431dea7da89fb
--- /dev/null
+++ b/src/meson.build
@@ -0,0 +1,59 @@
+screenshooter_sources = [
+  'main.c',
+]
+
+screenshooter = executable(
+  'xfce4-screenshooter',
+  screenshooter_sources,
+  sources: xfce_revision_h,
+  include_directories: [
+    include_directories('..', '..' / 'lib'),
+  ],
+  dependencies: [
+    gtk,
+    glib,
+    libxfce4util,
+    libxfce4ui,
+    xfconf,
+    x11_deps,
+    wayland_deps,
+    xfixes,
+  ],
+  link_with: [
+    libscreenshooter,
+  ],
+  install: true,
+  install_dir: get_option('prefix') / get_option('bindir'),
+)
+
+i18n.merge_file(
+    input: 'xfce4-screenshooter.desktop.in',
+    output: 'xfce4-screenshooter.desktop',
+    po_dir: '..' / 'po',
+    type: 'desktop',
+    install: true,
+    install_dir: get_option('prefix') / get_option('datadir') / 'applications',
+)
+
+i18n.merge_file(
+    input: 'xfce4-screenshooter.appdata.xml.in',
+    output: 'xfce4-screenshooter.appdata.xml',
+    po_dir: '..' / 'po',
+    type: 'xml',
+    install: true,
+    install_dir: get_option('prefix') / get_option('datadir') / 'metainfo',
+)
+
+help2man = find_program('help2man', required: false)
+if help2man.found()
+  custom_target(
+    'xfce4-screenshooter.1',
+    depends: screenshooter,
+    output: 'xfce4-screenshooter.1',
+    command: [
+      help2man, ['--no-info'], '--output=@OUTPUT@', screenshooter.full_path(),
+    ],
+    install: true,
+    install_dir: get_option('prefix') / get_option('datadir') / 'man' / 'man1',
+  )
+endif
diff --git a/xfce-revision.h.in b/xfce-revision.h.in
new file mode 100644
index 0000000000000000000000000000000000000000..0b9bb88560cb6fe889f16c75ada0b8915870d727
--- /dev/null
+++ b/xfce-revision.h.in
@@ -0,0 +1,15 @@
+/*
+ * The file xfce-revision.h is auto-generated and should not be modified
+ * directly.  Modify the xfce-revision.h.in file and re-run the build
+ * instead.
+ */
+
+#ifndef INC_XFCE_REVISION_H
+#define INC_XFCE_REVISION_H
+
+#define REVISION "@REVISION@"
+
+#define VERSION_FULL VERSION "-" REVISION
+#define PACKAGE_STRING_FULL PACKAGE " " VERSION_FULL
+
+#endif /* INC_XFCE_REVISION_H */