summary refs log tree commit diff
path: root/pkgs/desktops/gnome
diff options
context:
space:
mode:
authorJan Tojnar <jtojnar@gmail.com>2021-05-07 23:18:14 +0200
committerJan Tojnar <jtojnar@gmail.com>2021-05-08 09:47:42 +0200
commit468cb5980b56d348979488a74a9b5de638400160 (patch)
tree1426485105b897074e82af80efdd545462edb211 /pkgs/desktops/gnome
parentd03a5eb09720fd6ad670df12d8eafbbfcd7ff494 (diff)
downloadnixpkgs-468cb5980b56d348979488a74a9b5de638400160.tar
nixpkgs-468cb5980b56d348979488a74a9b5de638400160.tar.gz
nixpkgs-468cb5980b56d348979488a74a9b5de638400160.tar.bz2
nixpkgs-468cb5980b56d348979488a74a9b5de638400160.tar.lz
nixpkgs-468cb5980b56d348979488a74a9b5de638400160.tar.xz
nixpkgs-468cb5980b56d348979488a74a9b5de638400160.tar.zst
nixpkgs-468cb5980b56d348979488a74a9b5de638400160.zip
gnome: rename from gnome3
Since GNOME version is now 40, it no longer makes sense to use the old attribute name.
Diffstat (limited to 'pkgs/desktops/gnome')
-rw-r--r--pkgs/desktops/gnome/apps/accerciser/default.nix74
-rw-r--r--pkgs/desktops/gnome/apps/cheese/default.nix121
-rw-r--r--pkgs/desktops/gnome/apps/file-roller/default.nix48
-rw-r--r--pkgs/desktops/gnome/apps/gedit/default.nix81
-rw-r--r--pkgs/desktops/gnome/apps/ghex/default.nix84
-rw-r--r--pkgs/desktops/gnome/apps/gnome-books/default.nix86
-rw-r--r--pkgs/desktops/gnome/apps/gnome-boxes/default.nix145
-rw-r--r--pkgs/desktops/gnome/apps/gnome-calendar/default.nix84
-rw-r--r--pkgs/desktops/gnome/apps/gnome-calendar/gtk_image_reset_crash.patch17
-rw-r--r--pkgs/desktops/gnome/apps/gnome-characters/default.nix88
-rw-r--r--pkgs/desktops/gnome/apps/gnome-clocks/default.nix87
-rw-r--r--pkgs/desktops/gnome/apps/gnome-connections/default.nix75
-rw-r--r--pkgs/desktops/gnome/apps/gnome-documents/default.nix127
-rw-r--r--pkgs/desktops/gnome/apps/gnome-logs/default.nix86
-rw-r--r--pkgs/desktops/gnome/apps/gnome-maps/default.nix104
-rw-r--r--pkgs/desktops/gnome/apps/gnome-music/default.nix113
-rw-r--r--pkgs/desktops/gnome/apps/gnome-nettool/default.nix36
-rw-r--r--pkgs/desktops/gnome/apps/gnome-notes/default.nix87
-rw-r--r--pkgs/desktops/gnome/apps/gnome-power-manager/default.nix60
-rw-r--r--pkgs/desktops/gnome/apps/gnome-sound-recorder/default.nix72
-rw-r--r--pkgs/desktops/gnome/apps/gnome-todo/default.nix89
-rw-r--r--pkgs/desktops/gnome/apps/gnome-weather/default.nix76
-rw-r--r--pkgs/desktops/gnome/apps/polari/default.nix54
-rw-r--r--pkgs/desktops/gnome/apps/polari/make-thumbnailer-wrappable.patch24
-rw-r--r--pkgs/desktops/gnome/apps/seahorse/default.nix84
-rw-r--r--pkgs/desktops/gnome/apps/vinagre/default.nix34
-rw-r--r--pkgs/desktops/gnome/core/adwaita-icon-theme/default.nix36
-rw-r--r--pkgs/desktops/gnome/core/baobab/default.nix64
-rw-r--r--pkgs/desktops/gnome/core/caribou/default.nix54
-rw-r--r--pkgs/desktops/gnome/core/dconf-editor/default.nix69
-rw-r--r--pkgs/desktops/gnome/core/empathy/default.nix147
-rw-r--r--pkgs/desktops/gnome/core/eog/default.nix95
-rw-r--r--pkgs/desktops/gnome/core/epiphany/default.nix115
-rw-r--r--pkgs/desktops/gnome/core/evince/default.nix135
-rw-r--r--pkgs/desktops/gnome/core/evolution-data-server/default.nix66
-rw-r--r--pkgs/desktops/gnome/core/evolution-data-server/fix-paths.patch11
-rw-r--r--pkgs/desktops/gnome/core/evolution-data-server/hardcode-gsettings.patch526
-rw-r--r--pkgs/desktops/gnome/core/gdm/default.nix180
-rw-r--r--pkgs/desktops/gnome/core/gdm/fix-paths.patch82
-rw-r--r--pkgs/desktops/gnome/core/gdm/gdm-session-worker_forward-vars.patch31
-rw-r--r--pkgs/desktops/gnome/core/gdm/gdm-x-session_extra_args.patch38
-rw-r--r--pkgs/desktops/gnome/core/gdm/gdm-x-session_session-wrapper.patch40
-rw-r--r--pkgs/desktops/gnome/core/gdm/org.gnome.login-screen.gschema.override2
-rw-r--r--pkgs/desktops/gnome/core/gdm/reset-environment.patch20
-rw-r--r--pkgs/desktops/gnome/core/gnome-backgrounds/default.nix22
-rw-r--r--pkgs/desktops/gnome/core/gnome-bluetooth/default.nix86
-rw-r--r--pkgs/desktops/gnome/core/gnome-calculator/default.nix89
-rw-r--r--pkgs/desktops/gnome/core/gnome-color-manager/default.nix66
-rw-r--r--pkgs/desktops/gnome/core/gnome-common/default.nix27
-rw-r--r--pkgs/desktops/gnome/core/gnome-contacts/default.nix95
-rw-r--r--pkgs/desktops/gnome/core/gnome-control-center/default.nix190
-rw-r--r--pkgs/desktops/gnome/core/gnome-control-center/paths.patch194
-rw-r--r--pkgs/desktops/gnome/core/gnome-desktop/bubblewrap-paths.patch15
-rw-r--r--pkgs/desktops/gnome/core/gnome-desktop/default.nix96
-rw-r--r--pkgs/desktops/gnome/core/gnome-dictionary/default.nix36
-rw-r--r--pkgs/desktops/gnome/core/gnome-disk-utility/default.nix85
-rw-r--r--pkgs/desktops/gnome/core/gnome-font-viewer/default.nix35
-rw-r--r--pkgs/desktops/gnome/core/gnome-initial-setup/0001-fix-paths.patch62
-rw-r--r--pkgs/desktops/gnome/core/gnome-initial-setup/default.nix106
-rw-r--r--pkgs/desktops/gnome/core/gnome-initial-setup/vendor.conf5
-rw-r--r--pkgs/desktops/gnome/core/gnome-keyring/default.nix102
-rw-r--r--pkgs/desktops/gnome/core/gnome-online-miners/default.nix116
-rw-r--r--pkgs/desktops/gnome/core/gnome-remote-desktop/default.nix64
-rw-r--r--pkgs/desktops/gnome/core/gnome-screenshot/default.nix43
-rw-r--r--pkgs/desktops/gnome/core/gnome-session/ctl.nix42
-rw-r--r--pkgs/desktops/gnome/core/gnome-session/default.nix90
-rw-r--r--pkgs/desktops/gnome/core/gnome-session/fix-paths.patch42
-rw-r--r--pkgs/desktops/gnome/core/gnome-settings-daemon/default.nix133
-rw-r--r--pkgs/desktops/gnome/core/gnome-settings-daemon/fix-paths.patch15
-rw-r--r--pkgs/desktops/gnome/core/gnome-settings-daemon/global-backlight-helper.patch26
-rw-r--r--pkgs/desktops/gnome/core/gnome-shell-extensions/default.nix73
-rw-r--r--pkgs/desktops/gnome/core/gnome-shell-extensions/fix_gmenu.patch11
-rw-r--r--pkgs/desktops/gnome/core/gnome-shell/default.nix225
-rw-r--r--pkgs/desktops/gnome/core/gnome-shell/fix-paths.patch30
-rw-r--r--pkgs/desktops/gnome/core/gnome-shell/shew-gir-path.patch11
-rw-r--r--pkgs/desktops/gnome/core/gnome-shell/wrap-services.patch57
-rw-r--r--pkgs/desktops/gnome/core/gnome-software/default.nix120
-rw-r--r--pkgs/desktops/gnome/core/gnome-software/fix-paths.patch11
-rw-r--r--pkgs/desktops/gnome/core/gnome-system-monitor/default.nix81
-rw-r--r--pkgs/desktops/gnome/core/gnome-terminal/default.nix51
-rw-r--r--pkgs/desktops/gnome/core/gnome-themes-extra/default.nix35
-rw-r--r--pkgs/desktops/gnome/core/gnome-tour/default.nix75
-rw-r--r--pkgs/desktops/gnome/core/gnome-user-share/default.nix96
-rw-r--r--pkgs/desktops/gnome/core/gucharmap/default.nix108
-rw-r--r--pkgs/desktops/gnome/core/libgnome-keyring/default.nix32
-rw-r--r--pkgs/desktops/gnome/core/mutter/3.34/0001-EGL-Include-EGL-eglmesaext.h.patch74
-rw-r--r--pkgs/desktops/gnome/core/mutter/3.34/0002-drop-inheritable.patch135
-rw-r--r--pkgs/desktops/gnome/core/mutter/3.34/0003-Fix-glitches-in-gala.patch33
-rw-r--r--pkgs/desktops/gnome/core/mutter/3.34/0004-profiler-track-changes-in-GLib-and-Sysprof.patch58
-rw-r--r--pkgs/desktops/gnome/core/mutter/3.34/0005-meta-Add-missing-display.h-to-meta-workspace-manager.h.patch32
-rw-r--r--pkgs/desktops/gnome/core/mutter/3.34/0006-build-bump-ABI-to-sysprof-capture-4.patch102
-rw-r--r--pkgs/desktops/gnome/core/mutter/3.34/0007-fix-paths.patch27
-rw-r--r--pkgs/desktops/gnome/core/mutter/3.34/default.nix134
-rw-r--r--pkgs/desktops/gnome/core/mutter/default.nix170
-rw-r--r--pkgs/desktops/gnome/core/mutter/drop-inheritable.patch132
-rw-r--r--pkgs/desktops/gnome/core/mutter/fix-paths.patch13
-rw-r--r--pkgs/desktops/gnome/core/nautilus/default.nix118
-rw-r--r--pkgs/desktops/gnome/core/nautilus/extension_dir.patch24
-rw-r--r--pkgs/desktops/gnome/core/nautilus/fix-paths.patch13
-rw-r--r--pkgs/desktops/gnome/core/rygel/add-option-for-installation-sysconfdir.patch38
-rw-r--r--pkgs/desktops/gnome/core/rygel/default.nix110
-rw-r--r--pkgs/desktops/gnome/core/simple-scan/default.nix89
-rw-r--r--pkgs/desktops/gnome/core/sushi/default.nix83
-rw-r--r--pkgs/desktops/gnome/core/totem/default.nix123
-rw-r--r--pkgs/desktops/gnome/core/yelp-xsl/default.nix52
-rw-r--r--pkgs/desktops/gnome/core/yelp/default.nix36
-rw-r--r--pkgs/desktops/gnome/core/zenity/default.nix50
-rw-r--r--pkgs/desktops/gnome/default.nix366
-rw-r--r--pkgs/desktops/gnome/devtools/anjuta/default.nix44
-rw-r--r--pkgs/desktops/gnome/devtools/devhelp/default.nix80
-rw-r--r--pkgs/desktops/gnome/devtools/gnome-devel-docs/default.nix25
-rw-r--r--pkgs/desktops/gnome/extensions/EasyScreenCast/default.nix38
-rw-r--r--pkgs/desktops/gnome/extensions/EasyScreenCast/fix-gi-path.patch16
-rw-r--r--pkgs/desktops/gnome/extensions/appindicator/default.nix36
-rw-r--r--pkgs/desktops/gnome/extensions/arcmenu/default.nix35
-rw-r--r--pkgs/desktops/gnome/extensions/arcmenu/fix_gmenu.patch11
-rw-r--r--pkgs/desktops/gnome/extensions/caffeine/default.nix40
-rw-r--r--pkgs/desktops/gnome/extensions/chrome-gnome-shell/default.nix71
-rw-r--r--pkgs/desktops/gnome/extensions/clipboard-indicator/default.nix30
-rw-r--r--pkgs/desktops/gnome/extensions/clock-override/default.nix37
-rw-r--r--pkgs/desktops/gnome/extensions/dash-to-dock/default.nix35
-rw-r--r--pkgs/desktops/gnome/extensions/dash-to-panel/default.nix28
-rw-r--r--pkgs/desktops/gnome/extensions/disable-unredirect/default.nix31
-rw-r--r--pkgs/desktops/gnome/extensions/draw-on-your-screen/default.nix29
-rw-r--r--pkgs/desktops/gnome/extensions/drop-down-terminal/default.nix36
-rw-r--r--pkgs/desktops/gnome/extensions/drop-down-terminal/fix_vte_and_gjs.patch32
-rw-r--r--pkgs/desktops/gnome/extensions/dynamic-panel-transparency/default.nix38
-rw-r--r--pkgs/desktops/gnome/extensions/emoji-selector/default.nix38
-rw-r--r--pkgs/desktops/gnome/extensions/freon/default.nix37
-rwxr-xr-xpkgs/desktops/gnome/extensions/fuzzy-app-search/default.nix29
-rwxr-xr-xpkgs/desktops/gnome/extensions/fuzzy-app-search/fix-desktop-file-paths.patch50
-rw-r--r--pkgs/desktops/gnome/extensions/gsconnect/default.nix116
-rw-r--r--pkgs/desktops/gnome/extensions/gsconnect/fix-paths.patch37
-rw-r--r--pkgs/desktops/gnome/extensions/gsconnect/installed-tests-path.patch30
-rw-r--r--pkgs/desktops/gnome/extensions/hot-edge/default.nix33
-rw-r--r--pkgs/desktops/gnome/extensions/icon-hider/default.nix31
-rw-r--r--pkgs/desktops/gnome/extensions/impatience/default.nix39
-rw-r--r--pkgs/desktops/gnome/extensions/material-shell/default.nix35
-rw-r--r--pkgs/desktops/gnome/extensions/mpris-indicator-button/default.nix42
-rw-r--r--pkgs/desktops/gnome/extensions/night-theme-switcher/default.nix32
-rw-r--r--pkgs/desktops/gnome/extensions/no-title-bar/default.nix35
-rw-r--r--pkgs/desktops/gnome/extensions/no-title-bar/fix-paths.patch56
-rw-r--r--pkgs/desktops/gnome/extensions/noannoyance/default.nix31
-rw-r--r--pkgs/desktops/gnome/extensions/paperwm/default.nix31
-rw-r--r--pkgs/desktops/gnome/extensions/pidgin-im-integration/default.nix36
-rw-r--r--pkgs/desktops/gnome/extensions/remove-dropdown-arrows/default.nix34
-rw-r--r--pkgs/desktops/gnome/extensions/sound-output-device-chooser/default.nix44
-rw-r--r--pkgs/desktops/gnome/extensions/sound-output-device-chooser/fix-paths.patch26
-rw-r--r--pkgs/desktops/gnome/extensions/system-monitor/default.nix50
-rw-r--r--pkgs/desktops/gnome/extensions/system-monitor/paths_and_nonexisting_dirs.patch33
-rw-r--r--pkgs/desktops/gnome/extensions/taskwhisperer/default.nix42
-rw-r--r--pkgs/desktops/gnome/extensions/taskwhisperer/fix-paths.patch99
-rw-r--r--pkgs/desktops/gnome/extensions/tilingnome/default.nix38
-rw-r--r--pkgs/desktops/gnome/extensions/timepp/default.nix28
-rw-r--r--pkgs/desktops/gnome/extensions/topicons-plus/default.nix28
-rw-r--r--pkgs/desktops/gnome/extensions/unite/default.nix40
-rw-r--r--pkgs/desktops/gnome/extensions/window-corner-preview/default.nix31
-rw-r--r--pkgs/desktops/gnome/extensions/window-is-ready-remover/default.nix28
-rw-r--r--pkgs/desktops/gnome/extensions/workspace-matrix/default.nix36
-rw-r--r--pkgs/desktops/gnome/find-latest-version.py89
-rw-r--r--pkgs/desktops/gnome/games/aisleriot/default.nix77
-rw-r--r--pkgs/desktops/gnome/games/atomix/default.nix37
-rw-r--r--pkgs/desktops/gnome/games/five-or-more/default.nix40
-rw-r--r--pkgs/desktops/gnome/games/four-in-a-row/default.nix39
-rw-r--r--pkgs/desktops/gnome/games/gnome-chess/default.nix68
-rw-r--r--pkgs/desktops/gnome/games/gnome-klotski/default.nix43
-rw-r--r--pkgs/desktops/gnome/games/gnome-mahjongg/default.nix41
-rw-r--r--pkgs/desktops/gnome/games/gnome-mines/default.nix39
-rw-r--r--pkgs/desktops/gnome/games/gnome-nibbles/default.nix84
-rw-r--r--pkgs/desktops/gnome/games/gnome-robots/default.nix73
-rw-r--r--pkgs/desktops/gnome/games/gnome-sudoku/default.nix35
-rw-r--r--pkgs/desktops/gnome/games/gnome-taquin/default.nix75
-rw-r--r--pkgs/desktops/gnome/games/gnome-tetravex/default.nix39
-rw-r--r--pkgs/desktops/gnome/games/hitori/default.nix66
-rw-r--r--pkgs/desktops/gnome/games/iagno/default.nix77
-rw-r--r--pkgs/desktops/gnome/games/lightsoff/default.nix39
-rw-r--r--pkgs/desktops/gnome/games/quadrapassel/default.nix40
-rw-r--r--pkgs/desktops/gnome/games/swell-foop/default.nix72
-rw-r--r--pkgs/desktops/gnome/games/tali/default.nix38
-rw-r--r--pkgs/desktops/gnome/installer.nix15
-rw-r--r--pkgs/desktops/gnome/misc/geary/default.nix160
-rw-r--r--pkgs/desktops/gnome/misc/gitg/default.nix95
-rw-r--r--pkgs/desktops/gnome/misc/gnome-applets/default.nix80
-rw-r--r--pkgs/desktops/gnome/misc/gnome-autoar/default.nix48
-rw-r--r--pkgs/desktops/gnome/misc/gnome-flashback/default.nix203
-rw-r--r--pkgs/desktops/gnome/misc/gnome-packagekit/default.nix37
-rw-r--r--pkgs/desktops/gnome/misc/gnome-panel/default.nix99
-rw-r--r--pkgs/desktops/gnome/misc/gnome-screensaver/fix-dbus-service-dir.patch11
-rw-r--r--pkgs/desktops/gnome/misc/gnome-tweaks/default.nix81
-rw-r--r--pkgs/desktops/gnome/misc/gpaste/default.nix81
-rw-r--r--pkgs/desktops/gnome/misc/gpaste/fix-paths.patch37
-rw-r--r--pkgs/desktops/gnome/misc/gtkhtml/default.nix27
-rw-r--r--pkgs/desktops/gnome/misc/libgnome-games-support/default.nix58
-rw-r--r--pkgs/desktops/gnome/misc/metacity/default.nix74
-rw-r--r--pkgs/desktops/gnome/misc/metacity/fix-paths.patch11
-rw-r--r--pkgs/desktops/gnome/misc/nautilus-python/default.nix63
-rw-r--r--pkgs/desktops/gnome/misc/pomodoro/default.nix73
-rw-r--r--pkgs/desktops/gnome/update.nix26
198 files changed, 13034 insertions, 0 deletions
diff --git a/pkgs/desktops/gnome/apps/accerciser/default.nix b/pkgs/desktops/gnome/apps/accerciser/default.nix
new file mode 100644
index 00000000000..d81b8466194
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/accerciser/default.nix
@@ -0,0 +1,74 @@
+{ lib
+, fetchurl
+, pkg-config
+, gnome
+, gtk3
+, wrapGAppsHook
+, gobject-introspection
+, itstool
+, libxml2
+, python3
+, at-spi2-core
+, dbus
+, gettext
+, libwnck3
+, adwaita-icon-theme
+}:
+
+python3.pkgs.buildPythonApplication rec {
+  pname = "accerciser";
+  version = "3.38.0";
+
+  format = "other";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "0fd9vv2abd2if2qj4nlfy7mpd7rc4sx18zhmxd5ijlnfhkpggbp5";
+  };
+
+  nativeBuildInputs = [
+    gettext
+    gobject-introspection # For setup hook
+    itstool
+    libxml2
+    pkg-config
+    dbus
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    adwaita-icon-theme
+    at-spi2-core
+    gtk3
+    libwnck3
+  ];
+
+  propagatedBuildInputs = with python3.pkgs; [
+    ipython
+    pyatspi
+    pycairo
+    pygobject3
+    setuptools
+    xlib
+  ];
+
+  # Strict deps breaks accerciser
+  # and https://github.com/NixOS/nixpkgs/issues/56943
+  strictDeps = false;
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "accerciser";
+      attrPath = "gnome.accerciser";
+      versionPolicy = "odd-unstable";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Accerciser";
+    description = "Interactive Python accessibility explorer";
+    maintainers = teams.gnome.members;
+    license = licenses.bsd3;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/apps/cheese/default.nix b/pkgs/desktops/gnome/apps/cheese/default.nix
new file mode 100644
index 00000000000..d0a9d6aaabb
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/cheese/default.nix
@@ -0,0 +1,121 @@
+{ lib
+, stdenv
+, gettext
+, fetchurl
+, fetchpatch
+, wrapGAppsHook
+, gnome-video-effects
+, libcanberra-gtk3
+, pkg-config
+, gtk3
+, glib
+, clutter-gtk
+, clutter-gst
+, gst_all_1
+, itstool
+, vala
+, docbook_xml_dtd_43
+, docbook-xsl-nons
+, appstream-glib
+, libxslt
+, gtk-doc
+, adwaita-icon-theme
+, librsvg
+, totem
+, gdk-pixbuf
+, gnome
+, gnome-desktop
+, libxml2
+, meson
+, ninja
+, dbus
+, python3
+}:
+
+stdenv.mkDerivation rec {
+  pname = "cheese";
+  version = "3.38.0";
+
+  outputs = [ "out" "man" "devdoc" ];
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/cheese/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "0vyim2avlgq3a48rgdfz5g21kqk11mfb53b2l883340v88mp7ll8";
+  };
+
+  patches = [
+    # Fix build with latest Vala or GLib
+    (fetchpatch {
+      url = "https://gitlab.gnome.org/GNOME/cheese/commit/7cf6268e54620bbbe5e6e61800c50fb0cb4bea57.patch";
+      sha256 = "WJgGNrpZLTahe7Sxr8HdTl+4Mf4VcmJb6DdiInlDcT4=";
+    })
+  ];
+
+  nativeBuildInputs = [
+    appstream-glib
+    docbook_xml_dtd_43
+    docbook-xsl-nons
+    gettext
+    gtk-doc
+    itstool
+    libxml2
+    libxslt # for xsltproc
+    meson
+    ninja
+    pkg-config
+    python3
+    vala
+    wrapGAppsHook
+    glib # for glib-compile-schemas
+  ];
+
+  buildInputs = [
+    adwaita-icon-theme
+    clutter-gst
+    clutter-gtk
+    dbus
+    gdk-pixbuf
+    glib
+    gnome-desktop
+    gnome-video-effects
+    gst_all_1.gst-plugins-bad
+    gst_all_1.gst-plugins-base
+    gst_all_1.gst-plugins-good
+    gst_all_1.gstreamer
+    gtk3
+    libcanberra-gtk3
+    librsvg
+  ];
+
+  postPatch = ''
+    chmod +x meson_post_install.py
+    patchShebangs meson_post_install.py
+  '';
+
+  preFixup = ''
+    gappsWrapperArgs+=(
+      # Effects
+      --prefix XDG_DATA_DIRS : "${gnome-video-effects}/share"
+      # vp8enc preset
+      --prefix GST_PRESET_PATH : "${gst_all_1.gst-plugins-good}/share/gstreamer-1.0/presets"
+      # Thumbnailers
+      --prefix XDG_DATA_DIRS : "${gdk-pixbuf}/share"
+      --prefix XDG_DATA_DIRS : "${totem}/share"
+    )
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "cheese";
+      attrPath = "gnome.cheese";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Cheese";
+    description = "Take photos and videos with your webcam, with fun graphical effects";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/apps/file-roller/default.nix b/pkgs/desktops/gnome/apps/file-roller/default.nix
new file mode 100644
index 00000000000..6af1994fb06
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/file-roller/default.nix
@@ -0,0 +1,48 @@
+{ lib, stdenv, fetchurl, glib, gtk3, meson, ninja, pkg-config, gnome, gettext, itstool, libxml2, libarchive
+, file, json-glib, python3, wrapGAppsHook, desktop-file-utils, libnotify, nautilus, glibcLocales
+, unzip, cpio }:
+
+stdenv.mkDerivation rec {
+  pname = "file-roller";
+  version = "3.40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "039w1dcpa5ypmv6sm634alk9vbcdkyvy595vkh5gn032jsiqca2a";
+  };
+
+  LANG = "en_US.UTF-8"; # postinstall.py
+
+  nativeBuildInputs = [ meson ninja gettext itstool pkg-config libxml2 python3 wrapGAppsHook glibcLocales desktop-file-utils ];
+
+  buildInputs = [ glib gtk3 json-glib libarchive file gnome.adwaita-icon-theme libnotify nautilus cpio ];
+
+  PKG_CONFIG_LIBNAUTILUS_EXTENSION_EXTENSIONDIR = "${placeholder "out"}/lib/nautilus/extensions-3.0";
+
+  postPatch = ''
+    chmod +x postinstall.py # patchShebangs requires executable file
+    patchShebangs postinstall.py
+    patchShebangs data/set-mime-type-entry.py
+  '';
+
+  postFixup = ''
+    # Workaround because of https://gitlab.gnome.org/GNOME/file-roller/issues/40
+    wrapProgram "$out/bin/file-roller" \
+      --prefix PATH : ${lib.makeBinPath [ unzip ]}
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "file-roller";
+      attrPath = "gnome.file-roller";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/FileRoller";
+    description = "Archive manager for the GNOME desktop environment";
+    license = licenses.gpl2Plus;
+    platforms = platforms.linux;
+    maintainers = teams.gnome.members;
+  };
+}
diff --git a/pkgs/desktops/gnome/apps/gedit/default.nix b/pkgs/desktops/gnome/apps/gedit/default.nix
new file mode 100644
index 00000000000..a8479e9cdca
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/gedit/default.nix
@@ -0,0 +1,81 @@
+{ lib, stdenv
+, meson
+, fetchurl
+, python3
+, pkg-config
+, gtk3
+, glib
+, adwaita-icon-theme
+, libpeas
+, gtksourceview4
+, gsettings-desktop-schemas
+, wrapGAppsHook
+, ninja
+, libsoup
+, tepl
+, gnome
+, gspell
+, perl
+, itstool
+, desktop-file-utils
+, vala
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gedit";
+  version = "40.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gedit/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "149ngl9qw6h59546lir1pa7hvw23ppsnqlj9mfqphmmn5jl99qsm";
+  };
+
+  nativeBuildInputs = [
+    desktop-file-utils
+    itstool
+    meson
+    ninja
+    perl
+    pkg-config
+    python3
+    vala
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    adwaita-icon-theme
+    glib
+    gsettings-desktop-schemas
+    gspell
+    gtk3
+    gtksourceview4
+    libpeas
+    libsoup
+    tepl
+  ];
+
+  postPatch = ''
+    chmod +x build-aux/meson/post_install.py
+    chmod +x plugins/externaltools/scripts/gedit-tool-merge.pl
+    patchShebangs build-aux/meson/post_install.py
+    patchShebangs plugins/externaltools/scripts/gedit-tool-merge.pl
+  '';
+
+  # Reliably fails to generate gedit-file-browser-enum-types.h in time
+  enableParallelBuilding = false;
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "gedit";
+      attrPath = "gnome.gedit";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Gedit";
+    description = "Official text editor of the GNOME desktop environment";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2;
+    platforms = platforms.unix;
+  };
+}
diff --git a/pkgs/desktops/gnome/apps/ghex/default.nix b/pkgs/desktops/gnome/apps/ghex/default.nix
new file mode 100644
index 00000000000..500e60feb75
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/ghex/default.nix
@@ -0,0 +1,84 @@
+{ lib, stdenv
+, fetchurl
+, fetchpatch
+, pkg-config
+, meson
+, ninja
+, python3
+, gnome
+, desktop-file-utils
+, appstream-glib
+, gettext
+, itstool
+, libxml2
+, gtk3
+, glib
+, atk
+, wrapGAppsHook
+}:
+
+stdenv.mkDerivation rec {
+  pname = "ghex";
+  version = "3.18.4";
+
+  outputs = [ "out" "dev" ];
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/ghex/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "1h1pjrr9wynclfykizqd78dbi785wjz6b63p31k87kjvzy8w3nf2";
+  };
+
+  nativeBuildInputs = [
+    desktop-file-utils
+    gettext
+    itstool
+    meson
+    ninja
+    pkg-config
+    python3
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    gtk3
+    atk
+    glib
+  ];
+
+  checkInputs = [
+    appstream-glib
+    desktop-file-utils
+  ];
+
+  patches = [
+    # Fixes for darwin. Drop in next release.
+    (fetchpatch {
+      url = "https://gitlab.gnome.org/GNOME/ghex/commit/b0af26666cd990d99076c242b2abb3efc6e98671.patch";
+      sha256 = "1zwdkgr2nqrn9q3ydyvrrpn5x55cdi747fhbq6mh6blp9cbrk9b5";
+    })
+    (fetchpatch {
+      url = "https://gitlab.gnome.org/GNOME/ghex/commit/cc8ef9e67b23604c402460010dc0b5dccb85391b.patch";
+      sha256 = "0j2165rfhlbrlzhmcnirqd5m89ljpz0n3nz20sxbwlc8h42zv36s";
+    })
+  ];
+
+  postPatch = ''
+     chmod +x meson_post_install.py
+     patchShebangs meson_post_install.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "ghex";
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Ghex";
+    description = "Hex editor for GNOME desktop environment";
+    platforms = platforms.unix;
+    license = licenses.gpl2Plus;
+    maintainers = teams.gnome.members;
+  };
+}
diff --git a/pkgs/desktops/gnome/apps/gnome-books/default.nix b/pkgs/desktops/gnome/apps/gnome-books/default.nix
new file mode 100644
index 00000000000..0e8b322cf5e
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/gnome-books/default.nix
@@ -0,0 +1,86 @@
+{ lib, stdenv
+, meson
+, ninja
+, gettext
+, fetchurl
+, evince
+, gjs
+, pkg-config
+, gtk3
+, glib
+, tracker
+, tracker-miners
+, libxslt
+, webkitgtk
+, gnome-desktop
+, libgepub
+, gnome
+, gdk-pixbuf
+, gsettings-desktop-schemas
+, adwaita-icon-theme
+, docbook-xsl-nons
+, docbook_xml_dtd_42
+, desktop-file-utils
+, python3
+, gobject-introspection
+, wrapGAppsHook
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-books";
+  version = "40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "0c41l8m2di8h39bmk2fnhpwglwp6qhljmwqqbihzp4ay9976zrc5";
+  };
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    pkg-config
+    gettext
+    libxslt
+    desktop-file-utils
+    docbook-xsl-nons
+    docbook_xml_dtd_42
+    wrapGAppsHook
+    python3
+  ];
+
+  buildInputs = [
+    gtk3
+    glib
+    gsettings-desktop-schemas
+    gdk-pixbuf
+    adwaita-icon-theme
+    evince
+    webkitgtk
+    gjs
+    gobject-introspection
+    tracker
+    tracker-miners
+    gnome-desktop
+    libgepub
+  ];
+
+  postPatch = ''
+    chmod +x meson_post_install.py # patchShebangs requires executable file
+    patchShebangs meson_post_install.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "gnome-books";
+      attrPath = "gnome.gnome-books";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Books";
+    description = "An e-book manager application for GNOME";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/apps/gnome-boxes/default.nix b/pkgs/desktops/gnome/apps/gnome-boxes/default.nix
new file mode 100644
index 00000000000..605275be7de
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/gnome-boxes/default.nix
@@ -0,0 +1,145 @@
+{ lib, stdenv
+, fetchurl
+, meson
+, ninja
+, wrapGAppsHook
+, pkg-config
+, gettext
+, itstool
+, libvirt-glib
+, glib
+, gobject-introspection
+, libxml2
+, gtk3
+, gtksourceview4
+, gtk-vnc
+, freerdp
+, libvirt
+, spice-gtk
+, python3
+, appstream-glib
+, spice-protocol
+, libhandy
+, libsoup
+, libosinfo
+, systemd
+, tracker
+, tracker-miners
+, vala
+, libcap
+, yajl
+, gmp
+, gdbm
+, cyrus_sasl
+, gnome
+, librsvg
+, desktop-file-utils
+, mtools
+, cdrkit
+, libcdio
+, libusb1
+, libarchive
+, acl
+, libgudev
+, libsecret
+, libcap_ng
+, numactl
+, libapparmor
+, json-glib
+, webkitgtk
+, vte
+, glib-networking
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-boxes";
+  version = "40.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "seKPLH+3a/T7uGLQ1S6BG5TL6f8W8GdAiWRWhpCILvg=";
+  };
+
+  doCheck = true;
+
+  nativeBuildInputs = [
+    appstream-glib # for appstream-util
+    desktop-file-utils
+    gettext
+    gobject-introspection
+    itstool
+    meson
+    ninja
+    pkg-config
+    python3
+    vala
+    wrapGAppsHook
+  ];
+
+  # Required for USB redirection PolicyKit rules file
+  propagatedUserEnvPkgs = [
+    spice-gtk
+  ];
+
+  buildInputs = [
+    acl
+    cyrus_sasl
+    freerdp
+    gdbm
+    glib
+    glib-networking
+    gmp
+    gnome.adwaita-icon-theme
+    gtk-vnc
+    gtk3
+    gtksourceview4
+    json-glib
+    libapparmor
+    libarchive
+    libcap
+    libcap_ng
+    libgudev
+    libhandy
+    libosinfo
+    librsvg
+    libsecret
+    libsoup
+    libusb1
+    libvirt
+    libvirt-glib
+    libxml2
+    numactl
+    spice-gtk
+    spice-protocol
+    systemd
+    tracker
+    tracker-miners
+    vte
+    webkitgtk
+    yajl
+  ];
+
+  preFixup = ''
+    gappsWrapperArgs+=(--prefix PATH : "${lib.makeBinPath [ mtools cdrkit libcdio ]}")
+  '';
+
+  postPatch = ''
+    chmod +x build-aux/post_install.py # patchShebangs requires executable file
+    patchShebangs build-aux/post_install.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    description = "Simple GNOME 3 application to access remote or virtual systems";
+    homepage = "https://wiki.gnome.org/Apps/Boxes";
+    license = licenses.lgpl2Plus;
+    platforms = platforms.linux;
+    maintainers = teams.gnome.members;
+  };
+}
diff --git a/pkgs/desktops/gnome/apps/gnome-calendar/default.nix b/pkgs/desktops/gnome/apps/gnome-calendar/default.nix
new file mode 100644
index 00000000000..3e80575a33d
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/gnome-calendar/default.nix
@@ -0,0 +1,84 @@
+{ lib, stdenv
+, fetchurl
+, meson
+, ninja
+, pkg-config
+, wrapGAppsHook
+, libdazzle
+, libgweather
+, geoclue2
+, geocode-glib
+, python3
+, gettext
+, libxml2
+, gnome
+, gtk3
+, evolution-data-server
+, libsoup
+, glib
+, gnome-online-accounts
+, gsettings-desktop-schemas
+, libhandy
+, adwaita-icon-theme
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-calendar";
+  version = "40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "0d74hng9jdmwdcjgj4xfrcink2gwkbp1k1mad4wanaf7q31c6f38";
+  };
+
+  patches = [
+    # https://gitlab.gnome.org/GNOME/gnome-calendar/-/merge_requests/84
+    # A refactor has caused the PR patch to drift enough to need rebasing
+    ./gtk_image_reset_crash.patch
+  ];
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    pkg-config
+    gettext
+    libxml2
+    wrapGAppsHook
+    python3
+  ];
+
+  buildInputs = [
+    gtk3
+    evolution-data-server
+    libsoup
+    glib
+    gnome-online-accounts
+    libdazzle
+    libgweather
+    geoclue2
+    geocode-glib
+    gsettings-desktop-schemas
+    adwaita-icon-theme
+    libhandy
+  ];
+
+  postPatch = ''
+    chmod +x build-aux/meson/meson_post_install.py # patchShebangs requires executable file
+    patchShebangs build-aux/meson/meson_post_install.py
+  '';
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Calendar";
+    description = "Simple and beautiful calendar application for GNOME";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl3;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/apps/gnome-calendar/gtk_image_reset_crash.patch b/pkgs/desktops/gnome/apps/gnome-calendar/gtk_image_reset_crash.patch
new file mode 100644
index 00000000000..5065295b57b
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/gnome-calendar/gtk_image_reset_crash.patch
@@ -0,0 +1,17 @@
+diff --git a/src/gui/views/gcal-year-view.c b/src/gui/views/gcal-year-view.c
+index ac32a8f9..532425c1 100644
+--- a/src/gui/views/gcal-year-view.c
++++ b/src/gui/views/gcal-year-view.c
+@@ -2158,7 +2158,11 @@ update_weather (GcalYearView *self)
+   if (!updated)
+     {
+       gtk_label_set_text (self->temp_label, "");
+-      gtk_image_clear (self->weather_icon);
++      /* FIXME: This should never be NULL, but it somehow is.
++       * https://gitlab.gnome.org/GNOME/gnome-calendar/issues/299
++       */
++      if (self->weather_icon != NULL)
++        gtk_image_clear (self->weather_icon);
+     }
+ }
+ 
diff --git a/pkgs/desktops/gnome/apps/gnome-characters/default.nix b/pkgs/desktops/gnome/apps/gnome-characters/default.nix
new file mode 100644
index 00000000000..5cbd58d602a
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/gnome-characters/default.nix
@@ -0,0 +1,88 @@
+{ lib
+, stdenv
+, fetchurl
+, meson
+, ninja
+, pkg-config
+, gettext
+, gnome
+, glib
+, gtk3
+, pango
+, wrapGAppsHook
+, python3
+, gobject-introspection
+, gjs
+, libunistring
+, libhandy
+, gsettings-desktop-schemas
+, adwaita-icon-theme
+, gnome-desktop
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-characters";
+  version = "40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-characters/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "0z2xa4w921bzpzj6gv88pvbrijcnnwni6jxynwz0ybaravyzaqha";
+  };
+
+  nativeBuildInputs = [
+    gettext
+    gobject-introspection
+    meson
+    ninja
+    pkg-config
+    python3
+    wrapGAppsHook
+  ];
+
+
+  buildInputs = [
+    adwaita-icon-theme
+    gjs
+    glib
+    gnome-desktop # for typelib
+    gsettings-desktop-schemas
+    gtk3
+    libunistring
+    libhandy
+    pango
+  ];
+
+  postPatch = ''
+    chmod +x meson_post_install.py # patchShebangs requires executable file
+    patchShebangs meson_post_install.py
+  '';
+
+  dontWrapGApps = true;
+
+  # Fixes https://github.com/NixOS/nixpkgs/issues/31168
+  postFixup = ''
+    for file in $out/share/org.gnome.Characters/org.gnome.Characters \
+       $out/share/org.gnome.Characters/org.gnome.Characters.BackgroundService
+    do
+      sed -e $"2iimports.package._findEffectiveEntryPointName = () => \'$(basename $file)\' " \
+        -i $file
+
+      wrapGApp "$file"
+    done
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Characters";
+    description = "Simple utility application to find and insert unusual characters";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/apps/gnome-clocks/default.nix b/pkgs/desktops/gnome/apps/gnome-clocks/default.nix
new file mode 100644
index 00000000000..d9a749a24b0
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/gnome-clocks/default.nix
@@ -0,0 +1,87 @@
+{ lib, stdenv
+, fetchurl
+, meson
+, ninja
+, gettext
+, pkg-config
+, wrapGAppsHook
+, itstool
+, desktop-file-utils
+, vala
+, gobject-introspection
+, libxml2
+, gtk3
+, glib
+, gsound
+, sound-theme-freedesktop
+, gsettings-desktop-schemas
+, adwaita-icon-theme
+, gnome-desktop
+, geocode-glib
+, gnome
+, gdk-pixbuf
+, geoclue2
+, libgweather
+, libhandy
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-clocks";
+  version = "40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-clocks/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "02d3jg46sn8d9gd4dsaly22gg5vkbz2gpq4pmwpvncb4rsqk7sn2";
+  };
+
+  nativeBuildInputs = [
+    vala
+    meson
+    ninja
+    pkg-config
+    gettext
+    itstool
+    wrapGAppsHook
+    desktop-file-utils
+    libxml2
+    gobject-introspection # for finding vapi files
+  ];
+
+  buildInputs = [
+    gtk3
+    glib
+    gsettings-desktop-schemas
+    gdk-pixbuf
+    adwaita-icon-theme
+    gnome-desktop
+    geocode-glib
+    geoclue2
+    libgweather
+    gsound
+    libhandy
+  ];
+
+  preFixup = ''
+    gappsWrapperArgs+=(
+      # Fallback sound theme
+      --prefix XDG_DATA_DIRS : "${sound-theme-freedesktop}/share"
+    )
+  '';
+
+  doCheck = true;
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "gnome-clocks";
+      attrPath = "gnome.gnome-clocks";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Clocks";
+    description = "Clock application designed for GNOME 3";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/apps/gnome-connections/default.nix b/pkgs/desktops/gnome/apps/gnome-connections/default.nix
new file mode 100644
index 00000000000..abdf751baeb
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/gnome-connections/default.nix
@@ -0,0 +1,75 @@
+{ lib, stdenv
+, fetchurl
+, gnome
+, meson
+, ninja
+, vala
+, pkg-config
+, glib
+, gtk3
+, python3
+, libxml2
+, gtk-vnc
+, gettext
+, desktop-file-utils
+, appstream-glib
+, gobject-introspection
+, freerdp
+, wrapGAppsHook
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-connections";
+  version = "3.38.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/connections/${lib.versions.majorMinor version}/connections-${version}.tar.xz";
+    hash = "sha256-5c7uBFkh9Vsw6bWWUDjNTMDrrFqI5JEgYlsWpfyuTpA=";
+  };
+
+  nativeBuildInputs = [
+    desktop-file-utils
+    gettext
+    glib # glib-compile-resources
+    meson
+    appstream-glib
+    ninja
+    pkg-config
+    python3
+    vala
+    wrapGAppsHook
+
+    # for gtk-frdp subproject
+    gobject-introspection
+  ];
+
+  buildInputs = [
+    glib
+    gtk-vnc
+    gtk3
+    libxml2
+
+    # for gtk-frdp subproject
+    freerdp
+  ];
+
+  postPatch = ''
+    chmod +x build-aux/meson/postinstall.py
+    patchShebangs build-aux/meson/postinstall.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "connections";
+      attrPath = "gnome-connections";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://gitlab.gnome.org/GNOME/connections";
+    description = "A remote desktop client for the GNOME desktop environment";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl3Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/apps/gnome-documents/default.nix b/pkgs/desktops/gnome/apps/gnome-documents/default.nix
new file mode 100644
index 00000000000..3f7ac34696b
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/gnome-documents/default.nix
@@ -0,0 +1,127 @@
+{ lib, stdenv
+, meson
+, ninja
+, gettext
+, fetchurl
+, fetchpatch
+, evince
+, gjs
+, pkg-config
+, gtk3
+, glib
+, tracker
+, tracker-miners
+, itstool
+, libxslt
+, webkitgtk
+, libgdata
+, gnome-desktop
+, libzapojit
+, libgepub
+, gnome
+, gdk-pixbuf
+, libsoup
+, docbook_xsl
+, docbook_xml_dtd_42
+, gobject-introspection
+, inkscape
+, poppler_utils
+, desktop-file-utils
+, wrapGAppsHook
+, python3
+, appstream-glib
+, gsettings-desktop-schemas
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-documents";
+  version = "3.34.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-documents/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "1qph567mapg3s1a26k7b8y57g9bklhj2mh8xm758z9zkms20xafq";
+  };
+
+  patches = [
+    # Fix inkscape 1.0 usage
+    (fetchpatch {
+      url = "https://gitlab.gnome.org/GNOME/gnome-documents/commit/0f55a18c40a61e6ae4ec4652604775f139892350.diff";
+      sha256 = "1yrisq69dl1dn7639drlbza20a5ic6xg04ksr9iq4sxdx3xj3d8s";
+    })
+  ];
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    pkg-config
+    gettext
+    itstool
+    libxslt
+    desktop-file-utils
+    docbook_xsl
+    docbook_xml_dtd_42
+    wrapGAppsHook
+    python3
+    appstream-glib
+
+    # building getting started
+    inkscape
+    poppler_utils
+  ];
+
+  buildInputs = [
+    gtk3
+    glib
+    gsettings-desktop-schemas
+    gdk-pixbuf
+    gnome.adwaita-icon-theme
+    evince
+    libsoup
+    webkitgtk
+    gjs
+    gobject-introspection
+    tracker
+    tracker-miners
+    libgdata
+    gnome-desktop
+    libzapojit
+    libgepub
+  ];
+
+  doCheck = true;
+
+  mesonFlags = [
+    "-Dgetting_started=true"
+  ];
+
+  postPatch = ''
+    chmod +x meson_post_install.py # patchShebangs requires executable file
+    patchShebangs meson_post_install.py
+  '';
+
+  preFixup = ''
+    substituteInPlace $out/bin/gnome-documents --replace gapplication "${glib.bin}/bin/gapplication"
+  '';
+
+  preConfigure =
+    # To silence inkscape warnings regarding profile directory
+  ''
+    export INKSCAPE_PROFILE_DIR="$(mktemp -d)"
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    broken = true; # Tracker 3 not supported and it cannot start Tracker 2.
+    homepage = "https://wiki.gnome.org/Apps/Documents";
+    description = "Document manager application designed to work with GNOME 3";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/apps/gnome-logs/default.nix b/pkgs/desktops/gnome/apps/gnome-logs/default.nix
new file mode 100644
index 00000000000..da06eb4404c
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/gnome-logs/default.nix
@@ -0,0 +1,86 @@
+{ lib, stdenv
+, fetchurl
+, fetchpatch
+, meson
+, ninja
+, pkg-config
+, gnome
+, glib
+, gtk3
+, wrapGAppsHook
+, gettext
+, itstool
+, libxml2
+, libxslt
+, docbook_xsl
+, docbook_xml_dtd_43
+, systemd
+, python3
+, gsettings-desktop-schemas
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-logs";
+  version = "3.36.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-logs/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "0w1nfdxbv3f0wnhmdy21ydvr4swfc108hypda561p7l9lrhnnxj4";
+  };
+
+  patches = [
+    # https://gitlab.gnome.org/GNOME/gnome-logs/-/issues/52
+    (fetchpatch {
+      url = "https://gitlab.gnome.org/GNOME/gnome-logs/-/commit/b42defceefc775220b525f665a3b662ab9593b81.patch";
+      sha256 = "1s0zscmhwy7r0xff17wh8ik8x9xw1vrkipw5vl5i770bxnljps8n";
+    })
+  ];
+
+  nativeBuildInputs = [
+    python3
+    meson
+    ninja
+    pkg-config
+    wrapGAppsHook
+    gettext
+    itstool
+    libxml2
+    libxslt
+    docbook_xsl
+    docbook_xml_dtd_43
+  ];
+
+  buildInputs = [
+    glib
+    gtk3
+    systemd
+    gsettings-desktop-schemas
+    gnome.adwaita-icon-theme
+  ];
+
+  mesonFlags = [
+    "-Dman=true"
+  ];
+
+  postPatch = ''
+    chmod +x meson_post_install.py
+    patchShebangs meson_post_install.py
+  '';
+
+  doCheck = true;
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "gnome-logs";
+      attrPath = "gnome.gnome-logs";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Logs";
+    description = "A log viewer for the systemd journal";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl3;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/apps/gnome-maps/default.nix b/pkgs/desktops/gnome/apps/gnome-maps/default.nix
new file mode 100644
index 00000000000..2818215a4ff
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/gnome-maps/default.nix
@@ -0,0 +1,104 @@
+{ lib, stdenv
+, fetchurl
+, meson
+, ninja
+, gettext
+, python3
+, pkg-config
+, gnome
+, gtk3
+, gobject-introspection
+, gdk-pixbuf
+, librsvg
+, libgweather
+, geoclue2
+, wrapGAppsHook
+, folks
+, libchamplain
+, gfbgraph
+, libsoup
+, gsettings-desktop-schemas
+, webkitgtk
+, gjs
+, libgee
+, libhandy
+, geocode-glib
+, evolution-data-server
+, gnome-online-accounts
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-maps";
+  version = "40.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "sha256-mAXUwFs6NpV0bTdisoFr/+bZ19VuF7y7nZ1B3C0CYxo=";
+  };
+
+  doCheck = true;
+
+  nativeBuildInputs = [
+    gettext
+    meson
+    ninja
+    pkg-config
+    python3
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    evolution-data-server
+    folks
+    gdk-pixbuf
+    geoclue2
+    geocode-glib
+    gfbgraph
+    gjs
+    gnome-online-accounts
+    gnome.adwaita-icon-theme
+    gobject-introspection
+    gsettings-desktop-schemas
+    gtk3
+    libchamplain
+    libgee
+    libgweather
+    libhandy
+    librsvg
+    libsoup
+    webkitgtk
+  ];
+
+  postPatch = ''
+    chmod +x meson_post_install.py # patchShebangs requires executable file
+    patchShebangs meson_post_install.py
+
+    # The .service file isn't wrapped with the correct environment
+    # so misses GIR files when started. By re-pointing from the gjs
+    # entry point to the wrapped binary we get back to a wrapped
+    # binary.
+    substituteInPlace "data/org.gnome.Maps.service.in" \
+        --replace "Exec=@pkgdatadir@/org.gnome.Maps" \
+                  "Exec=$out/bin/gnome-maps"
+  '';
+
+  preCheck = ''
+    # “time.js” included by “timeTest” and “translationsTest” depends on “org.gnome.desktop.interface” schema.
+    export XDG_DATA_DIRS="${gsettings-desktop-schemas}/share/gsettings-schemas/${gsettings-desktop-schemas.name}:$XDG_DATA_DIRS"
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Maps";
+    description = "A map application for GNOME 3";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/apps/gnome-music/default.nix b/pkgs/desktops/gnome/apps/gnome-music/default.nix
new file mode 100644
index 00000000000..51e3d5a9cdf
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/gnome-music/default.nix
@@ -0,0 +1,113 @@
+{ lib
+, meson
+, ninja
+, gettext
+, fetchurl
+, gdk-pixbuf
+, tracker
+, libxml2
+, python3
+, libnotify
+, wrapGAppsHook
+, libmediaart
+, gobject-introspection
+, gnome-online-accounts
+, grilo
+, grilo-plugins
+, pkg-config
+, gtk3
+, pango
+, glib
+, desktop-file-utils
+, appstream-glib
+, itstool
+, gnome
+, gst_all_1
+, libdazzle
+, libsoup
+, gsettings-desktop-schemas
+}:
+
+python3.pkgs.buildPythonApplication rec {
+  pname = "gnome-music";
+  version = "40.0";
+
+  format = "other";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "1djqhd4jccvk352hwxjhiwjgbnv1qnpv450f2c6w6581vcn9pq38";
+  };
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    gettext
+    itstool
+    pkg-config
+    libxml2
+    wrapGAppsHook
+    desktop-file-utils
+    appstream-glib
+    gobject-introspection
+  ];
+
+  buildInputs = [
+    gtk3
+    pango
+    glib
+    libmediaart
+    gnome-online-accounts
+    gobject-introspection
+    gdk-pixbuf
+    gnome.adwaita-icon-theme
+    python3
+    grilo
+    grilo-plugins
+    libnotify
+    libdazzle
+    libsoup
+    gsettings-desktop-schemas
+    tracker
+  ] ++ (with gst_all_1; [
+    gstreamer
+    gst-plugins-base
+    gst-plugins-good
+    gst-plugins-bad
+    gst-plugins-ugly
+  ]);
+
+  propagatedBuildInputs = with python3.pkgs; [
+    pycairo
+    dbus-python
+    pygobject3
+  ];
+
+
+  postPatch = ''
+    for f in meson_post_conf.py meson_post_install.py; do
+      chmod +x $f
+      patchShebangs $f
+    done
+  '';
+
+  doCheck = false;
+
+  # handle setup hooks better
+  strictDeps = false;
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Music";
+    description = "Music player and management application for the GNOME desktop environment";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/apps/gnome-nettool/default.nix b/pkgs/desktops/gnome/apps/gnome-nettool/default.nix
new file mode 100644
index 00000000000..ca75b7aae07
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/gnome-nettool/default.nix
@@ -0,0 +1,36 @@
+{ lib, stdenv, fetchurl, pkg-config, gnome, gtk3, wrapGAppsHook
+, libgtop, intltool, itstool, libxml2, nmap, inetutils }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-nettool";
+  version = "3.8.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "1c9cvzvyqgfwa5zzyvp7118pkclji62fkbb33g4y9sp5kw6m397h";
+  };
+
+  nativeBuildInputs = [ pkg-config ];
+  buildInputs = [
+    gtk3 wrapGAppsHook libgtop intltool itstool libxml2
+    gnome.adwaita-icon-theme
+  ];
+
+  propagatedUserEnvPkgs = [ nmap inetutils ];
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+      versionPolicy = "none";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://gitlab.gnome.org/GNOME/gnome-nettool";
+    description = "A collection of networking tools";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/apps/gnome-notes/default.nix b/pkgs/desktops/gnome/apps/gnome-notes/default.nix
new file mode 100644
index 00000000000..6af206069e2
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/gnome-notes/default.nix
@@ -0,0 +1,87 @@
+{ lib, stdenv
+, meson
+, ninja
+, gettext
+, fetchurl
+, pkg-config
+, wrapGAppsHook
+, itstool
+, desktop-file-utils
+, python3
+, glib
+, gtk3
+, evolution-data-server
+, gnome-online-accounts
+, json-glib
+, libuuid
+, curl
+, libhandy
+, webkitgtk
+, gnome
+, libxml2
+, gsettings-desktop-schemas
+, tracker
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-notes";
+  version = "40.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/bijiben/${lib.versions.major version}/bijiben-${version}.tar.xz";
+    sha256 = "1gvvb2klkzbmyzwkjgmscdiqcl8lyz9b0rxb4igjz079csq6z805";
+  };
+
+  doCheck = true;
+
+  postPatch = ''
+    chmod +x build-aux/meson_post_install.py
+    patchShebangs build-aux/meson_post_install.py
+  '';
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    pkg-config
+    gettext
+    itstool
+    libxml2
+    desktop-file-utils
+    python3
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    glib
+    gtk3
+    json-glib
+    libuuid
+    curl
+    libhandy
+    webkitgtk
+    tracker
+    gnome-online-accounts
+    gsettings-desktop-schemas
+    evolution-data-server
+    gnome.adwaita-icon-theme
+  ];
+
+  mesonFlags = [
+    "-Dupdate_mimedb=false"
+  ];
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "bijiben";
+      attrPath = "gnome.gnome-notes";
+    };
+  };
+
+  meta = with lib; {
+    description = "Note editor designed to remain simple to use";
+    homepage = "https://wiki.gnome.org/Apps/Notes";
+    license = licenses.gpl3;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/apps/gnome-power-manager/default.nix b/pkgs/desktops/gnome/apps/gnome-power-manager/default.nix
new file mode 100644
index 00000000000..0337f70a20e
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/gnome-power-manager/default.nix
@@ -0,0 +1,60 @@
+{ lib, stdenv
+, gettext
+, fetchurl
+, pkg-config
+, gtk3
+, glib
+, meson
+, ninja
+, upower
+, python3
+, desktop-file-utils
+, wrapGAppsHook
+, gnome }:
+
+let
+  pname = "gnome-power-manager";
+  version = "3.32.0";
+in stdenv.mkDerivation rec {
+  name = "${pname}-${version}";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${name}.tar.xz";
+    sha256 = "0drfn3wcc8l4n07qwv6p0rw2dwcd00hwzda282q62l6sasks2b2g";
+  };
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    pkg-config
+    wrapGAppsHook
+    gettext
+
+    # needed by meson_post_install.sh
+    python3
+    glib.dev
+    desktop-file-utils
+  ];
+
+  buildInputs = [
+    gtk3
+    glib
+    upower
+    gnome.adwaita-icon-theme
+  ];
+
+  meta = with lib; {
+    homepage = "https://projects-old.gnome.org/gnome-power-manager/";
+    description = "View battery and power statistics provided by UPower";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/apps/gnome-sound-recorder/default.nix b/pkgs/desktops/gnome/apps/gnome-sound-recorder/default.nix
new file mode 100644
index 00000000000..29f7aa6e9ee
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/gnome-sound-recorder/default.nix
@@ -0,0 +1,72 @@
+{ lib, stdenv
+, fetchurl
+, pkg-config
+, gettext
+, gobject-introspection
+, wrapGAppsHook
+, gjs
+, glib
+, gtk3
+, gdk-pixbuf
+, gst_all_1
+, gnome
+, meson
+, ninja
+, python3
+, desktop-file-utils
+, libhandy
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-sound-recorder";
+  version = "40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "00b55vsfzx877b7mj744abzjws7zclz71wbvh0axsrbl9l84ranl";
+  };
+
+  nativeBuildInputs = [
+    pkg-config
+    gettext
+    meson
+    ninja
+    gobject-introspection
+    wrapGAppsHook
+    python3
+    desktop-file-utils
+  ];
+
+  buildInputs = [
+    gjs
+    glib
+    gtk3
+    gdk-pixbuf
+    libhandy
+  ] ++ (with gst_all_1; [
+    gstreamer
+    gst-plugins-base
+    gst-plugins-good
+    gst-plugins-bad # for gstreamer-player-1.0
+  ]);
+
+  postPatch = ''
+    chmod +x build-aux/meson_post_install.py
+    patchShebangs build-aux/meson_post_install.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    description = "A simple and modern sound recorder";
+    homepage = "https://wiki.gnome.org/Apps/SoundRecorder";
+    license = licenses.gpl2Plus;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/apps/gnome-todo/default.nix b/pkgs/desktops/gnome/apps/gnome-todo/default.nix
new file mode 100644
index 00000000000..885f21cf3ec
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/gnome-todo/default.nix
@@ -0,0 +1,89 @@
+{ lib, stdenv
+, fetchurl
+, fetchpatch
+, meson
+, ninja
+, pkg-config
+, python3
+, wrapGAppsHook
+, gettext
+, gnome
+, glib
+, gtk3
+, libpeas
+, gnome-online-accounts
+, gsettings-desktop-schemas
+, evolution-data-server
+, libxml2
+, libsoup
+, libical
+, librest
+, json-glib
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-todo";
+  version = "3.28.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "08ygqbib72jlf9y0a16k54zz51sncpq2wa18wp81v46q8301ymy7";
+  };
+
+  patches = [
+    # fix build with libecal 2.0
+    (fetchpatch {
+      name = "gnome-todo-eds-libecal-2.0.patch";
+      url = "https://src.fedoraproject.org/rpms/gnome-todo/raw/bed44b8530f3c79589982e03b430b3a125e9bceb/f/gnome-todo-eds-libecal-2.0.patch";
+      sha256 = "1ghrz973skal36j90wm2z13m3panw983r6y0k7z9gpj5lxgz92mq";
+    })
+  ];
+  postPatch = ''
+    chmod +x meson_post_install.py
+    patchShebangs meson_post_install.py
+  '';
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    pkg-config
+    gettext
+    python3
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    glib
+    gtk3
+    libpeas
+    gnome-online-accounts
+    gsettings-desktop-schemas
+    gnome.adwaita-icon-theme
+    # Plug-ins
+    evolution-data-server
+    libxml2
+    libsoup
+    libical
+    librest
+    json-glib
+  ];
+
+  # Fix parallel building: missing dependency from src/gtd-application.c
+  # Probably remove for 3.30+ https://gitlab.gnome.org/GNOME/gnome-todo/issues/170
+  preBuild = "ninja src/gtd-vcs-identifier.h";
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    description = "Personal task manager for GNOME";
+    homepage = "https://wiki.gnome.org/Apps/Todo";
+    license = licenses.gpl3Plus;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/apps/gnome-weather/default.nix b/pkgs/desktops/gnome/apps/gnome-weather/default.nix
new file mode 100644
index 00000000000..39c10e82a1c
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/gnome-weather/default.nix
@@ -0,0 +1,76 @@
+{ lib
+, stdenv
+, fetchurl
+, pkg-config
+, gnome
+, gtk3
+, libhandy
+, wrapGAppsHook
+, gjs
+, gobject-introspection
+, libgweather
+, meson
+, ninja
+, geoclue2
+, gnome-desktop
+, python3
+, gsettings-desktop-schemas
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-weather";
+  version = "40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-weather/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "1vxfcvga5waangq3rzwdrdxyy5sw40vv0l463lc651s0n8xafd9a";
+  };
+
+  nativeBuildInputs = [
+    pkg-config
+    meson
+    ninja
+    wrapGAppsHook
+    python3
+  ];
+
+  buildInputs = [
+    gtk3
+    libhandy
+    gjs
+    gobject-introspection
+    gnome-desktop
+    libgweather
+    gnome.adwaita-icon-theme
+    geoclue2
+    gsettings-desktop-schemas
+  ];
+
+  postPatch = ''
+    # The .service file is not wrapped with the correct environment
+    # so misses GIR files when started. By re-pointing from the gjs
+    # entry point to the wrapped binary we get back to a wrapped
+    # binary.
+    substituteInPlace "data/org.gnome.Weather.service.in" \
+        --replace "Exec=@DATA_DIR@/@APP_ID@" \
+                  "Exec=$out/bin/gnome-weather"
+
+    chmod +x meson_post_install.py
+    patchShebangs meson_post_install.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "gnome-weather";
+      attrPath = "gnome.gnome-weather";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Weather";
+    description = "Access current weather conditions and forecasts";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/apps/polari/default.nix b/pkgs/desktops/gnome/apps/polari/default.nix
new file mode 100644
index 00000000000..0675ccb2f82
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/polari/default.nix
@@ -0,0 +1,54 @@
+{ lib, stdenv, itstool, fetchurl, gdk-pixbuf, adwaita-icon-theme
+, telepathy-glib, gjs, meson, ninja, gettext, telepathy-idle, libxml2, desktop-file-utils
+, pkg-config, gtk3, glib, libsecret, libsoup, webkitgtk, gobject-introspection, appstream-glib
+, gnome, wrapGAppsHook, telepathy-logger, gspell, gsettings-desktop-schemas }:
+
+let
+  pname = "polari";
+  version = "3.38.0";
+in stdenv.mkDerivation rec {
+  name = "${pname}-${version}";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${name}.tar.xz";
+    sha256 = "1l82nmb5qk4h69rsdhzlcmjjdhwh9jzfs4cnw8hy39sg5v9ady1s";
+  };
+
+  patches = [
+    # Upstream runs the thumbnailer by passing it to gjs.
+    # If we wrap it in a shell script, gjs can no longer run it.
+    # Let’s change the code to run the script directly by making it executable and having gjs in shebang.
+    ./make-thumbnailer-wrappable.patch
+  ];
+
+  propagatedUserEnvPkgs = [ telepathy-idle telepathy-logger ];
+
+  nativeBuildInputs = [
+    meson ninja pkg-config itstool gettext wrapGAppsHook libxml2
+    desktop-file-utils gobject-introspection appstream-glib
+  ];
+
+  buildInputs = [
+    gtk3 glib adwaita-icon-theme gsettings-desktop-schemas
+    telepathy-glib telepathy-logger gjs gspell gdk-pixbuf libsecret libsoup webkitgtk
+  ];
+
+  postFixup = ''
+    wrapGApp "$out/share/polari/thumbnailer.js"
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Polari";
+    description = "IRC chat client designed to integrate with the GNOME desktop";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/apps/polari/make-thumbnailer-wrappable.patch b/pkgs/desktops/gnome/apps/polari/make-thumbnailer-wrappable.patch
new file mode 100644
index 00000000000..0fb09eb154a
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/polari/make-thumbnailer-wrappable.patch
@@ -0,0 +1,24 @@
+diff --git a/src/thumbnailer.js b/src/thumbnailer.js
+old mode 100644
+new mode 100755
+index e2ad0a5..7ebf08a
+--- a/src/thumbnailer.js
++++ b/src/thumbnailer.js
+@@ -1,3 +1,4 @@
++#!/usr/bin/env gjs
+ imports.gi.versions.Gdk = '3.0';
+ imports.gi.versions.Gtk = '3.0';
+ 
+diff --git a/src/urlPreview.js b/src/urlPreview.js
+index f17e0be..ccffc32 100644
+--- a/src/urlPreview.js
++++ b/src/urlPreview.js
+@@ -44,7 +44,7 @@ class Thumbnailer {
+     _generateThumbnail(data) {
+         let { filename, uri } = data;
+         this._subProc = Gio.Subprocess.new(
+-            ['gjs', `${pkg.pkgdatadir}/thumbnailer.js`, uri, filename],
++            [`${pkg.pkgdatadir}/thumbnailer.js`, uri, filename],
+             Gio.SubprocessFlags.NONE);
+         this._subProc.wait_async(null, (o, res) => {
+             try {
diff --git a/pkgs/desktops/gnome/apps/seahorse/default.nix b/pkgs/desktops/gnome/apps/seahorse/default.nix
new file mode 100644
index 00000000000..d46aed7bbe9
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/seahorse/default.nix
@@ -0,0 +1,84 @@
+{ lib, stdenv
+, fetchurl
+, vala
+, meson
+, ninja
+, libpwquality
+, pkg-config
+, gtk3
+, glib
+, wrapGAppsHook
+, itstool
+, gnupg
+, libsoup
+, gnome
+, gpgme
+, python3
+, openldap
+, gcr
+, libsecret
+, avahi
+, p11-kit
+, openssh
+, gsettings-desktop-schemas
+, libhandy
+}:
+
+stdenv.mkDerivation rec {
+  pname = "seahorse";
+  version = "40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    hash = "sha256-fscFezhousbqBB/aghQKOfXsnlsYi0UJFNRTvC1V0Cw=";
+  };
+
+  doCheck = true;
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    pkg-config
+    vala
+    itstool
+    wrapGAppsHook
+    python3
+  ];
+
+  buildInputs = [
+    gtk3
+    glib
+    gcr
+    gsettings-desktop-schemas
+    gnupg
+    gnome.adwaita-icon-theme
+    gpgme
+    libsecret
+    avahi
+    libsoup
+    p11-kit
+    openssh
+    openldap
+    libpwquality
+    libhandy
+  ];
+
+  postPatch = ''
+    patchShebangs build-aux/
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Seahorse";
+    description = "Application for managing encryption keys and passwords in the GnomeKeyring";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/apps/vinagre/default.nix b/pkgs/desktops/gnome/apps/vinagre/default.nix
new file mode 100644
index 00000000000..31e198783e0
--- /dev/null
+++ b/pkgs/desktops/gnome/apps/vinagre/default.nix
@@ -0,0 +1,34 @@
+{ lib, stdenv, fetchurl, pkg-config, gtk3, gnome, vte, libxml2, gtk-vnc, intltool
+, libsecret, itstool, wrapGAppsHook, librsvg }:
+
+stdenv.mkDerivation rec {
+  pname = "vinagre";
+  version = "3.22.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/vinagre/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "cd1cdbacca25c8d1debf847455155ee798c3e67a20903df8b228d4ece5505e82";
+  };
+
+  nativeBuildInputs = [ pkg-config intltool itstool wrapGAppsHook ];
+  buildInputs = [
+    gtk3 vte libxml2 gtk-vnc libsecret gnome.adwaita-icon-theme librsvg
+  ];
+
+  NIX_CFLAGS_COMPILE = "-Wno-format-nonliteral";
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "vinagre";
+      attrPath = "gnome.vinagre";
+    };
+  };
+
+  meta = with lib; {
+    description = "Remote desktop viewer for GNOME";
+    homepage = "https://wiki.gnome.org/Apps/Vinagre";
+    license = licenses.gpl2Plus;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/adwaita-icon-theme/default.nix b/pkgs/desktops/gnome/core/adwaita-icon-theme/default.nix
new file mode 100644
index 00000000000..04f8a7a3c37
--- /dev/null
+++ b/pkgs/desktops/gnome/core/adwaita-icon-theme/default.nix
@@ -0,0 +1,36 @@
+{ lib, stdenv, fetchurl, pkg-config, intltool, gnome
+, iconnamingutils, gtk3, gdk-pixbuf, librsvg, hicolor-icon-theme }:
+
+stdenv.mkDerivation rec {
+  pname = "adwaita-icon-theme";
+  version = "40.1.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/adwaita-icon-theme/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "C2xDbtatmIeoitofcqAZex63OwINjTRKurTH+nJQ+PY=";
+  };
+
+  # For convenience, we can specify adwaita-icon-theme only in packages
+  propagatedBuildInputs = [ hicolor-icon-theme ];
+
+  buildInputs = [ gdk-pixbuf librsvg ];
+
+  nativeBuildInputs = [ pkg-config intltool iconnamingutils gtk3 ];
+
+  dontDropIconThemeCache = true;
+
+  # remove a tree of dirs with no files within
+  postInstall = '' rm -rf "$out/locale" '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "adwaita-icon-theme";
+      attrPath = "gnome.adwaita-icon-theme";
+    };
+  };
+
+  meta = with lib; {
+    platforms = with platforms; linux ++ darwin;
+    maintainers = teams.gnome.members;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/baobab/default.nix b/pkgs/desktops/gnome/core/baobab/default.nix
new file mode 100644
index 00000000000..8d0f9459c3b
--- /dev/null
+++ b/pkgs/desktops/gnome/core/baobab/default.nix
@@ -0,0 +1,64 @@
+{ stdenv
+, lib
+, gettext
+, fetchurl
+, vala
+, desktop-file-utils
+, meson
+, ninja
+, pkg-config
+, python3
+, gtk3
+, libhandy
+, glib
+, libxml2
+, wrapGAppsHook
+, itstool
+, gnome
+}:
+
+stdenv.mkDerivation rec {
+  pname = "baobab";
+  version = "40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "19yii3bdgivxrcka1c4g6dpbmql5nyawwhzlsph7z6bs68nambm6";
+  };
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    pkg-config
+    vala
+    gettext
+    itstool
+    libxml2
+    desktop-file-utils
+    wrapGAppsHook
+    python3
+  ];
+
+  buildInputs = [
+    gtk3
+    libhandy
+    glib
+    gnome.adwaita-icon-theme
+  ];
+
+  doCheck = true;
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+    };
+  };
+
+  meta = with lib; {
+    description = "Graphical application to analyse disk usage in any GNOME environment";
+    homepage = "https://wiki.gnome.org/Apps/DiskUsageAnalyzer";
+    license = licenses.gpl2Plus;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/caribou/default.nix b/pkgs/desktops/gnome/core/caribou/default.nix
new file mode 100644
index 00000000000..5985ff82266
--- /dev/null
+++ b/pkgs/desktops/gnome/core/caribou/default.nix
@@ -0,0 +1,54 @@
+{ fetchurl, lib, stdenv, pkg-config, gnome, glib, gtk3, clutter, dbus, python3, libxml2
+, libxklavier, libXtst, gtk2, intltool, libxslt, at-spi2-core, autoreconfHook
+, wrapGAppsHook, libgee }:
+
+let
+  pname = "caribou";
+  version = "0.4.21";
+  pythonEnv = python3.withPackages ( ps: with ps; [ pygobject3 ] );
+in stdenv.mkDerivation rec {
+  name = "${pname}-${version}";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${name}.tar.xz";
+    sha256 = "0mfychh1q3dx0b96pjz9a9y112bm9yqyim40yykzxx1hppsdjhww";
+  };
+
+  patches = [
+    # Fix crash in GNOME Flashback
+    # https://bugzilla.gnome.org/show_bug.cgi?id=791001
+    (fetchurl {
+      url = "https://bugzilla.gnome.org/attachment.cgi?id=364774";
+      sha256 = "15k1455grf6knlrxqbjnk7sals1730b0whj30451scp46wyvykvd";
+    })
+  ];
+
+  nativeBuildInputs = [ pkg-config intltool libxslt libxml2 autoreconfHook wrapGAppsHook ];
+
+  buildInputs = [
+    glib gtk3 clutter at-spi2-core dbus pythonEnv python3.pkgs.pygobject3
+    libXtst gtk2
+  ];
+
+  propagatedBuildInputs = [ libgee libxklavier ];
+
+  postPatch = ''
+    patchShebangs .
+    substituteInPlace libcaribou/Makefile.am --replace "--shared-library=libcaribou.so.0" "--shared-library=$out/lib/libcaribou.so.0"
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    description = "An input assistive technology intended for switch and pointer users";
+    homepage = "https://wiki.gnome.org/Projects/Caribou";
+    license = licenses.lgpl21;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/dconf-editor/default.nix b/pkgs/desktops/gnome/core/dconf-editor/default.nix
new file mode 100644
index 00000000000..165980d7e9c
--- /dev/null
+++ b/pkgs/desktops/gnome/core/dconf-editor/default.nix
@@ -0,0 +1,69 @@
+{ lib
+, stdenv
+, fetchurl
+, meson
+, ninja
+, vala
+, libxslt
+, pkg-config
+, glib
+, gtk3
+, gnome
+, python3
+, dconf
+, libxml2
+, gettext
+, docbook-xsl-nons
+, wrapGAppsHook
+, gobject-introspection
+}:
+
+stdenv.mkDerivation rec {
+  pname = "dconf-editor";
+  version = "3.38.3";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "sha256-Vxr0x9rU8Em1PmzXKLea3fCMJ92ra8V7OW0hGGbueeM=";
+  };
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    vala
+    libxslt
+    pkg-config
+    wrapGAppsHook
+    gettext
+    docbook-xsl-nons
+    libxml2
+    gobject-introspection
+    python3
+  ];
+
+  buildInputs = [
+    glib
+    gtk3
+    dconf
+  ];
+
+  postPatch = ''
+    chmod +x meson_post_install.py
+    patchShebangs meson_post_install.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    description = "GSettings editor for GNOME";
+    homepage = "https://wiki.gnome.org/Apps/DconfEditor";
+    license = licenses.gpl3Plus;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/empathy/default.nix b/pkgs/desktops/gnome/core/empathy/default.nix
new file mode 100644
index 00000000000..fbfee37cd13
--- /dev/null
+++ b/pkgs/desktops/gnome/core/empathy/default.nix
@@ -0,0 +1,147 @@
+{ lib, stdenv
+, intltool
+, fetchurl
+, webkitgtk
+, pkg-config
+, gtk3
+, glib
+, file
+, librsvg
+, gnome
+, gdk-pixbuf
+, python3
+, telepathy-glib
+, telepathy-farstream
+, clutter-gtk
+, clutter-gst
+, gst_all_1
+, cogl
+, gnome-online-accounts
+, gcr
+, libsecret
+, folks
+, libpulseaudio
+, telepathy-mission-control
+, telepathy-logger
+, libnotify
+, clutter
+, libsoup
+, gnutls
+, evolution-data-server
+, yelp-xsl
+, libcanberra-gtk3
+, p11-kit
+, farstream
+, libtool
+, shared-mime-info
+, wrapGAppsHook
+, itstool
+, libxml2
+, libxslt
+, icu
+, libgee
+, gsettings-desktop-schemas
+, isocodes
+, enchant
+, libchamplain
+, geoclue2
+, geocode-glib
+, cheese
+, libgudev
+}:
+
+stdenv.mkDerivation rec {
+  pname = "empathy";
+  version = "3.25.90";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/empathy/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "0sn10fcymc6lyrabk7vx8lpvlaxxkqnmcwj9zdkfa8qf3388k4nc";
+  };
+
+  propagatedBuildInputs = [
+    (folks.override { telepathySupport = true; })
+    telepathy-logger
+    evolution-data-server
+    telepathy-mission-control
+  ];
+
+  nativeBuildInputs = [
+    pkg-config
+    libtool
+    intltool
+    itstool
+    file
+    wrapGAppsHook
+    libxml2
+    libxslt
+    yelp-xsl
+    python3
+  ];
+
+  buildInputs = [
+    gtk3
+    glib
+    webkitgtk
+    icu
+    gnome-online-accounts
+    telepathy-glib
+    clutter-gtk
+    clutter-gst
+    cogl
+    gst_all_1.gstreamer
+    gst_all_1.gst-plugins-base
+    gcr
+    libsecret
+    libpulseaudio
+    gdk-pixbuf
+    libnotify
+    clutter
+    libsoup
+    gnutls
+    libgee
+    p11-kit
+    libcanberra-gtk3
+    telepathy-farstream
+    farstream
+    gnome.adwaita-icon-theme
+    gsettings-desktop-schemas
+    librsvg
+
+    # Spell-checking
+    enchant
+    isocodes
+
+    # Display maps, location awareness, geocode support
+    libchamplain
+    geoclue2
+    geocode-glib
+
+    # Cheese webcam support, camera monitoring
+    cheese
+    libgudev
+  ];
+
+  enableParallelBuilding = true;
+
+  preFixup = ''
+    gappsWrapperArgs+=(
+      --prefix XDG_DATA_DIRS : "${shared-mime-info}/share"
+    )
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "empathy";
+      versionPolicy = "none";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Empathy";
+    description = "Messaging program which supports text, voice, video chat, and file transfers over many different protocols";
+    maintainers = teams.gnome.members;
+    license = [ licenses.gpl2 ];
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/eog/default.nix b/pkgs/desktops/gnome/core/eog/default.nix
new file mode 100644
index 00000000000..426a8783352
--- /dev/null
+++ b/pkgs/desktops/gnome/core/eog/default.nix
@@ -0,0 +1,95 @@
+{ lib, stdenv
+, fetchurl
+, meson
+, ninja
+, gettext
+, itstool
+, pkg-config
+, libxml2
+, libjpeg
+, libpeas
+, libportal
+, gnome
+, gtk3
+, glib
+, gsettings-desktop-schemas
+, adwaita-icon-theme
+, gnome-desktop
+, lcms2
+, gdk-pixbuf
+, exempi
+, shared-mime-info
+, wrapGAppsHook
+, librsvg
+, libexif
+, gobject-introspection
+, python3
+}:
+
+stdenv.mkDerivation rec {
+  pname = "eog";
+  version = "40.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "sha256-e+CGA3/tm2v4S6yXqD48kYMBt+nJavEwsnJS0KURFok=";
+  };
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    pkg-config
+    gettext
+    itstool
+    wrapGAppsHook
+    libxml2
+    gobject-introspection
+    python3
+  ];
+
+  buildInputs = [
+    libjpeg
+    libportal
+    gtk3
+    gdk-pixbuf
+    glib
+    libpeas
+    librsvg
+    lcms2
+    gnome-desktop
+    libexif
+    exempi
+    gsettings-desktop-schemas
+    shared-mime-info
+    adwaita-icon-theme
+  ];
+
+  postPatch = ''
+    chmod +x meson_post_install.py
+    patchShebangs meson_post_install.py
+  '';
+
+  preFixup = ''
+    gappsWrapperArgs+=(
+      # Thumbnailers
+      --prefix XDG_DATA_DIRS : "${gdk-pixbuf}/share"
+      --prefix XDG_DATA_DIRS : "${librsvg}/share"
+      --prefix XDG_DATA_DIRS : "${shared-mime-info}/share"
+    )
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    description = "GNOME image viewer";
+    homepage = "https://wiki.gnome.org/Apps/EyeOfGnome";
+    license = licenses.gpl2Plus;
+    maintainers = teams.gnome.members;
+    platforms = platforms.unix;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/epiphany/default.nix b/pkgs/desktops/gnome/core/epiphany/default.nix
new file mode 100644
index 00000000000..f286d384c4e
--- /dev/null
+++ b/pkgs/desktops/gnome/core/epiphany/default.nix
@@ -0,0 +1,115 @@
+{ lib, stdenv
+, meson
+, ninja
+, gettext
+, fetchurl
+, pkg-config
+, gtk3
+, glib
+, icu
+, wrapGAppsHook
+, gnome
+, libportal
+, libxml2
+, libxslt
+, itstool
+, webkitgtk
+, libsoup
+, glib-networking
+, libsecret
+, gnome-desktop
+, libnotify
+, libarchive
+, p11-kit
+, sqlite
+, gcr
+, isocodes
+, desktop-file-utils
+, python3
+, nettle
+, gdk-pixbuf
+, gst_all_1
+, json-glib
+, libdazzle
+, libhandy
+, buildPackages
+}:
+
+stdenv.mkDerivation rec {
+  pname = "epiphany";
+  version = "40.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "1l0sb1xg16g4wg3z99xb0w2kbyczbn7q4mphs3w4lxq22xml4sk9";
+  };
+
+  nativeBuildInputs = [
+    desktop-file-utils
+    gettext
+    itstool
+    libxslt
+    meson
+    ninja
+    pkg-config
+    python3
+    wrapGAppsHook
+    buildPackages.glib
+    buildPackages.gtk3
+  ];
+
+  buildInputs = [
+    gcr
+    gdk-pixbuf
+    glib
+    glib-networking
+    gnome-desktop
+    gnome.adwaita-icon-theme
+    gst_all_1.gst-libav
+    gst_all_1.gst-plugins-bad
+    gst_all_1.gst-plugins-base
+    gst_all_1.gst-plugins-good
+    gst_all_1.gst-plugins-ugly
+    gst_all_1.gstreamer
+    gtk3
+    icu
+    isocodes
+    json-glib
+    libdazzle
+    libhandy
+    libportal
+    libnotify
+    libarchive
+    libsecret
+    libsoup
+    libxml2
+    nettle
+    p11-kit
+    sqlite
+    webkitgtk
+  ];
+
+  # Tests need an X display
+  mesonFlags = [
+    "-Dunit_tests=disabled"
+  ];
+
+  postPatch = ''
+    chmod +x post_install.py # patchShebangs requires executable file
+    patchShebangs post_install.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Epiphany";
+    description = "WebKit based web browser for GNOME";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl3Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/evince/default.nix b/pkgs/desktops/gnome/core/evince/default.nix
new file mode 100644
index 00000000000..3d7f3e0b835
--- /dev/null
+++ b/pkgs/desktops/gnome/core/evince/default.nix
@@ -0,0 +1,135 @@
+{ lib, stdenv
+, fetchurl
+, meson
+, ninja
+, pkg-config
+, gettext
+, libxml2
+, appstream
+, glib
+, gtk3
+, pango
+, atk
+, gdk-pixbuf
+, shared-mime-info
+, itstool
+, gnome
+, poppler
+, ghostscriptX
+, djvulibre
+, libspectre
+, libarchive
+, libhandy
+, libsecret
+, wrapGAppsHook
+, librsvg
+, gobject-introspection
+, yelp-tools
+, gspell
+, adwaita-icon-theme
+, gsettings-desktop-schemas
+, gnome-desktop
+, dbus
+, python3
+, texlive
+, t1lib
+, gst_all_1
+, gtk-doc
+, docbook-xsl-nons
+, docbook_xml_dtd_43
+, supportMultimedia ? true # PDF multimedia
+, libgxps
+, supportXPS ? true # Open XML Paper Specification via libgxps
+}:
+
+stdenv.mkDerivation rec {
+  pname = "evince";
+  version = "40.1";
+
+  outputs = [ "out" "dev" "devdoc" ];
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/evince/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "0bfg7prmjk3z8irx1nfkkqph3igg3cy4pwd7pcxjxbshqdin6rks";
+  };
+
+  postPatch = ''
+    chmod +x meson_post_install.py
+    patchShebangs meson_post_install.py
+  '';
+
+  nativeBuildInputs = [
+    appstream
+    docbook-xsl-nons
+    docbook_xml_dtd_43
+    gettext
+    gobject-introspection
+    gtk-doc
+    itstool
+    meson
+    ninja
+    pkg-config
+    python3
+    wrapGAppsHook
+    yelp-tools
+  ];
+
+  buildInputs = [
+    adwaita-icon-theme
+    atk
+    dbus # only needed to find the service directory
+    djvulibre
+    gdk-pixbuf
+    ghostscriptX
+    glib
+    gnome-desktop
+    gsettings-desktop-schemas
+    gspell
+    gtk3
+    libarchive
+    libhandy
+    librsvg
+    libsecret
+    libspectre
+    libxml2
+    pango
+    poppler
+    t1lib
+    texlive.bin.core # kpathsea for DVI support
+  ] ++ lib.optional supportXPS libgxps
+    ++ lib.optionals supportMultimedia (with gst_all_1; [
+      gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav ]);
+
+  mesonFlags = [
+    "-Dnautilus=false"
+    "-Dps=enabled"
+  ];
+
+  NIX_CFLAGS_COMPILE = "-I${glib.dev}/include/gio-unix-2.0";
+
+  preFixup = ''
+    gappsWrapperArgs+=(--prefix XDG_DATA_DIRS : "${shared-mime-info}/share")
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Evince";
+    description = "GNOME's document viewer";
+
+    longDescription = ''
+      Evince is a document viewer for multiple document formats.  It
+      currently supports PDF, PostScript, DjVu, TIFF and DVI.  The goal
+      of Evince is to replace the multiple document viewers that exist
+      on the GNOME Desktop with a single simple application.
+    '';
+
+    license = lib.licenses.gpl2Plus;
+    platforms = platforms.linux;
+    maintainers = teams.gnome.members;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/evolution-data-server/default.nix b/pkgs/desktops/gnome/core/evolution-data-server/default.nix
new file mode 100644
index 00000000000..0ed3565d7f0
--- /dev/null
+++ b/pkgs/desktops/gnome/core/evolution-data-server/default.nix
@@ -0,0 +1,66 @@
+{ fetchurl, lib, stdenv, substituteAll, pkg-config, gnome, python3, gobject-introspection
+, intltool, libsoup, libxml2, libsecret, icu, sqlite, tzdata, libcanberra-gtk3, gcr, p11-kit
+, db, nspr, nss, libical, gperf, wrapGAppsHook, glib-networking, pcre, vala, cmake, ninja
+, libkrb5, openldap, webkitgtk, libaccounts-glib, json-glib, glib, gtk3, libphonenumber
+, gnome-online-accounts, libgweather, libgdata, gsettings-desktop-schemas, boost, protobuf }:
+
+stdenv.mkDerivation rec {
+  pname = "evolution-data-server";
+  version = "3.40.1";
+
+  outputs = [ "out" "dev" ];
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/evolution-data-server/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "08iykha7zhk21b3axsp3v1jfwda612v0m8rz8zlzppm5i8s5ziza";
+  };
+
+  patches = [
+    (substituteAll {
+      src = ./fix-paths.patch;
+      inherit tzdata;
+    })
+  ];
+
+  prePatch = ''
+    substitute ${./hardcode-gsettings.patch} hardcode-gsettings.patch --subst-var-by ESD_GSETTINGS_PATH ${glib.makeSchemaPath "$out" "${pname}-${version}"} \
+      --subst-var-by GDS_GSETTINGS_PATH ${glib.getSchemaPath gsettings-desktop-schemas}
+    patches="$patches $PWD/hardcode-gsettings.patch"
+  '';
+
+  nativeBuildInputs = [
+    cmake ninja pkg-config intltool python3 gperf wrapGAppsHook gobject-introspection vala
+  ];
+  buildInputs = [
+    glib libsoup libxml2 gtk3 gnome-online-accounts
+    gcr p11-kit libgweather libgdata libaccounts-glib json-glib
+    icu sqlite libkrb5 openldap webkitgtk glib-networking
+    libcanberra-gtk3 pcre libphonenumber boost protobuf
+  ];
+
+  propagatedBuildInputs = [ libsecret nss nspr libical db libsoup ];
+
+  cmakeFlags = [
+    "-DENABLE_UOA=OFF"
+    "-DENABLE_VALA_BINDINGS=ON"
+    "-DENABLE_INTROSPECTION=ON"
+    "-DCMAKE_SKIP_BUILD_RPATH=OFF"
+    "-DINCLUDE_INSTALL_DIR=${placeholder "dev"}/include"
+    "-DWITH_PHONENUMBER=ON"
+  ];
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "evolution-data-server";
+      versionPolicy = "odd-unstable";
+    };
+  };
+
+  meta = with lib; {
+    description = "Unified backend for programs that work with contacts, tasks, and calendar information";
+    homepage = "https://wiki.gnome.org/Apps/Evolution";
+    license = licenses.lgpl2;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/evolution-data-server/fix-paths.patch b/pkgs/desktops/gnome/core/evolution-data-server/fix-paths.patch
new file mode 100644
index 00000000000..33423551659
--- /dev/null
+++ b/pkgs/desktops/gnome/core/evolution-data-server/fix-paths.patch
@@ -0,0 +1,11 @@
+--- a/src/calendar/libecal/e-cal-system-timezone.c
++++ b/src/calendar/libecal/e-cal-system-timezone.c
+@@ -26,7 +26,7 @@
+ #ifdef HAVE_SOLARIS
+ #define SYSTEM_ZONEINFODIR "/usr/share/lib/zoneinfo/tab"
+ #else
+-#define SYSTEM_ZONEINFODIR "/usr/share/zoneinfo"
++#define SYSTEM_ZONEINFODIR "@tzdata@/share/zoneinfo"
+ #endif
+ 
+ #define ETC_TIMEZONE        "/etc/timezone"
diff --git a/pkgs/desktops/gnome/core/evolution-data-server/hardcode-gsettings.patch b/pkgs/desktops/gnome/core/evolution-data-server/hardcode-gsettings.patch
new file mode 100644
index 00000000000..4e345c3cb3c
--- /dev/null
+++ b/pkgs/desktops/gnome/core/evolution-data-server/hardcode-gsettings.patch
@@ -0,0 +1,526 @@
+diff --git a/src/addressbook/libebook/e-book-client.c b/src/addressbook/libebook/e-book-client.c
+index 2c0557c3c..5955aa55e 100644
+--- a/src/addressbook/libebook/e-book-client.c
++++ b/src/addressbook/libebook/e-book-client.c
+@@ -1989,7 +1989,20 @@ e_book_client_get_self (ESourceRegistry *registry,
+ 
+ 	*out_client = book_client;
+ 
+-	settings = g_settings_new (SELF_UID_PATH_ID);
++	{
++		GSettingsSchemaSource *schema_source;
++		GSettingsSchema *schema;
++		schema_source = g_settings_schema_source_new_from_directory("@ESD_GSETTINGS_PATH@",
++									    g_settings_schema_source_get_default(),
++									    TRUE,
++									    NULL);
++		schema = g_settings_schema_source_lookup(schema_source,
++							 SELF_UID_PATH_ID,
++							 FALSE);
++		settings = g_settings_new_full(schema, NULL, NULL);
++		g_settings_schema_source_unref(schema_source);
++		g_settings_schema_unref(schema);
++	}
+ 	uid = g_settings_get_string (settings, SELF_UID_KEY);
+ 	g_object_unref (settings);
+ 
+@@ -2057,7 +2070,20 @@ e_book_client_set_self (EBookClient *client,
+ 	g_return_val_if_fail (
+ 		e_contact_get_const (contact, E_CONTACT_UID) != NULL, FALSE);
+ 
+-	settings = g_settings_new (SELF_UID_PATH_ID);
++	{
++		GSettingsSchemaSource *schema_source;
++		GSettingsSchema *schema;
++		schema_source = g_settings_schema_source_new_from_directory("@ESD_GSETTINGS_PATH@",
++									    g_settings_schema_source_get_default(),
++									    TRUE,
++									    NULL);
++		schema = g_settings_schema_source_lookup(schema_source,
++							 SELF_UID_PATH_ID,
++							 FALSE);
++		settings = g_settings_new_full(schema, NULL, NULL);
++		g_settings_schema_source_unref(schema_source);
++		g_settings_schema_unref(schema);
++	}
+ 	g_settings_set_string (
+ 		settings, SELF_UID_KEY,
+ 		e_contact_get_const (contact, E_CONTACT_UID));
+@@ -2093,8 +2119,20 @@ e_book_client_is_self (EContact *contact)
+ 	 * unfortunately the API doesn't allow that.
+ 	 */
+ 	g_mutex_lock (&mutex);
+-	if (!settings)
+-		settings = g_settings_new (SELF_UID_PATH_ID);
++	if (!settings) {
++		GSettingsSchemaSource *schema_source;
++		GSettingsSchema *schema;
++		schema_source = g_settings_schema_source_new_from_directory("@ESD_GSETTINGS_PATH@",
++									    g_settings_schema_source_get_default(),
++									    TRUE,
++									    NULL);
++		schema = g_settings_schema_source_lookup(schema_source,
++							 SELF_UID_PATH_ID,
++							 FALSE);
++		settings = g_settings_new_full(schema, NULL, NULL);
++		g_settings_schema_source_unref(schema_source);
++		g_settings_schema_unref(schema);
++	}
+ 	uid = g_settings_get_string (settings, SELF_UID_KEY);
+ 	g_mutex_unlock (&mutex);
+ 
+diff --git a/src/addressbook/libebook/e-book.c b/src/addressbook/libebook/e-book.c
+index 3396b57c0..ac6420b2e 100644
+--- a/src/addressbook/libebook/e-book.c
++++ b/src/addressbook/libebook/e-book.c
+@@ -2594,7 +2594,20 @@ e_book_get_self (ESourceRegistry *registry,
+ 		return FALSE;
+ 	}
+ 
+-	settings = g_settings_new (SELF_UID_PATH_ID);
++	{
++		GSettingsSchemaSource *schema_source;
++		GSettingsSchema *schema;
++		schema_source = g_settings_schema_source_new_from_directory("@ESD_GSETTINGS_PATH@",
++									    g_settings_schema_source_get_default(),
++									    TRUE,
++									    NULL);
++		schema = g_settings_schema_source_lookup(schema_source,
++							 SELF_UID_PATH_ID,
++							 FALSE);
++		settings = g_settings_new_full(schema, NULL, NULL);
++		g_settings_schema_source_unref(schema_source);
++		g_settings_schema_unref(schema);
++	}
+ 	uid = g_settings_get_string (settings, SELF_UID_KEY);
+ 	g_object_unref (settings);
+ 
+@@ -2649,7 +2662,20 @@ e_book_set_self (EBook *book,
+ 	g_return_val_if_fail (E_IS_BOOK (book), FALSE);
+ 	g_return_val_if_fail (E_IS_CONTACT (contact), FALSE);
+ 
+-	settings = g_settings_new (SELF_UID_PATH_ID);
++	{
++		GSettingsSchemaSource *schema_source;
++		GSettingsSchema *schema;
++		schema_source = g_settings_schema_source_new_from_directory("@ESD_GSETTINGS_PATH@",
++									    g_settings_schema_source_get_default(),
++									    TRUE,
++									    NULL);
++		schema = g_settings_schema_source_lookup(schema_source,
++							 SELF_UID_PATH_ID,
++							 FALSE);
++		settings = g_settings_new_full(schema, NULL, NULL);
++		g_settings_schema_source_unref(schema_source);
++		g_settings_schema_unref(schema);
++	}
+ 	g_settings_set_string (
+ 		settings, SELF_UID_KEY,
+ 		e_contact_get_const (contact, E_CONTACT_UID));
+@@ -2677,7 +2703,20 @@ e_book_is_self (EContact *contact)
+ 
+ 	g_return_val_if_fail (E_IS_CONTACT (contact), FALSE);
+ 
+-	settings = g_settings_new (SELF_UID_PATH_ID);
++	{
++		GSettingsSchemaSource *schema_source;
++		GSettingsSchema *schema;
++		schema_source = g_settings_schema_source_new_from_directory("@ESD_GSETTINGS_PATH@",
++									    g_settings_schema_source_get_default(),
++									    TRUE,
++									    NULL);
++		schema = g_settings_schema_source_lookup(schema_source,
++							 SELF_UID_PATH_ID,
++							 FALSE);
++		settings = g_settings_new_full(schema, NULL, NULL);
++		g_settings_schema_source_unref(schema_source);
++		g_settings_schema_unref(schema);
++	}
+ 	uid = g_settings_get_string (settings, SELF_UID_KEY);
+ 	g_object_unref (settings);
+ 
+diff --git a/src/calendar/backends/contacts/e-cal-backend-contacts.c b/src/calendar/backends/contacts/e-cal-backend-contacts.c
+index de1716941..e83b104f1 100644
+--- a/src/calendar/backends/contacts/e-cal-backend-contacts.c
++++ b/src/calendar/backends/contacts/e-cal-backend-contacts.c
+@@ -1397,7 +1397,20 @@ e_cal_backend_contacts_init (ECalBackendContacts *cbc)
+ 		(GDestroyNotify) g_free,
+ 		(GDestroyNotify) contact_record_free);
+ 
+-	cbc->priv->settings = g_settings_new ("org.gnome.evolution-data-server.calendar");
++	{
++		GSettingsSchemaSource *schema_source;
++		GSettingsSchema *schema;
++		schema_source = g_settings_schema_source_new_from_directory("@ESD_GSETTINGS_PATH@",
++									    g_settings_schema_source_get_default(),
++									    TRUE,
++									    NULL);
++		schema = g_settings_schema_source_lookup(schema_source,
++							 "org.gnome.evolution-data-server.calendar",
++							 FALSE);
++		cbc->priv->settings = g_settings_new_full(schema, NULL, NULL);
++		g_settings_schema_source_unref(schema_source);
++		g_settings_schema_unref(schema);
++	}
+ 	cbc->priv->notifyid = 0;
+ 	cbc->priv->update_alarms_id = 0;
+ 	cbc->priv->alarm_enabled = FALSE;
+diff --git a/src/calendar/libecal/e-reminder-watcher.c b/src/calendar/libecal/e-reminder-watcher.c
+index b08a7f301..a49fe39c5 100644
+--- a/src/calendar/libecal/e-reminder-watcher.c
++++ b/src/calendar/libecal/e-reminder-watcher.c
+@@ -2202,7 +2202,21 @@ e_reminder_watcher_init (EReminderWatcher *watcher)
+ 
+ 	watcher->priv = G_TYPE_INSTANCE_GET_PRIVATE (watcher, E_TYPE_REMINDER_WATCHER, EReminderWatcherPrivate);
+ 	watcher->priv->cancellable = g_cancellable_new ();
+-	watcher->priv->settings = g_settings_new ("org.gnome.evolution-data-server.calendar");
++	{
++		GSettingsSchemaSource *schema_source;
++		GSettingsSchema *schema;
++		schema_source = g_settings_schema_source_new_from_directory("@ESD_GSETTINGS_PATH@",
++									    g_settings_schema_source_get_default(),
++									    TRUE,
++									    NULL);
++		schema = g_settings_schema_source_lookup(schema_source,
++							 "org.gnome.evolution-data-server.calendar",
++							 FALSE);
++		watcher->priv->settings = g_settings_new_full(schema, NULL,
++							      NULL);
++		g_settings_schema_source_unref(schema_source);
++		g_settings_schema_unref(schema);
++	}
+ 	watcher->priv->scheduled = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, e_reminder_watcher_free_rd_slist);
+ 	watcher->priv->default_zone = icaltimezone_copy (zone);
+ 	watcher->priv->timers_enabled = TRUE;
+diff --git a/src/camel/camel-cipher-context.c b/src/camel/camel-cipher-context.c
+index dcdc3eed0..fd2e428c2 100644
+--- a/src/camel/camel-cipher-context.c
++++ b/src/camel/camel-cipher-context.c
+@@ -1635,7 +1635,20 @@ camel_cipher_can_load_photos (void)
+ 	GSettings *settings;
+ 	gboolean load_photos;
+ 
+-	settings = g_settings_new ("org.gnome.evolution-data-server");
++	{
++		GSettingsSchemaSource *schema_source;
++		GSettingsSchema *schema;
++		schema_source = g_settings_schema_source_new_from_directory("@ESD_GSETTINGS_PATH@",
++									    g_settings_schema_source_get_default(),
++									    TRUE,
++									    NULL);
++		schema = g_settings_schema_source_lookup(schema_source,
++							 "org.gnome.evolution-data-server",
++							 FALSE);
++		settings = g_settings_new_full(schema, NULL, NULL);
++		g_settings_schema_source_unref(schema_source);
++		g_settings_schema_unref(schema);
++	}
+ 	load_photos = g_settings_get_boolean (settings, "camel-cipher-load-photos");
+ 	g_clear_object (&settings);
+ 
+diff --git a/src/camel/camel-gpg-context.c b/src/camel/camel-gpg-context.c
+index 1b3362886..f0811b292 100644
+--- a/src/camel/camel-gpg-context.c
++++ b/src/camel/camel-gpg-context.c
+@@ -573,7 +573,20 @@ gpg_ctx_get_executable_name (void)
+ 		GSettings *settings;
+ 		gchar *path;
+ 
+-		settings = g_settings_new ("org.gnome.evolution-data-server");
++		{
++			GSettingsSchemaSource *schema_source;
++			GSettingsSchema *schema;
++			schema_source = g_settings_schema_source_new_from_directory("@ESD_GSETTINGS_PATH@",
++										    g_settings_schema_source_get_default(),
++										    TRUE,
++										    NULL);
++			schema = g_settings_schema_source_lookup(schema_source,
++								 "org.gnome.evolution-data-server",
++								 FALSE);
++			settings = g_settings_new_full(schema, NULL, NULL);
++			g_settings_schema_source_unref(schema_source);
++			g_settings_schema_unref(schema);
++		}
+ 		path = g_settings_get_string (settings, "camel-gpg-binary");
+ 		g_clear_object (&settings);
+ 
+diff --git a/src/libedataserver/e-network-monitor.c b/src/libedataserver/e-network-monitor.c
+index e0d8b87d6..3a4d5a359 100644
+--- a/src/libedataserver/e-network-monitor.c
++++ b/src/libedataserver/e-network-monitor.c
+@@ -255,7 +255,20 @@ e_network_monitor_constructed (GObject *object)
+ 	/* Chain up to parent's method. */
+ 	G_OBJECT_CLASS (e_network_monitor_parent_class)->constructed (object);
+ 
+-	settings = g_settings_new ("org.gnome.evolution-data-server");
++	{
++		GSettingsSchemaSource *schema_source;
++		GSettingsSchema *schema;
++		schema_source = g_settings_schema_source_new_from_directory("@ESD_GSETTINGS_PATH@",
++									    g_settings_schema_source_get_default(),
++									    TRUE,
++									    NULL);
++		schema = g_settings_schema_source_lookup(schema_source,
++							 "org.gnome.evolution-data-server",
++							 FALSE);
++		settings = g_settings_new_full(schema, NULL, NULL);
++		g_settings_schema_source_unref(schema_source);
++		g_settings_schema_unref(schema);
++	}
+ 	g_settings_bind (
+ 		settings, "network-monitor-gio-name",
+ 		object, "gio-name",
+diff --git a/src/libedataserver/e-oauth2-service-google.c b/src/libedataserver/e-oauth2-service-google.c
+index f0c6f2cbf..0053e3ce6 100644
+--- a/src/libedataserver/e-oauth2-service-google.c
++++ b/src/libedataserver/e-oauth2-service-google.c
+@@ -69,7 +69,20 @@ eos_google_read_settings (EOAuth2Service *service,
+ 	if (!value) {
+ 		GSettings *settings;
+ 
+-		settings = g_settings_new ("org.gnome.evolution-data-server");
++		{
++			GSettingsSchemaSource *schema_source;
++			GSettingsSchema *schema;
++			schema_source = g_settings_schema_source_new_from_directory("@ESD_GSETTINGS_PATH@",
++										    g_settings_schema_source_get_default(),
++										    TRUE,
++										    NULL);
++			schema = g_settings_schema_source_lookup(schema_source,
++								 "org.gnome.evolution-data-server",
++								 FALSE);
++			settings = g_settings_new_full(schema, NULL, NULL);
++			g_settings_schema_source_unref(schema_source);
++			g_settings_schema_unref(schema);
++		}
+ 		value = g_settings_get_string (settings, key_name);
+ 		g_object_unref (settings);
+ 
+diff --git a/src/libedataserver/e-oauth2-service-outlook.c b/src/libedataserver/e-oauth2-service-outlook.c
+index 687c10d3b..684583c35 100644
+--- a/src/libedataserver/e-oauth2-service-outlook.c
++++ b/src/libedataserver/e-oauth2-service-outlook.c
+@@ -70,7 +70,20 @@ eos_outlook_read_settings (EOAuth2Service *service,
+ 	if (!value) {
+ 		GSettings *settings;
+ 
+-		settings = g_settings_new ("org.gnome.evolution-data-server");
++		{
++			GSettingsSchemaSource *schema_source;
++			GSettingsSchema *schema;
++			schema_source = g_settings_schema_source_new_from_directory("@ESD_GSETTINGS_PATH@",
++										    g_settings_schema_source_get_default(),
++										    TRUE,
++										    NULL);
++			schema = g_settings_schema_source_lookup(schema_source,
++								 "org.gnome.evolution-data-server",
++								 FALSE);
++			settings = g_settings_new_full(schema, NULL, NULL);
++			g_settings_schema_source_unref(schema_source);
++			g_settings_schema_unref(schema);
++		}
+ 		value = g_settings_get_string (settings, key_name);
+ 		g_object_unref (settings);
+ 
+diff --git a/src/libedataserver/e-oauth2-service.c b/src/libedataserver/e-oauth2-service.c
+index 682673c16..436f52d5f 100644
+--- a/src/libedataserver/e-oauth2-service.c
++++ b/src/libedataserver/e-oauth2-service.c
+@@ -95,7 +95,20 @@ eos_default_guess_can_process (EOAuth2Service *service,
+ 	name_len = strlen (name);
+ 	hostname_len = strlen (hostname);
+ 
+-	settings = g_settings_new ("org.gnome.evolution-data-server");
++	{
++		GSettingsSchemaSource *schema_source;
++		GSettingsSchema *schema;
++		schema_source = g_settings_schema_source_new_from_directory("@ESD_GSETTINGS_PATH@",
++									    g_settings_schema_source_get_default(),
++									    TRUE,
++									    NULL);
++		schema = g_settings_schema_source_lookup(schema_source,
++							 "org.gnome.evolution-data-server",
++							 FALSE);
++		settings = g_settings_new_full(schema, NULL, NULL);
++		g_settings_schema_source_unref(schema_source);
++		g_settings_schema_unref(schema);
++	}
+ 	values = g_settings_get_strv (settings, "oauth2-services-hint");
+ 	g_object_unref (settings);
+ 
+diff --git a/src/libedataserver/e-proxy.c b/src/libedataserver/e-proxy.c
+index 883379a60..989353494 100644
+--- a/src/libedataserver/e-proxy.c
++++ b/src/libedataserver/e-proxy.c
+@@ -969,8 +969,37 @@ e_proxy_init (EProxy *proxy)
+ 
+ 	proxy->priv->type = PROXY_TYPE_SYSTEM;
+ 
+-	proxy->priv->evolution_proxy_settings = g_settings_new ("org.gnome.evolution.shell.network-config");
+-	proxy->priv->proxy_settings = g_settings_new ("org.gnome.system.proxy");
++	{
++		GSettingsSchemaSource *schema_source;
++		GSettingsSchema *schema;
++		schema_source = g_settings_schema_source_new_from_directory("@ESD_GSETTINGS_PATH@",
++									    g_settings_schema_source_get_default(),
++									    TRUE,
++									    NULL);
++		schema = g_settings_schema_source_lookup(schema_source,
++							 "org.gnome.evolution.shell.network-config",
++							 FALSE);
++		proxy->priv->evolution_proxy_settings = g_settings_new_full(schema,
++									    NULL,
++									    NULL);
++		g_settings_schema_source_unref(schema_source);
++		g_settings_schema_unref(schema);
++	}
++	{
++		GSettingsSchemaSource *schema_source;
++		GSettingsSchema *schema;
++		schema_source = g_settings_schema_source_new_from_directory("@GDS_GSETTINGS_PATH@",
++									    g_settings_schema_source_get_default(),
++									    TRUE,
++									    NULL);
++		schema = g_settings_schema_source_lookup(schema_source,
++							 "org.gnome.system.proxy",
++							 FALSE);
++		proxy->priv->proxy_settings = g_settings_new_full(schema,
++								  NULL, NULL);
++		g_settings_schema_source_unref(schema_source);
++		g_settings_schema_unref(schema);
++	}
+ 	proxy->priv->proxy_http_settings = g_settings_get_child (proxy->priv->proxy_settings, "http");
+ 	proxy->priv->proxy_https_settings = g_settings_get_child (proxy->priv->proxy_settings, "https");
+ 	proxy->priv->proxy_socks_settings = g_settings_get_child (proxy->priv->proxy_settings, "socks");
+diff --git a/src/libedataserver/e-source-registry.c b/src/libedataserver/e-source-registry.c
+index a5a30a3e1..5fbdf8190 100644
+--- a/src/libedataserver/e-source-registry.c
++++ b/src/libedataserver/e-source-registry.c
+@@ -1749,7 +1749,21 @@ e_source_registry_init (ESourceRegistry *registry)
+ 
+ 	g_mutex_init (&registry->priv->sources_lock);
+ 
+-	registry->priv->settings = g_settings_new (GSETTINGS_SCHEMA);
++	{
++		GSettingsSchemaSource *schema_source;
++		GSettingsSchema *schema;
++		schema_source = g_settings_schema_source_new_from_directory("@ESD_GSETTINGS_PATH@",
++									    g_settings_schema_source_get_default(),
++									    TRUE,
++									    NULL);
++		schema = g_settings_schema_source_lookup(schema_source,
++							 GSETTINGS_SCHEMA,
++							 FALSE);
++		registry->priv->settings = g_settings_new_full(schema, NULL,
++							       NULL);
++		g_settings_schema_source_unref(schema_source);
++		g_settings_schema_unref(schema);
++	}
+ 
+ 	g_signal_connect (
+ 		registry->priv->settings, "changed",
+diff --git a/src/libedataserverui/e-reminders-widget.c b/src/libedataserverui/e-reminders-widget.c
+index f89cd4a5c..06cca9b5f 100644
+--- a/src/libedataserverui/e-reminders-widget.c
++++ b/src/libedataserverui/e-reminders-widget.c
+@@ -1650,7 +1650,21 @@ static void
+ e_reminders_widget_init (ERemindersWidget *reminders)
+ {
+ 	reminders->priv = e_reminders_widget_get_instance_private (reminders);
+-	reminders->priv->settings = g_settings_new ("org.gnome.evolution-data-server.calendar");
++	{
++		GSettingsSchemaSource *schema_source;
++		GSettingsSchema *schema;
++		schema_source = g_settings_schema_source_new_from_directory("@ESD_GSETTINGS_PATH@",
++									    g_settings_schema_source_get_default(),
++									    TRUE,
++									    NULL);
++		schema = g_settings_schema_source_lookup(schema_source,
++							 "org.gnome.evolution-data-server.calendar",
++							 FALSE);
++		reminders->priv->settings = g_settings_new_full(schema, NULL,
++								NULL);
++		g_settings_schema_source_unref(schema_source);
++		g_settings_schema_unref(schema);
++	}
+ 	reminders->priv->cancellable = g_cancellable_new ();
+ 	reminders->priv->is_empty = TRUE;
+ 	reminders->priv->is_mapped = FALSE;
+diff --git a/src/services/evolution-source-registry/evolution-source-registry-autoconfig.c b/src/services/evolution-source-registry/evolution-source-registry-autoconfig.c
+index 6f03053d6..dffc186c7 100644
+--- a/src/services/evolution-source-registry/evolution-source-registry-autoconfig.c
++++ b/src/services/evolution-source-registry/evolution-source-registry-autoconfig.c
+@@ -706,7 +706,20 @@ evolution_source_registry_merge_autoconfig_sources (ESourceRegistryServer *serve
+ 	gchar *autoconfig_directory;
+ 	gint ii;
+ 
+-	settings = g_settings_new ("org.gnome.evolution-data-server");
++	{
++		GSettingsSchemaSource *schema_source;
++		GSettingsSchema *schema;
++		schema_source = g_settings_schema_source_new_from_directory("@ESD_GSETTINGS_PATH@",
++									    g_settings_schema_source_get_default(),
++									    TRUE,
++									    NULL);
++		schema = g_settings_schema_source_lookup(schema_source,
++							 "org.gnome.evolution-data-server",
++							 FALSE);
++		settings = g_settings_new_full(schema, NULL, NULL);
++		g_settings_schema_source_unref(schema_source);
++		g_settings_schema_unref(schema);
++	}
+ 
+ 	autoconfig_sources = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, e_autoconfig_free_merge_source_data);
+ 
+diff --git a/src/services/evolution-source-registry/evolution-source-registry-migrate-proxies.c b/src/services/evolution-source-registry/evolution-source-registry-migrate-proxies.c
+index d531cb9e2..c5b1c761c 100644
+--- a/src/services/evolution-source-registry/evolution-source-registry-migrate-proxies.c
++++ b/src/services/evolution-source-registry/evolution-source-registry-migrate-proxies.c
+@@ -61,7 +61,20 @@ evolution_source_registry_migrate_proxies (ESourceRegistryServer *server)
+ 	extension_name = E_SOURCE_EXTENSION_PROXY;
+ 	extension = e_source_get_extension (source, extension_name);
+ 
+-	settings = g_settings_new (NETWORK_CONFIG_SCHEMA_ID);
++	{
++		GSettingsSchemaSource *schema_source;
++		GSettingsSchema *schema;
++		schema_source = g_settings_schema_source_new_from_directory("@ESD_GSETTINGS_PATH@",
++									    g_settings_schema_source_get_default(),
++									    TRUE,
++									    NULL);
++			schema = g_settings_schema_source_lookup(schema_source,
++								 NETWORK_CONFIG_SCHEMA_ID,
++								 FALSE);
++			settings = g_settings_new_full(schema, NULL, NULL);
++			g_settings_schema_source_unref(schema_source);
++			g_settings_schema_unref(schema);
++	}
+ 
+ 	switch (g_settings_get_int (settings, "proxy-type")) {
+ 		case 1:
+diff --git a/src/services/evolution-source-registry/evolution-source-registry.c b/src/services/evolution-source-registry/evolution-source-registry.c
+index 1c0a11382..3e144845e 100644
+--- a/src/services/evolution-source-registry/evolution-source-registry.c
++++ b/src/services/evolution-source-registry/evolution-source-registry.c
+@@ -181,7 +181,20 @@ main (gint argc,
+ 
+ reload:
+ 
+-	settings = g_settings_new ("org.gnome.evolution-data-server");
++	{
++		GSettingsSchemaSource *schema_source;
++		GSettingsSchema *schema;
++		schema_source = g_settings_schema_source_new_from_directory("@ESD_GSETTINGS_PATH@",
++									    g_settings_schema_source_get_default(),
++									    TRUE,
++									    NULL);
++		schema = g_settings_schema_source_lookup(schema_source,
++							 "org.gnome.evolution-data-server",
++							 FALSE);
++		settings = g_settings_new_full(schema, NULL, NULL);
++		g_settings_schema_source_unref(schema_source);
++		g_settings_schema_unref(schema);
++	}
+ 
+ 	if (!opt_disable_migration && !g_settings_get_boolean (settings, "migrated")) {
+ 		g_settings_set_boolean (settings, "migrated", TRUE);
diff --git a/pkgs/desktops/gnome/core/gdm/default.nix b/pkgs/desktops/gnome/core/gdm/default.nix
new file mode 100644
index 00000000000..f3044977349
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gdm/default.nix
@@ -0,0 +1,180 @@
+{ lib, stdenv
+, fetchurl
+, fetchpatch
+, substituteAll
+, meson
+, ninja
+, python3
+, rsync
+, pkg-config
+, glib
+, itstool
+, libxml2
+, xorg
+, accountsservice
+, libX11
+, gnome
+, systemd
+, dconf
+, gtk3
+, libcanberra-gtk3
+, pam
+, libselinux
+, keyutils
+, audit
+, gobject-introspection
+, plymouth
+, librsvg
+, coreutils
+, xwayland
+, dbus
+, nixos-icons
+}:
+
+let
+
+  override = substituteAll {
+    src = ./org.gnome.login-screen.gschema.override;
+    icon = "${nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake-white.svg";
+  };
+
+in
+
+stdenv.mkDerivation rec {
+  pname = "gdm";
+  version = "40.0";
+
+  outputs = [ "out" "dev" ];
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gdm/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "XtdLc506Iy/7HkoTK8+WW9/pVdmVtSh3NYh3WwLylQ4=";
+  };
+
+  mesonFlags = [
+    "-Dgdm-xsession=true"
+    # TODO: Setup a default-path? https://gitlab.gnome.org/GNOME/gdm/-/blob/6fc40ac6aa37c8ad87c32f0b1a5d813d34bf7770/meson_options.txt#L6
+    "-Dinitial-vt=${passthru.initialVT}"
+    "-Dudev-dir=${placeholder "out"}/lib/udev/rules.d"
+    "-Dsystemdsystemunitdir=${placeholder "out"}/lib/systemd/system"
+    "-Dsystemduserunitdir=${placeholder "out"}/lib/systemd/user"
+    "--sysconfdir=/etc"
+    "--localstatedir=/var"
+  ];
+
+  nativeBuildInputs = [
+    dconf
+    glib # for glib-compile-schemas
+    itstool
+    meson
+    ninja
+    pkg-config
+    python3
+    rsync
+  ];
+
+  buildInputs = [
+    accountsservice
+    audit
+    glib
+    gobject-introspection
+    gtk3
+    keyutils
+    libX11
+    libcanberra-gtk3
+    libselinux
+    pam
+    plymouth
+    systemd
+    xorg.libXdmcp
+  ];
+
+  patches = [
+    # GDM fails to find g-s with the following error in the journal.
+    # gdm-x-session[976]: dbus-run-session: failed to exec 'gnome-session': No such file or directory
+    # https://gitlab.gnome.org/GNOME/gdm/-/merge_requests/92
+    (fetchpatch {
+      url = "https://gitlab.gnome.org/GNOME/gdm/-/commit/ccecd9c975d04da80db4cd547b67a1a94fa83292.patch";
+      sha256 = "5hKS9wjjhuSAYwXct5vS0dPbmPRIINJoLC0Zm1naz6Q=";
+      revert = true;
+    })
+
+    # Change hardcoded paths to nix store paths.
+    (substituteAll {
+      src = ./fix-paths.patch;
+      inherit coreutils plymouth xwayland dbus;
+    })
+
+    # The following patches implement certain environment variables in GDM which are set by
+    # the gdm configuration module (nixos/modules/services/x11/display-managers/gdm.nix).
+
+    ./gdm-x-session_extra_args.patch
+
+    # Allow specifying a wrapper for running the session command.
+    ./gdm-x-session_session-wrapper.patch
+
+    # Forwards certain environment variables to the gdm-x-session child process
+    # to ensure that the above two patches actually work.
+    ./gdm-session-worker_forward-vars.patch
+
+    # Set up the environment properly when launching sessions
+    # https://github.com/NixOS/nixpkgs/issues/48255
+    ./reset-environment.patch
+  ];
+
+  postPatch = ''
+    patchShebangs build-aux/meson_post_install.py
+
+    # Upstream checks some common paths to find an `X` binary. We already know it.
+    echo #!/bin/sh > build-aux/find-x-server.sh
+    echo "echo ${lib.getBin xorg.xorgserver}/bin/X" >> build-aux/find-x-server.sh
+    patchShebangs build-aux/find-x-server.sh
+  '';
+
+  preInstall = ''
+    install -D ${override} ${DESTDIR}/$out/share/glib-2.0/schemas/org.gnome.login-screen.gschema.override
+  '';
+
+  postInstall = ''
+    # Move stuff from DESTDIR to proper location.
+    # We use rsync to merge the directories.
+    rsync --archive "${DESTDIR}/etc" "$out"
+    rm --recursive "${DESTDIR}/etc"
+    for o in $outputs; do
+        rsync --archive "${DESTDIR}/''${!o}" "$(dirname "''${!o}")"
+        rm --recursive "${DESTDIR}/''${!o}"
+    done
+    # Ensure the DESTDIR is removed.
+    rmdir "${DESTDIR}/nix/store" "${DESTDIR}/nix" "${DESTDIR}"
+
+    # We are setting DESTDIR so the post-install script does not compile the schemas.
+    glib-compile-schemas "$out/share/glib-2.0/schemas"
+  '';
+
+  # HACK: We want to install configuration files to $out/etc
+  # but GDM should read them from /etc on a NixOS system.
+  # With autotools, it was possible to override Make variables
+  # at install time but Meson does not support this
+  # so we need to convince it to install all files to a temporary
+  # location using DESTDIR and then move it to proper one in postInstall.
+  DESTDIR = "${placeholder "out"}/dest";
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "gdm";
+      attrPath = "gnome.gdm";
+    };
+
+    # Used in GDM NixOS module
+    # Don't remove.
+    initialVT = "7";
+  };
+
+  meta = with lib; {
+    description = "A program that manages graphical display servers and handles graphical user logins";
+    homepage = "https://wiki.gnome.org/Projects/GDM";
+    license = licenses.gpl2Plus;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gdm/fix-paths.patch b/pkgs/desktops/gnome/core/gdm/fix-paths.patch
new file mode 100644
index 00000000000..d649556fe9e
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gdm/fix-paths.patch
@@ -0,0 +1,82 @@
+--- a/daemon/gdm-local-display-factory.c
++++ b/daemon/gdm-local-display-factory.c
+@@ -201,7 +201,7 @@
+ #ifdef ENABLE_WAYLAND_SUPPORT
+         gboolean wayland_enabled = FALSE;
+         if (gdm_settings_direct_get_boolean (GDM_KEY_WAYLAND_ENABLE, &wayland_enabled)) {
+-                if (wayland_enabled && g_file_test ("/usr/bin/Xwayland", G_FILE_TEST_IS_EXECUTABLE) )
++                if (wayland_enabled && g_file_test ("@xwayland@/bin/Xwayland", G_FILE_TEST_IS_EXECUTABLE) )
+                         return TRUE;
+         }
+ #endif
+--- a/daemon/gdm-manager.c
++++ b/daemon/gdm-manager.c
+@@ -145,7 +145,7 @@
+         GError  *error;
+
+         error = NULL;
+-        res = g_spawn_command_line_sync ("plymouth --ping",
++        res = g_spawn_command_line_sync ("@plymouth@/bin/plymouth --ping",
+                                          NULL, NULL, &status, &error);
+         if (! res) {
+                 g_debug ("Could not ping plymouth: %s", error->message);
+@@ -163,7 +163,7 @@
+         GError  *error;
+
+         error = NULL;
+-        res = g_spawn_command_line_sync ("plymouth deactivate",
++        res = g_spawn_command_line_sync ("@plymouth@/bin/plymouth deactivate",
+                                          NULL, NULL, NULL, &error);
+         if (! res) {
+                 g_warning ("Could not deactivate plymouth: %s", error->message);
+@@ -178,7 +178,7 @@
+         GError  *error;
+
+         error = NULL;
+-        res = g_spawn_command_line_async ("plymouth quit --retain-splash", &error);
++        res = g_spawn_command_line_async ("@plymouth@/bin/plymouth quit --retain-splash", &error);
+         if (! res) {
+                 g_warning ("Could not quit plymouth: %s", error->message);
+                 g_error_free (error);
+@@ -194,7 +194,7 @@
+         GError  *error;
+
+         error = NULL;
+-        res = g_spawn_command_line_async ("plymouth quit", &error);
++        res = g_spawn_command_line_async ("@plymouth@/bin/plymouth quit", &error);
+         if (! res) {
+                 g_warning ("Could not quit plymouth: %s", error->message);
+                 g_error_free (error);
+--- a/data/gdm.service.in
++++ b/data/gdm.service.in
+@@ -26,7 +26,7 @@ Restart=always
+ IgnoreSIGPIPE=no
+ BusName=org.gnome.DisplayManager
+ EnvironmentFile=-${LANG_CONFIG_FILE}
+-ExecReload=/bin/kill -SIGHUP $MAINPID
++ExecReload=@coreutils@/bin/kill -SIGHUP $MAINPID
+ KeyringMode=shared
+
+ [Install]
+--- a/daemon/gdm-session.c
++++ b/daemon/gdm-session.c
+@@ -2916,16 +2916,16 @@ gdm_session_start_session (GdmSession *self,
+                  */
+                 if (run_launcher) {
+                         if (is_x11) {
+-                                program = g_strdup_printf (LIBEXECDIR "/gdm-x-session %s\"dbus-run-session -- %s\"",
++                                program = g_strdup_printf (LIBEXECDIR "/gdm-x-session %s\"@dbus@/bin/dbus-run-session --dbus-daemon=@dbus@/bin/dbus-daemon -- %s\"",
+                                                            register_session ? "--register-session " : "",
+                                                            self->selected_program);
+                         } else {
+-                                program = g_strdup_printf (LIBEXECDIR "/gdm-wayland-session %s\"dbus-run-session -- %s\"",
++                                program = g_strdup_printf (LIBEXECDIR "/gdm-wayland-session %s\"@dbus@/bin/dbus-run-session --dbus-daemon=@dbus@/bin/dbus-daemon -- %s\"",
+                                                            register_session ? "--register-session " : "",
+                                                            self->selected_program);
+                         }
+                 } else {
+-                        program = g_strdup_printf ("dbus-run-session -- %s",
++                        program = g_strdup_printf ("@dbus@/bin/dbus-run-session --dbus-daemon=@dbus@/bin/dbus-daemon -- %s",
+                                                    self->selected_program);
+                 }
+         }
diff --git a/pkgs/desktops/gnome/core/gdm/gdm-session-worker_forward-vars.patch b/pkgs/desktops/gnome/core/gdm/gdm-session-worker_forward-vars.patch
new file mode 100644
index 00000000000..401b6aea0c2
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gdm/gdm-session-worker_forward-vars.patch
@@ -0,0 +1,31 @@
+diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
+index 9ef4c5b..94da834 100644
+--- a/daemon/gdm-session-worker.c
++++ b/daemon/gdm-session-worker.c
+@@ -1515,6 +1515,16 @@ gdm_session_worker_load_env_d (GdmSessionWorker *worker)
+         g_object_unref (dir);
+ }
+ 
++static void
++gdm_session_worker_forward_var (GdmSessionWorker *worker, char const *var)
++{
++        char const *value = g_getenv(var);
++        if (value != NULL) {
++                g_debug ("forwarding %s= %s", var, value);
++                gdm_session_worker_set_environment_variable(worker, var, value);
++        }
++}
++
+ static gboolean
+ gdm_session_worker_accredit_user (GdmSessionWorker  *worker,
+                                   GError           **error)
+@@ -1559,6 +1569,9 @@ gdm_session_worker_accredit_user (GdmSessionWorker  *worker,
+                 goto out;
+         }
+ 
++        gdm_session_worker_forward_var(worker, "GDM_X_SERVER_EXTRA_ARGS");
++        gdm_session_worker_forward_var(worker, "GDM_X_SESSION_WRAPPER");
++
+         gdm_session_worker_update_environment_from_passwd_info (worker,
+                                                                 uid,
+                                                                 gid,
diff --git a/pkgs/desktops/gnome/core/gdm/gdm-x-session_extra_args.patch b/pkgs/desktops/gnome/core/gdm/gdm-x-session_extra_args.patch
new file mode 100644
index 00000000000..66071aa4af8
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gdm/gdm-x-session_extra_args.patch
@@ -0,0 +1,38 @@
+diff --git a/daemon/gdm-x-session.c.orig b/daemon/gdm-x-session.c
+index d835b34..1f4b7f1 100644
+--- a/daemon/gdm-x-session.c.orig
++++ b/daemon/gdm-x-session.c
+@@ -211,6 +211,7 @@ spawn_x_server (State        *state,
+         char     *vt_string = NULL;
+         char     *display_number;
+         gsize     display_number_size;
++        gchar   **xserver_extra_args = NULL;
+ 
+         auth_file = prepare_auth_file ();
+ 
+@@ -285,6 +286,17 @@ spawn_x_server (State        *state,
+         if (state->debug_enabled) {
+                 g_ptr_array_add (arguments, "-core");
+         }
++
++        if (g_getenv ("GDM_X_SERVER_EXTRA_ARGS") != NULL) {
++                g_debug ("using GDM_X_SERVER_EXTRA_ARGS: %s", g_getenv("GDM_X_SERVER_EXTRA_ARGS"));
++                xserver_extra_args = g_strsplit(g_getenv("GDM_X_SERVER_EXTRA_ARGS"), " ", -1);
++                for (gchar **extra_arg = xserver_extra_args; *extra_arg; extra_arg++) {
++                        if (strlen(*extra_arg) < 1) continue;
++			g_debug ("adding: %s", *extra_arg);
++                        g_ptr_array_add (arguments, *extra_arg);
++                }
++        }
++
+         g_ptr_array_add (arguments, NULL);
+ 
+         subprocess = g_subprocess_launcher_spawnv (launcher,
+@@ -332,6 +344,7 @@ spawn_x_server (State        *state,
+ 
+         is_running = TRUE;
+ out:
++	g_strfreev(xserver_extra_args);
+         g_clear_pointer (&auth_file, g_free);
+         g_clear_object (&data_stream);
+         g_clear_object (&subprocess);
diff --git a/pkgs/desktops/gnome/core/gdm/gdm-x-session_session-wrapper.patch b/pkgs/desktops/gnome/core/gdm/gdm-x-session_session-wrapper.patch
new file mode 100644
index 00000000000..58481f0730f
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gdm/gdm-x-session_session-wrapper.patch
@@ -0,0 +1,40 @@
+diff --git a/daemon/gdm-x-session.c b/daemon/gdm-x-session.c
+index 88fe96f..b1b140a 100644
+--- a/daemon/gdm-x-session.c
++++ b/daemon/gdm-x-session.c
+@@ -664,18 +664,34 @@ spawn_session (State        *state,
+                                                           state->session_command,
+                                                           NULL);
+         } else {
++                char const *session_wrapper;
++                char *eff_session_command;
+                 int ret;
+                 char **argv;
+ 
+-                ret = g_shell_parse_argv (state->session_command,
++                session_wrapper = g_getenv("GDM_X_SESSION_WRAPPER");
++                if (session_wrapper != NULL) {
++                        char *quoted_wrapper = g_shell_quote(session_wrapper);
++                        eff_session_command = g_strjoin(" ", quoted_wrapper, state->session_command, NULL);
++                        g_free(quoted_wrapper);
++                } else {
++                        eff_session_command = state->session_command;
++                }
++
++                ret = g_shell_parse_argv (eff_session_command,
+                                           NULL,
+                                           &argv,
+                                           &error);
+ 
++                if (session_wrapper != NULL) {
++                        g_free(eff_session_command);
++                }
++
+                 if (!ret) {
+                         g_debug ("could not parse session arguments: %s", error->message);
+                         goto out;
+                 }
++
+                 subprocess = g_subprocess_launcher_spawnv (launcher,
+                                                            (const char * const *) argv,
+                                                            &error);
diff --git a/pkgs/desktops/gnome/core/gdm/org.gnome.login-screen.gschema.override b/pkgs/desktops/gnome/core/gdm/org.gnome.login-screen.gschema.override
new file mode 100644
index 00000000000..8c17f494b0f
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gdm/org.gnome.login-screen.gschema.override
@@ -0,0 +1,2 @@
+[org.gnome.login-screen]
+logo='@icon@'
diff --git a/pkgs/desktops/gnome/core/gdm/reset-environment.patch b/pkgs/desktops/gnome/core/gdm/reset-environment.patch
new file mode 100644
index 00000000000..61defd9c4bc
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gdm/reset-environment.patch
@@ -0,0 +1,20 @@
+--- a/daemon/gdm-wayland-session.c
++++ b/daemon/gdm-wayland-session.c
+@@ -285,6 +285,7 @@ spawn_session (State        *state,
+                                                     "WAYLAND_DISPLAY",
+                                                     "WAYLAND_SOCKET",
+                                                     "GNOME_SHELL_SESSION_MODE",
++                                                    "__NIXOS_SET_ENVIRONMENT_DONE",
+                                                     NULL };
+ 
+         g_debug ("Running wayland session");
+--- a/daemon/gdm-x-session.c
++++ b/daemon/gdm-x-session.c
+@@ -610,6 +610,7 @@ spawn_session (State        *state,
+                                                      "WAYLAND_DISPLAY",
+                                                      "WAYLAND_SOCKET",
+                                                      "GNOME_SHELL_SESSION_MODE",
++                                                     "__NIXOS_SET_ENVIRONMENT_DONE",
+                                                      NULL };
+ 
+         g_debug ("Running X session");
diff --git a/pkgs/desktops/gnome/core/gnome-backgrounds/default.nix b/pkgs/desktops/gnome/core/gnome-backgrounds/default.nix
new file mode 100644
index 00000000000..370cd14e467
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-backgrounds/default.nix
@@ -0,0 +1,22 @@
+{ lib, stdenv, fetchurl, meson, ninja, pkg-config, gnome, gettext }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-backgrounds";
+  version = "40.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-backgrounds/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "YN+KDaMBzkJbcEPUKuMuxAEf8I8Y4Pxi8pQBMF2jpw4=";
+  };
+
+  passthru = {
+    updateScript = gnome.updateScript { packageName = "gnome-backgrounds"; attrPath = "gnome.gnome-backgrounds"; };
+  };
+
+  nativeBuildInputs = [ meson ninja pkg-config gettext ];
+
+  meta = with lib; {
+    platforms = platforms.unix;
+    maintainers = teams.gnome.members;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gnome-bluetooth/default.nix b/pkgs/desktops/gnome/core/gnome-bluetooth/default.nix
new file mode 100644
index 00000000000..07b77c04994
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-bluetooth/default.nix
@@ -0,0 +1,86 @@
+{ lib
+, stdenv
+, fetchurl
+, gnome
+, meson
+, ninja
+, pkg-config
+, gtk3
+, gettext
+, glib
+, udev
+, itstool
+, libxml2
+, wrapGAppsHook
+, libnotify
+, libcanberra-gtk3
+, gobject-introspection
+, gtk-doc
+, docbook-xsl-nons
+, docbook_xml_dtd_43
+, python3
+, gsettings-desktop-schemas
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-bluetooth";
+  version = "3.34.5";
+
+  # TODO: split out "lib"
+  outputs = [ "out" "dev" "devdoc" "man" ];
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "1a9ynlwwkb3wpg293ym517vmrkk63y809mmcv9a21k5yr199x53c";
+  };
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    gettext
+    itstool
+    pkg-config
+    libxml2
+    wrapGAppsHook
+    gobject-introspection
+    gtk-doc
+    docbook-xsl-nons
+    docbook_xml_dtd_43
+    python3
+  ];
+
+  buildInputs = [
+    glib
+    gtk3
+    udev
+    libnotify
+    libcanberra-gtk3
+    gnome.adwaita-icon-theme
+    gsettings-desktop-schemas
+  ];
+
+  mesonFlags = [
+    "-Dicon_update=false"
+    "-Dgtk_doc=true"
+  ];
+
+  postPatch = ''
+    chmod +x meson_post_install.py # patchShebangs requires executable file
+    patchShebangs meson_post_install.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://help.gnome.org/users/gnome-bluetooth/stable/index.html.en";
+    description = "Application that let you manage Bluetooth in the GNOME destkop";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gnome-calculator/default.nix b/pkgs/desktops/gnome/core/gnome-calculator/default.nix
new file mode 100644
index 00000000000..7e19e9523ce
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-calculator/default.nix
@@ -0,0 +1,89 @@
+{ stdenv
+, lib
+, meson
+, ninja
+, vala
+, gettext
+, itstool
+, fetchurl
+, pkg-config
+, libxml2
+, gtk3
+, glib
+, gtksourceview4
+, wrapGAppsHook
+, gobject-introspection
+, python3
+, gnome
+, mpfr
+, gmp
+, libsoup
+, libmpc
+, libhandy
+, gsettings-desktop-schemas
+, libgee
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-calculator";
+  version = "40.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-calculator/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "1xkazxbkpn1z5pfphhps7fc5q4yc8lp7f6b222n8bx5iyxhwbrkz";
+  };
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    pkg-config
+    vala
+    gettext
+    itstool
+    wrapGAppsHook
+    python3
+    gobject-introspection # for finding vapi files
+  ];
+
+  buildInputs = [
+    gtk3
+    glib
+    libxml2
+    gtksourceview4
+    mpfr
+    gmp
+    gnome.adwaita-icon-theme
+    libgee
+    gsettings-desktop-schemas
+    libsoup
+    libmpc
+    libhandy
+  ];
+
+  doCheck = true;
+
+  postPatch = ''
+    chmod +x meson_post_install.py # patchShebangs requires executable file
+    patchShebangs meson_post_install.py
+  '';
+
+  preCheck = ''
+    # Currency conversion test tries to store currency data in $HOME/.cache.
+    export HOME=$TMPDIR
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "gnome-calculator";
+      attrPath = "gnome.gnome-calculator";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Calculator";
+    description = "Application that solves mathematical equations and is suitable as a default application in a Desktop environment";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl3Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gnome-color-manager/default.nix b/pkgs/desktops/gnome/core/gnome-color-manager/default.nix
new file mode 100644
index 00000000000..dae367f1d5b
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-color-manager/default.nix
@@ -0,0 +1,66 @@
+{ lib, stdenv
+, fetchurl
+, meson
+, ninja
+, pkg-config
+, gettext
+, itstool
+, desktop-file-utils
+, gnome
+, glib
+, gtk3
+, libexif
+, libtiff
+, colord
+, colord-gtk
+, libcanberra-gtk3
+, lcms2
+, vte
+, exiv2
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-color-manager";
+  version = "3.32.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "1vpxa2zjz3lkq9ldjg0fl65db9s6b4kcs8nyaqfz3jygma7ifg3w";
+  };
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    pkg-config
+    gettext
+    itstool
+    desktop-file-utils
+  ];
+
+  buildInputs = [
+    glib
+    gtk3
+    libexif
+    libtiff
+    colord
+    colord-gtk
+    libcanberra-gtk3
+    lcms2
+    vte
+    exiv2
+  ];
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    description = "A set of graphical utilities for color management to be used in the GNOME desktop";
+    license = licenses.gpl2Plus;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gnome-common/default.nix b/pkgs/desktops/gnome/core/gnome-common/default.nix
new file mode 100644
index 00000000000..cb50396a404
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-common/default.nix
@@ -0,0 +1,27 @@
+{ lib, stdenv, fetchurl, which, gnome, autoconf, automake }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-common";
+  version = "3.18.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-common/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "22569e370ae755e04527b76328befc4c73b62bfd4a572499fde116b8318af8cf";
+  };
+
+  passthru = {
+    updateScript = gnome.updateScript { packageName = "gnome-common"; attrPath = "gnome.gnome-common"; };
+  };
+
+  patches = [(fetchurl {
+    name = "gnome-common-patch";
+    url = "https://bug697543.bugzilla-attachments.gnome.org/attachment.cgi?id=240935";
+    sha256 = "17abp7czfzirjm7qsn2czd03hdv9kbyhk3lkjxg2xsf5fky7z7jl";
+  })];
+
+  propagatedBuildInputs = [ which autoconf automake ]; # autogen.sh which is using gnome-common tends to require which
+
+  meta = with lib; {
+    maintainers = teams.gnome.members;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gnome-contacts/default.nix b/pkgs/desktops/gnome/core/gnome-contacts/default.nix
new file mode 100644
index 00000000000..62a43d20d58
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-contacts/default.nix
@@ -0,0 +1,95 @@
+{ lib, stdenv
+, gettext
+, fetchurl
+, evolution-data-server
+, pkg-config
+, libxslt
+, docbook_xsl
+, docbook_xml_dtd_42
+, python3
+, gtk3
+, glib
+, cheese
+, libchamplain
+, clutter-gtk
+, geocode-glib
+, gnome-desktop
+, gnome-online-accounts
+, wrapGAppsHook
+, folks
+, libgdata
+, libxml2
+, gnome
+, vala
+, meson
+, ninja
+, libhandy
+, gsettings-desktop-schemas
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-contacts";
+  version = "40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-contacts/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "0w2g5xhw65adzvwzakrj5kaim4sw1w7s8qqwm3nm6inq50znzpn9";
+  };
+
+  propagatedUserEnvPkgs = [
+    evolution-data-server
+  ];
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    pkg-config
+    vala
+    gettext
+    libxslt
+    docbook_xsl
+    docbook_xml_dtd_42
+    python3
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    gtk3
+    glib
+    evolution-data-server
+    gsettings-desktop-schemas
+    folks
+    libgdata # required by some dependency transitively
+    gnome-desktop
+    libhandy
+    libxml2
+    gnome-online-accounts
+    cheese
+    gnome.adwaita-icon-theme
+    libchamplain
+    clutter-gtk
+    geocode-glib
+  ];
+
+  postPatch = ''
+    chmod +x build-aux/meson_post_install.py
+    patchShebangs build-aux/meson_post_install.py
+  '';
+
+  doCheck = true;
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "gnome-contacts";
+      attrPath = "gnome.gnome-contacts";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Contacts";
+    description = "GNOME’s integrated address book";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gnome-control-center/default.nix b/pkgs/desktops/gnome/core/gnome-control-center/default.nix
new file mode 100644
index 00000000000..6170f53c716
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-control-center/default.nix
@@ -0,0 +1,190 @@
+{ fetchurl
+, fetchpatch
+, lib
+, stdenv
+, substituteAll
+, accountsservice
+, adwaita-icon-theme
+, cheese
+, clutter
+, clutter-gtk
+, colord
+, colord-gtk
+, cups
+, docbook-xsl-nons
+, fontconfig
+, gdk-pixbuf
+, gettext
+, glib
+, glib-networking
+, glibc
+, gnome-bluetooth
+, gnome-color-manager
+, gnome-desktop
+, gnome-online-accounts
+, gnome-settings-daemon
+, gnome
+, grilo
+, grilo-plugins
+, gsettings-desktop-schemas
+, gsound
+, gtk3
+, ibus
+, libcanberra-gtk3
+, libgnomekbd
+, libgtop
+, libgudev
+, libhandy
+, libkrb5
+, libpulseaudio
+, libpwquality
+, librsvg
+, libsecret
+, libsoup
+, libwacom
+, libxml2
+, libxslt
+, meson
+, modemmanager
+, mutter
+, networkmanager
+, networkmanagerapplet
+, libnma
+, ninja
+, pkg-config
+, polkit
+, python3
+, samba
+, shared-mime-info
+, sound-theme-freedesktop
+, tracker
+, tracker-miners
+, tzdata
+, udisks2
+, upower
+, epoxy
+, gnome-user-share
+, gnome-remote-desktop
+, wrapGAppsHook
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-control-center";
+  version = "40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "sha256-zMmlc2UXOFEJrlpZkGwlgkTdh5t1A61ZhM9BZVyzAvE=";
+  };
+
+  patches = [
+    (substituteAll {
+      src = ./paths.patch;
+      gcm = gnome-color-manager;
+      gnome_desktop = gnome-desktop;
+      inherit glibc libgnomekbd tzdata;
+      inherit cups networkmanagerapplet;
+    })
+
+    # Fix startup assertion in power panel.
+    # https://gitlab.gnome.org/GNOME/gnome-control-center/merge_requests/974
+    (fetchpatch {
+      url = "https://gitlab.gnome.org/GNOME/gnome-control-center/commit/9acaa10567c94048657c69538e5d7813f82c4224.patch";
+      sha256 = "59GeTPcG2UiVTL4VTS/TP0p0QkAQpm3VgvuAiw64wUU=";
+    })
+  ];
+
+  nativeBuildInputs = [
+    docbook-xsl-nons
+    gettext
+    libxslt
+    meson
+    ninja
+    pkg-config
+    python3
+    shared-mime-info
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    accountsservice
+    adwaita-icon-theme
+    cheese
+    clutter
+    clutter-gtk
+    colord
+    colord-gtk
+    epoxy
+    fontconfig
+    gdk-pixbuf
+    glib
+    glib-networking
+    gnome-bluetooth
+    gnome-desktop
+    gnome-online-accounts
+    gnome-remote-desktop # optional, sharing panel
+    gnome-settings-daemon
+    gnome-user-share # optional, sharing panel
+    grilo
+    grilo-plugins # for setting wallpaper from Flickr
+    gsettings-desktop-schemas
+    gsound
+    gtk3
+    ibus
+    libcanberra-gtk3
+    libgtop
+    libgudev
+    libhandy
+    libkrb5
+    libnma
+    libpulseaudio
+    libpwquality
+    librsvg
+    libsecret
+    libsoup
+    libwacom
+    libxml2
+    modemmanager
+    mutter # schemas for the keybindings
+    networkmanager
+    polkit
+    samba
+    tracker
+    tracker-miners # for search locations dialog
+    udisks2
+    upower
+  ];
+
+  postPatch = ''
+    chmod +x build-aux/meson/meson_post_install.py # patchShebangs requires executable file
+    patchShebangs build-aux/meson/meson_post_install.py
+  '';
+
+  preFixup = ''
+    gappsWrapperArgs+=(
+      --prefix XDG_DATA_DIRS : "${sound-theme-freedesktop}/share"
+      # Thumbnailers (for setting user profile pictures)
+      --prefix XDG_DATA_DIRS : "${gdk-pixbuf}/share"
+      --prefix XDG_DATA_DIRS : "${librsvg}/share"
+      # WM keyboard shortcuts
+      --prefix XDG_DATA_DIRS : "${mutter}/share"
+    )
+    for i in $out/share/applications/*; do
+      substituteInPlace $i --replace "Exec=gnome-control-center" "Exec=$out/bin/gnome-control-center"
+    done
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    description = "Utilities to configure the GNOME desktop";
+    license = licenses.gpl2Plus;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gnome-control-center/paths.patch b/pkgs/desktops/gnome/core/gnome-control-center/paths.patch
new file mode 100644
index 00000000000..a6787477b81
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-control-center/paths.patch
@@ -0,0 +1,194 @@
+diff --git a/panels/color/cc-color-panel.c b/panels/color/cc-color-panel.c
+index 603178efc..c363a6a5c 100644
+--- a/panels/color/cc-color-panel.c
++++ b/panels/color/cc-color-panel.c
+@@ -591,7 +591,7 @@ gcm_prefs_calibrate_cb (CcColorPanel *prefs)
+ 
+   /* run with modal set */
+   argv = g_ptr_array_new_with_free_func (g_free);
+-  g_ptr_array_add (argv, g_strdup ("gcm-calibrate"));
++  g_ptr_array_add (argv, g_build_filename ("@gcm@", "bin", "gcm-calibrate", NULL));
+   g_ptr_array_add (argv, g_strdup ("--device"));
+   g_ptr_array_add (argv, g_strdup (cd_device_get_id (prefs->current_device)));
+   g_ptr_array_add (argv, g_strdup ("--parent-window"));
+@@ -1029,7 +1029,7 @@ gcm_prefs_profile_view (CcColorPanel *prefs, CdProfile *profile)
+ 
+   /* open up gcm-viewer as a info pane */
+   argv = g_ptr_array_new_with_free_func (g_free);
+-  g_ptr_array_add (argv, g_strdup ("gcm-viewer"));
++  g_ptr_array_add (argv, g_build_filename ("@gcm@", "bin", "gcm-viewer", NULL));
+   g_ptr_array_add (argv, g_strdup ("--profile"));
+   g_ptr_array_add (argv, g_strdup (cd_profile_get_id (profile)));
+   g_ptr_array_add (argv, g_strdup ("--parent-window"));
+@@ -1275,15 +1275,12 @@ gcm_prefs_device_clicked (CcColorPanel *prefs, CdDevice *device)
+ static void
+ gcm_prefs_profile_clicked (CcColorPanel *prefs, CdProfile *profile, CdDevice *device)
+ {
+-  g_autofree gchar *s = NULL;
+-
+   /* get profile */
+   g_debug ("selected profile = %s",
+      cd_profile_get_filename (profile));
+ 
+   /* allow getting profile info */
+-  if (cd_profile_get_filename (profile) != NULL &&
+-      (s = g_find_program_in_path ("gcm-viewer")) != NULL)
++  if (cd_profile_get_filename (profile) != NULL)
+     gtk_widget_set_sensitive (prefs->toolbutton_profile_view, TRUE);
+   else
+     gtk_widget_set_sensitive (prefs->toolbutton_profile_view, FALSE);
+diff --git a/panels/datetime/tz.h b/panels/datetime/tz.h
+index a2376f8a4..98769e08f 100644
+--- a/panels/datetime/tz.h
++++ b/panels/datetime/tz.h
+@@ -27,11 +27,7 @@
+ 
+ G_BEGIN_DECLS
+ 
+-#ifndef __sun
+-#  define TZ_DATA_FILE "/usr/share/zoneinfo/zone.tab"
+-#else
+-#  define TZ_DATA_FILE "/usr/share/lib/zoneinfo/tab/zone_sun.tab"
+-#endif
++#define TZ_DATA_FILE "@tzdata@/share/zoneinfo/zone.tab"
+ 
+ typedef struct _TzDB TzDB;
+ typedef struct _TzLocation TzLocation;
+diff --git a/panels/info-overview/cc-info-overview-panel.c b/panels/info-overview/cc-info-overview-panel.c
+index bd0e07762..0e71351f8 100644
+--- a/panels/info-overview/cc-info-overview-panel.c
++++ b/panels/info-overview/cc-info-overview-panel.c
+@@ -172,7 +172,7 @@ load_gnome_version (char **version,
+   gsize length;
+   g_autoptr(VersionData) data = NULL;
+ 
+-  if (!g_file_get_contents (DATADIR "/gnome/gnome-version.xml",
++  if (!g_file_get_contents ("@gnome_desktop@/share/gnome/gnome-version.xml",
+                             &contents,
+                             &length,
+                             &error))
+diff --git a/panels/keyboard/cc-input-list-box.c b/panels/keyboard/cc-input-list-box.c
+index 6c2cb5614..8f57159cc 100644
+--- a/panels/keyboard/cc-input-list-box.c
++++ b/panels/keyboard/cc-input-list-box.c
+@@ -223,10 +223,10 @@ row_layout_cb (CcInputListBox *self,
+   layout_variant = cc_input_source_get_layout_variant (source);
+ 
+   if (layout_variant && layout_variant[0])
+-    commandline = g_strdup_printf ("gkbd-keyboard-display -l \"%s\t%s\"",
++    commandline = g_strdup_printf ("@libgnomekbd@/bin/gkbd-keyboard-display -l \"%s\t%s\"",
+ 				   layout, layout_variant);
+   else
+-    commandline = g_strdup_printf ("gkbd-keyboard-display -l %s",
++    commandline = g_strdup_printf ("@libgnomekbd@/bin/gkbd-keyboard-display -l %s",
+ 				   layout);
+ 
+   g_spawn_command_line_async (commandline, NULL);
+diff --git a/panels/network/connection-editor/net-connection-editor.c b/panels/network/connection-editor/net-connection-editor.c
+index 505b8ee25..62e94009f 100644
+--- a/panels/network/connection-editor/net-connection-editor.c
++++ b/panels/network/connection-editor/net-connection-editor.c
+@@ -267,9 +267,9 @@ net_connection_editor_do_fallback (NetConnectionEditor *self, const gchar *type)
+         g_autoptr(GError) error = NULL;
+ 
+         if (self->is_new_connection) {
+-                cmdline = g_strdup_printf ("nm-connection-editor --type='%s' --create", type);
++                cmdline = g_strdup_printf ("@networkmanagerapplet@/bin/nm-connection-editor --type='%s' --create", type);
+         } else {
+-                cmdline = g_strdup_printf ("nm-connection-editor --edit='%s'",
++                cmdline = g_strdup_printf ("@networkmanagerapplet@/bin/nm-connection-editor --edit='%s'",
+                                            nm_connection_get_uuid (self->connection));
+         }
+ 
+diff --git a/panels/network/net-device-bluetooth.c b/panels/network/net-device-bluetooth.c
+index 74dfb0e9a..5f53d1a20 100644
+--- a/panels/network/net-device-bluetooth.c
++++ b/panels/network/net-device-bluetooth.c
+@@ -90,7 +90,7 @@ nm_device_bluetooth_refresh_ui (NetDeviceBluetooth *self)
+         update_off_switch_from_device_state (self->device_off_switch, state, self);
+ 
+         /* set up the Options button */
+-        path = g_find_program_in_path ("nm-connection-editor");
++        path = g_find_program_in_path ("@networkmanagerapplet@/bin/nm-connection-editor");
+         gtk_widget_set_visible (GTK_WIDGET (self->options_button), state != NM_DEVICE_STATE_UNMANAGED && path != NULL);
+ }
+ 
+@@ -141,7 +141,7 @@ options_button_clicked_cb (NetDeviceBluetooth *self)
+ 
+         connection = net_device_get_find_connection (self->client, self->device);
+         uuid = nm_connection_get_uuid (connection);
+-        cmdline = g_strdup_printf ("nm-connection-editor --edit %s", uuid);
++        cmdline = g_strdup_printf ("@networkmanagerapplet@/bin/nm-connection-editor --edit %s", uuid);
+         g_debug ("Launching '%s'\n", cmdline);
+         if (!g_spawn_command_line_async (cmdline, &error))
+                 g_warning ("Failed to launch nm-connection-editor: %s", error->message);
+@@ -185,7 +185,7 @@ net_device_bluetooth_init (NetDeviceBluetooth *self)
+ 
+         gtk_widget_init_template (GTK_WIDGET (self));
+ 
+-        path = g_find_program_in_path ("nm-connection-editor");
++        path = g_find_program_in_path ("@networkmanagerapplet@/bin/nm-connection-editor");
+         gtk_widget_set_visible (GTK_WIDGET (self->options_button), path != NULL);
+ }
+ 
+diff --git a/panels/network/net-device-mobile.c b/panels/network/net-device-mobile.c
+index 34eb86241..50d0a2bed 100644
+--- a/panels/network/net-device-mobile.c
++++ b/panels/network/net-device-mobile.c
+@@ -508,7 +508,7 @@ options_button_clicked_cb (NetDeviceMobile *self)
+ 
+         connection = net_device_get_find_connection (self->client, self->device);
+         uuid = nm_connection_get_uuid (connection);
+-        cmdline = g_strdup_printf ("nm-connection-editor --edit %s", uuid);
++        cmdline = g_strdup_printf ("@networkmanagerapplet@/bin/nm-connection-editor --edit %s", uuid);
+         g_debug ("Launching '%s'\n", cmdline);
+         if (!g_spawn_command_line_async (cmdline, &error))
+                 g_warning ("Failed to launch nm-connection-editor: %s", error->message);
+@@ -797,7 +797,7 @@ net_device_mobile_init (NetDeviceMobile *self)
+ 
+         self->cancellable = g_cancellable_new ();
+ 
+-        path = g_find_program_in_path ("nm-connection-editor");
++        path = g_find_program_in_path ("@networkmanagerapplet@/bin/nm-connection-editor");
+         gtk_widget_set_visible (GTK_WIDGET (self->options_button), path != NULL);
+ }
+ 
+diff --git a/panels/printers/pp-host.c b/panels/printers/pp-host.c
+index a31a606e3..ed5133d29 100644
+--- a/panels/printers/pp-host.c
++++ b/panels/printers/pp-host.c
+@@ -256,7 +256,7 @@ _pp_host_get_snmp_devices_thread (GTask        *task,
+   devices = g_ptr_array_new_with_free_func (g_object_unref);
+ 
+   argv = g_new0 (gchar *, 3);
+-  argv[0] = g_strdup ("/usr/lib/cups/backend/snmp");
++  argv[0] = g_strdup ("@cups@/lib/cups/backend/snmp");
+   argv[1] = g_strdup (priv->hostname);
+ 
+   /* Use SNMP to get printer's informations */
+diff --git a/panels/user-accounts/run-passwd.c b/panels/user-accounts/run-passwd.c
+index 86f53d4fc..0b052856f 100644
+--- a/panels/user-accounts/run-passwd.c
++++ b/panels/user-accounts/run-passwd.c
+@@ -150,7 +150,7 @@ spawn_passwd (PasswdHandler *passwd_handler, GError **error)
+         gchar  **envp;
+         gint    my_stdin, my_stdout, my_stderr;
+ 
+-        argv[0] = "/usr/bin/passwd";    /* Is it safe to rely on a hard-coded path? */
++        argv[0] = "/run/wrappers/bin/passwd";    /* Is it safe to rely on a hard-coded path? */
+         argv[1] = NULL;
+ 
+         envp = g_get_environ ();
+diff --git a/tests/datetime/test-endianess.c b/tests/datetime/test-endianess.c
+index 9cb92007a..84d2f0fa3 100644
+--- a/tests/datetime/test-endianess.c
++++ b/tests/datetime/test-endianess.c
+@@ -26,7 +26,7 @@ test_endianess (void)
+ 	g_autoptr(GDir) dir = NULL;
+ 	const char *name;
+ 
+-	dir = g_dir_open ("/usr/share/i18n/locales/", 0, NULL);
++	dir = g_dir_open ("@glibc@/share/i18n/locales/", 0, NULL);
+ 	if (dir == NULL) {
+ 		/* Try with /usr/share/locale/
+ 		 * https://bugzilla.gnome.org/show_bug.cgi?id=646780 */
diff --git a/pkgs/desktops/gnome/core/gnome-desktop/bubblewrap-paths.patch b/pkgs/desktops/gnome/core/gnome-desktop/bubblewrap-paths.patch
new file mode 100644
index 00000000000..57eb4b3d44a
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-desktop/bubblewrap-paths.patch
@@ -0,0 +1,15 @@
+--- a/libgnome-desktop/gnome-desktop-thumbnail-script.c
++++ b/libgnome-desktop/gnome-desktop-thumbnail-script.c
+@@ -536,9 +536,9 @@ add_bwrap (GPtrArray   *array,
+   g_return_val_if_fail (script->s_infile != NULL, FALSE);
+ 
+   add_args (array,
+-	    "bwrap",
+-	    "--ro-bind", "/usr", "/usr",
+-	    "--ro-bind", "/etc/ld.so.cache", "/etc/ld.so.cache",
++	    "@bubblewrap_bin@",
++	    "--ro-bind", "@storeDir@", "@storeDir@",
++	    "--ro-bind", "/run/current-system", "/run/current-system",
+ 	    NULL);
+ 
+   /* These directories might be symlinks into /usr/... */
diff --git a/pkgs/desktops/gnome/core/gnome-desktop/default.nix b/pkgs/desktops/gnome/core/gnome-desktop/default.nix
new file mode 100644
index 00000000000..56bd074c2cb
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-desktop/default.nix
@@ -0,0 +1,96 @@
+{ lib
+, stdenv
+, fetchurl
+, substituteAll
+, pkg-config
+, libxslt
+, ninja
+, gnome
+, gtk3
+, glib
+, gettext
+, libxml2
+, xkeyboard_config
+, libxkbcommon
+, isocodes
+, meson
+, wayland
+, libseccomp
+, systemd
+, bubblewrap
+, gobject-introspection
+, gtk-doc
+, docbook-xsl-nons
+, gsettings-desktop-schemas
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-desktop";
+  version = "40.1";
+
+  outputs = [ "out" "dev" "devdoc" ];
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-desktop/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "sha256-igeJcwUhnFaZVJriBI9xVVFe+Xx85NZYXd2hXVhZ4c8=";
+  };
+
+  patches = [
+    (substituteAll {
+      src = ./bubblewrap-paths.patch;
+      bubblewrap_bin = "${bubblewrap}/bin/bwrap";
+      inherit (builtins) storeDir;
+    })
+  ];
+
+  nativeBuildInputs = [
+    pkg-config
+    meson
+    ninja
+    gettext
+    libxslt
+    libxml2
+    gobject-introspection
+    gtk-doc
+    docbook-xsl-nons
+    glib
+  ];
+
+  buildInputs = [
+    bubblewrap
+    xkeyboard_config
+    libxkbcommon # for xkbregistry
+    isocodes
+    wayland
+    gtk3
+    glib
+    libseccomp
+    systemd
+  ];
+
+  propagatedBuildInputs = [
+    gsettings-desktop-schemas
+  ];
+
+  mesonFlags = [
+    "-Dgtk_doc=true"
+    "-Ddesktop_docs=false"
+  ];
+
+  separateDebugInfo = stdenv.isLinux;
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "gnome-desktop";
+      attrPath = "gnome.gnome-desktop";
+    };
+  };
+
+  meta = with lib; {
+    description = "Library with common API for various GNOME modules";
+    homepage = "https://gitlab.gnome.org/GNOME/gnome-desktop";
+    license = with licenses; [ gpl2Plus lgpl2Plus ];
+    platforms = platforms.linux;
+    maintainers = teams.gnome.members;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gnome-dictionary/default.nix b/pkgs/desktops/gnome/core/gnome-dictionary/default.nix
new file mode 100644
index 00000000000..a399c4e8537
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-dictionary/default.nix
@@ -0,0 +1,36 @@
+{ lib, stdenv, fetchurl, meson, ninja, pkg-config, desktop-file-utils, appstream-glib, libxslt
+, libxml2, gettext, itstool, wrapGAppsHook, docbook_xsl, docbook_xml_dtd_43
+, gnome, gtk3, glib, gsettings-desktop-schemas }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-dictionary";
+  version = "40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-dictionary/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "1d8dhcfys788vv27v34i3s3x3jdvdi2kqn2a5p8c937a9hm0qr9f";
+  };
+
+  doCheck = true;
+
+  nativeBuildInputs = [
+    meson ninja pkg-config wrapGAppsHook libxml2 gettext itstool
+    desktop-file-utils appstream-glib libxslt docbook_xsl docbook_xml_dtd_43
+  ];
+  buildInputs = [ gtk3 glib gsettings-desktop-schemas gnome.adwaita-icon-theme ];
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "gnome-dictionary";
+      attrPath = "gnome.gnome-dictionary";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Dictionary";
+    description = "Dictionary is the GNOME application to look up definitions";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gnome-disk-utility/default.nix b/pkgs/desktops/gnome/core/gnome-disk-utility/default.nix
new file mode 100644
index 00000000000..c11a1df883a
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-disk-utility/default.nix
@@ -0,0 +1,85 @@
+{ lib
+, stdenv
+, gettext
+, fetchurl
+, pkg-config
+, udisks2
+, libhandy
+, libsecret
+, libdvdread
+, meson
+, ninja
+, gtk3
+, glib
+, wrapGAppsHook
+, python3
+, libnotify
+, itstool
+, gnome
+, libxml2
+, gsettings-desktop-schemas
+, libcanberra-gtk3
+, libxslt
+, docbook-xsl-nons
+, libpwquality
+, systemd
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-disk-utility";
+  version = "40.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-disk-utility/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "sha256-KkuZrBHKIzlLKMVYS56WKE6MWk2mXPBiB95U9Csf8UE=";
+  };
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    pkg-config
+    gettext
+    itstool
+    libxslt
+    docbook-xsl-nons
+    wrapGAppsHook
+    python3
+    libxml2
+  ];
+
+  buildInputs = [
+    gtk3
+    glib
+    libhandy
+    libsecret
+    libpwquality
+    libnotify
+    libdvdread
+    libcanberra-gtk3
+    udisks2
+    gnome.adwaita-icon-theme
+    systemd
+    gnome.gnome-settings-daemon
+    gsettings-desktop-schemas
+  ];
+
+  postPatch = ''
+    chmod +x meson_post_install.py # patchShebangs requires executable file
+    patchShebangs meson_post_install.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "gnome-disk-utility";
+      attrPath = "gnome.gnome-disk-utility";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Disks";
+    description = "A udisks graphical front-end";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gnome-font-viewer/default.nix b/pkgs/desktops/gnome/core/gnome-font-viewer/default.nix
new file mode 100644
index 00000000000..622a7de1bff
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-font-viewer/default.nix
@@ -0,0 +1,35 @@
+{ lib, stdenv, meson, ninja, gettext, fetchurl
+, pkg-config, gtk3, glib, libxml2, gnome-desktop, adwaita-icon-theme, libhandy
+, wrapGAppsHook, gnome, harfbuzz }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-font-viewer";
+  version = "40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-font-viewer/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "0hpyi0sz3gcqqs9lkwyk8b6hr39m3n27432x98kxr436jj37dk6j";
+  };
+
+  doCheck = true;
+
+  nativeBuildInputs = [ meson ninja pkg-config gettext wrapGAppsHook libxml2 ];
+  buildInputs = [ gtk3 glib gnome-desktop adwaita-icon-theme harfbuzz libhandy ];
+
+  # Do not run meson-postinstall.sh
+  preConfigure = "sed -i '2,$ d'  meson-postinstall.sh";
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "gnome-font-viewer";
+      attrPath = "gnome.gnome-font-viewer";
+    };
+  };
+
+  meta = with lib; {
+    description = "Program that can preview fonts and create thumbnails for fonts";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gnome-initial-setup/0001-fix-paths.patch b/pkgs/desktops/gnome/core/gnome-initial-setup/0001-fix-paths.patch
new file mode 100644
index 00000000000..23237595225
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-initial-setup/0001-fix-paths.patch
@@ -0,0 +1,62 @@
+From 1ae0eca39ba6af27f37e2fe81395b91a2761a408 Mon Sep 17 00:00:00 2001
+Message-Id: <1ae0eca39ba6af27f37e2fe81395b91a2761a408.1600627676.git-series.worldofpeace@protonmail.ch>
+From: WORLDofPEACE <worldofpeace@protonmail.ch>
+Date: Sun, 20 Sep 2020 14:46:59 -0400
+Subject: [PATCH] fix paths
+
+---
+ gnome-initial-setup/pages/keyboard/cc-input-chooser.c | 6 +++---
+ gnome-initial-setup/pages/timezone/tz.h               | 4 ++--
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/gnome-initial-setup/pages/keyboard/cc-input-chooser.c b/gnome-initial-setup/pages/keyboard/cc-input-chooser.c
+index 196abf6..613d0e5 100644
+--- a/gnome-initial-setup/pages/keyboard/cc-input-chooser.c
++++ b/gnome-initial-setup/pages/keyboard/cc-input-chooser.c
+@@ -177,9 +177,9 @@ preview_cb (GtkLabel       *label,
+ 		return TRUE;
+ 
+ 	if (variant[0])
+-		commandline = g_strdup_printf ("gkbd-keyboard-display -l \"%s\t%s\"", layout, variant);
++		commandline = g_strdup_printf ("@libgnomekbd@/bin/gkbd-keyboard-display -l \"%s\t%s\"", layout, variant);
+ 	else
+-		commandline = g_strdup_printf ("gkbd-keyboard-display -l %s", layout);
++		commandline = g_strdup_printf ("@libgnomekbd@/bin/gkbd-keyboard-display -l %s", layout);
+ 	g_spawn_command_line_async (commandline, NULL);
+ 	g_free (commandline);
+ 
+@@ -831,7 +831,7 @@ cc_input_chooser_class_init (CcInputChooserClass *klass)
+                 g_param_spec_string ("showing-extra", "", "", "",
+                                      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ 
+-	signals[CHANGED] = 
++	signals[CHANGED] =
+ 		g_signal_new ("changed",
+ 			      G_TYPE_FROM_CLASS (object_class),
+ 			      G_SIGNAL_RUN_FIRST,
+diff --git a/gnome-initial-setup/pages/timezone/tz.h b/gnome-initial-setup/pages/timezone/tz.h
+index a2376f8..5cb7bc9 100644
+--- a/gnome-initial-setup/pages/timezone/tz.h
++++ b/gnome-initial-setup/pages/timezone/tz.h
+@@ -4,7 +4,7 @@
+  * Copyright (C) 2000-2001 Ximian, Inc.
+  *
+  * Authors: Hans Petter Jansson <hpj@ximian.com>
+- * 
++ *
+  * Largely based on Michael Fulbright's work on Anaconda.
+  *
+  * This program is free software; you can redistribute it and/or modify
+@@ -28,7 +28,7 @@
+ G_BEGIN_DECLS
+ 
+ #ifndef __sun
+-#  define TZ_DATA_FILE "/usr/share/zoneinfo/zone.tab"
++#  define TZ_DATA_FILE "@tzdata@/share/zoneinfo/zone.tab"
+ #else
+ #  define TZ_DATA_FILE "/usr/share/lib/zoneinfo/tab/zone_sun.tab"
+ #endif
+
+base-commit: 5132e206a6bf81964450561d68473ac015760455
+-- 
+git-series 0.9.1
diff --git a/pkgs/desktops/gnome/core/gnome-initial-setup/default.nix b/pkgs/desktops/gnome/core/gnome-initial-setup/default.nix
new file mode 100644
index 00000000000..6d57e29a596
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-initial-setup/default.nix
@@ -0,0 +1,106 @@
+{ lib, stdenv
+, fetchurl
+, substituteAll
+, gettext
+, meson
+, ninja
+, pkg-config
+, wrapGAppsHook
+, gnome
+, accountsservice
+, fontconfig
+, gdm
+, geoclue2
+, geocode-glib
+, glib
+, gnome-desktop
+, gnome-online-accounts
+, gtk3
+, libgweather
+, json-glib
+, krb5
+, libpwquality
+, librest
+, libsecret
+, networkmanager
+, pango
+, polkit
+, webkitgtk
+, systemd
+, libnma
+, tzdata
+, libgnomekbd
+, gsettings-desktop-schemas
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-initial-setup";
+  version = "40.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "10zf87n6c947k9rkk2rqc9cbfwcvq23axq3rf7x1an7npv3414gi";
+  };
+
+  patches = [
+    (substituteAll {
+      src = ./0001-fix-paths.patch;
+      inherit tzdata libgnomekbd;
+    })
+  ];
+
+  nativeBuildInputs = [
+    gettext
+    meson
+    ninja
+    pkg-config
+    systemd
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    accountsservice
+    fontconfig
+    gdm
+    geoclue2
+    geocode-glib
+    glib
+    gnome-desktop
+    gnome-online-accounts
+    gsettings-desktop-schemas
+    gtk3
+    json-glib
+    krb5
+    libgweather
+    libnma
+    libpwquality
+    librest
+    libsecret
+    networkmanager
+    pango
+    polkit
+    webkitgtk
+  ];
+
+  mesonFlags = [
+    "-Dcheese=disabled"
+    "-Dibus=disabled"
+    "-Dparental_controls=disabled"
+    "-Dvendor-conf-file=${./vendor.conf}"
+  ];
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    description = "Simple, easy, and safe way to prepare a new system";
+    homepage = "https://gitlab.gnome.org/GNOME/gnome-initial-setup";
+    license = licenses.gpl2Plus;
+    platforms = platforms.linux;
+    maintainers = teams.gnome.members;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gnome-initial-setup/vendor.conf b/pkgs/desktops/gnome/core/gnome-initial-setup/vendor.conf
new file mode 100644
index 00000000000..a06b37e100e
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-initial-setup/vendor.conf
@@ -0,0 +1,5 @@
+# Disable pages not right for NixOS
+# For example user accounts should be preconfigured
+# and we can't modify system time with systemd.
+[pages]
+skip=account;software;password;timezone;
diff --git a/pkgs/desktops/gnome/core/gnome-keyring/default.nix b/pkgs/desktops/gnome/core/gnome-keyring/default.nix
new file mode 100644
index 00000000000..8c9815509e2
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-keyring/default.nix
@@ -0,0 +1,102 @@
+{ lib
+, stdenv
+, fetchurl
+, pkg-config
+, dbus
+, libgcrypt
+, pam
+, python2
+, glib
+, libxslt
+, gettext
+, gcr
+, libcap_ng
+, libselinux
+, p11-kit
+, openssh
+, wrapGAppsHook
+, docbook-xsl-nons
+, docbook_xml_dtd_43
+, gnome
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-keyring";
+  version = "40.0";
+
+  outputs = [ "out" "dev" ];
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-keyring/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "0cdrlcw814zayhvlaxqs1sm9bqlfijlp22dzzd0g5zg2isq4vlm3";
+  };
+
+  nativeBuildInputs = [
+    pkg-config
+    gettext
+    libxslt
+    docbook-xsl-nons
+    docbook_xml_dtd_43
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    glib
+    libgcrypt
+    pam
+    openssh
+    libcap_ng
+    libselinux
+    gcr
+    p11-kit
+  ];
+
+  # In 3.20.1, tests do not support Python 3
+  checkInputs = [ dbus python2 ];
+
+  configureFlags = [
+    "--with-pkcs11-config=${placeholder "out"}/etc/pkcs11/" # installation directories
+    "--with-pkcs11-modules=${placeholder "out"}/lib/pkcs11/"
+  ];
+
+  # Tends to fail non-deterministically.
+  # - https://github.com/NixOS/nixpkgs/issues/55293
+  # - https://github.com/NixOS/nixpkgs/issues/51121
+  doCheck = false;
+
+  postPatch = ''
+    patchShebangs build
+  '';
+
+  checkPhase = ''
+    export HOME=$(mktemp -d)
+    dbus-run-session \
+      --config-file=${dbus.daemon}/share/dbus-1/session.conf \
+      make check
+  '';
+
+  # Use wrapped gnome-keyring-daemon with cap_ipc_lock=ep
+  postFixup = ''
+    files=($out/etc/xdg/autostart/* $out/share/dbus-1/services/*)
+
+    for file in ''${files[*]}; do
+      substituteInPlace $file \
+        --replace "$out/bin/gnome-keyring-daemon" "/run/wrappers/bin/gnome-keyring-daemon"
+    done
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "gnome-keyring";
+      attrPath = "gnome.gnome-keyring";
+    };
+  };
+
+  meta = with lib; {
+    description = "Collection of components in GNOME that store secrets, passwords, keys, certificates and make them available to applications";
+    homepage = "https://wiki.gnome.org/Projects/GnomeKeyring";
+    license = licenses.gpl2;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gnome-online-miners/default.nix b/pkgs/desktops/gnome/core/gnome-online-miners/default.nix
new file mode 100644
index 00000000000..95fdf35b883
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-online-miners/default.nix
@@ -0,0 +1,116 @@
+{ lib, stdenv
+, fetchurl
+, fetchpatch
+, autoconf-archive
+, autoreconfHook
+, pkg-config
+, glib
+, gnome
+, libxml2
+, libgdata
+, grilo
+, libzapojit
+, grilo-plugins
+, gnome-online-accounts
+, libmediaart
+, tracker
+, gfbgraph
+, librest
+, libsoup
+, json-glib
+, gmp
+, openssl
+, dleyna-server
+, wrapGAppsHook
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-online-miners";
+  version = "3.34.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-online-miners/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "1n2jz9i8a42zwxx5h8j2gdy6q1vyydh4vl00r0al7w8jzdh24p44";
+  };
+
+  patches = [
+    # Fix use after free
+    # https://gitlab.gnome.org/GNOME/gnome-online-miners/merge_requests/4
+    (fetchpatch {
+      url = "https://gitlab.gnome.org/GNOME/gnome-online-miners/commit/9eb57c6a8cd1a925c508646edae936eee0a8e46b.patch";
+      sha256 = "O1GRnzs33I0mFzrNDFkTGiBKstq5krYg7fwj60367TA=";
+    })
+
+    # Port to Tracker 3
+    # https://gitlab.gnome.org/GNOME/gnome-online-miners/merge_requests/3
+    (fetchpatch {
+      url = "https://gitlab.gnome.org/GNOME/gnome-online-miners/commit/2d3798252807cad9eb061ed2b37e35170c1a1daf.patch";
+      sha256 = "hwrkxroMpTfOwJAPkYQFdDCroZ2qSsvOgDetrJDig20=";
+    })
+    (fetchpatch {
+      url = "https://gitlab.gnome.org/GNOME/gnome-online-miners/commit/1548c0c527f0e4389047448d7d3b6cff55278c8e.patch";
+      sha256 = "U9w81c9Kze7kv5KHeGqvDeSNHzSayVrUG0XYsYMa1sg=";
+    })
+    (fetchpatch {
+      url = "https://gitlab.gnome.org/GNOME/gnome-online-miners/commit/941ebd8890c9ac4f75a1f58ccbea9731f46ad912.patch";
+      sha256 = "JHtDlZ54/BlSiUA3ROHfCTtTKSin3g6JNm8NS6pYML8=";
+    })
+    (fetchpatch {
+      url = "https://gitlab.gnome.org/GNOME/gnome-online-miners/commit/d1681a64bc3f65894af2549e3ba2bffbaf6f539a.patch";
+      sha256 = "9ZEatz5I81UAnjS1qCGWYDQQOxg/qp9Tg3xG/a+3goc=";
+    })
+    (fetchpatch {
+      url = "https://gitlab.gnome.org/GNOME/gnome-online-miners/commit/3d2af8785c84d6e50d8a8e6a2569a4b709184e94.patch";
+      sha256 = "7bdUE2k6g3Z8sdGYEb6pUm1/wbKDe4BHbylXUzfuTG0=";
+    })
+  ];
+
+  nativeBuildInputs = [
+    # patch changes configure.ac
+    autoconf-archive
+    autoreconfHook
+
+    pkg-config
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    glib
+    libgdata
+    libxml2
+    libsoup
+    gmp
+    openssl
+    grilo
+    libzapojit
+    grilo-plugins
+    gnome-online-accounts
+    libmediaart
+    tracker
+    gfbgraph
+    json-glib
+    librest
+    dleyna-server
+  ];
+
+  NIX_CFLAGS_COMPILE = [
+    "-Wno-error=format-security" # https://gitlab.gnome.org/GNOME/gnome-online-miners/merge_requests/3/diffs#note_942747
+  ];
+
+  enableParallelBuilding = true;
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "gnome-online-miners";
+      attrPath = "gnome.gnome-online-miners";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Projects/GnomeOnlineMiners";
+    description = "A set of crawlers that go through your online content and index them locally in Tracker";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gnome-remote-desktop/default.nix b/pkgs/desktops/gnome/core/gnome-remote-desktop/default.nix
new file mode 100644
index 00000000000..8411b2edecb
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-remote-desktop/default.nix
@@ -0,0 +1,64 @@
+{ lib, stdenv
+, fetchurl
+, cairo
+, meson
+, ninja
+, pkg-config
+, python3
+, wrapGAppsHook
+, glib
+, pipewire
+, systemd
+, libvncserver
+, libsecret
+, libnotify
+, gdk-pixbuf
+, freerdp
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-remote-desktop";
+  version = "0.1.9";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    hash = "sha256-8iZtp4tBRT7NNRKuzwop3rcMvq16RG/I2sAlEIsJ0M8=";
+  };
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    pkg-config
+    python3
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    cairo
+    freerdp
+    gdk-pixbuf # For libnotify
+    glib
+    libnotify
+    libsecret
+    libvncserver
+    pipewire
+    systemd
+  ];
+
+  postPatch = ''
+    chmod +x meson_post_install.py # patchShebangs requires executable file
+    patchShebangs meson_post_install.py
+  '';
+
+  mesonFlags = [
+    "-Dsystemd_user_unit_dir=${placeholder "out"}/lib/systemd/user"
+  ];
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Projects/Mutter/RemoteDesktop";
+    description = "GNOME Remote Desktop server";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gnome-screenshot/default.nix b/pkgs/desktops/gnome/core/gnome-screenshot/default.nix
new file mode 100644
index 00000000000..5b02fda3e32
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-screenshot/default.nix
@@ -0,0 +1,43 @@
+{ lib, stdenv, gettext, libxml2, libhandy, fetchurl, pkg-config, libcanberra-gtk3
+, gtk3, glib, meson, ninja, python3, wrapGAppsHook, appstream-glib, desktop-file-utils
+, gnome, gsettings-desktop-schemas }:
+
+let
+  pname = "gnome-screenshot";
+  version = "40.0";
+in stdenv.mkDerivation rec {
+  name = "${pname}-${version}";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.major version}/${name}.tar.xz";
+    sha256 = "1qm544ymwibk31s30k47vnn79xg30m18r7l4di0c57g375dak31n";
+  };
+
+  doCheck = true;
+
+  postPatch = ''
+    chmod +x build-aux/postinstall.py # patchShebangs requires executable file
+    patchShebangs build-aux/postinstall.py
+  '';
+
+  nativeBuildInputs = [ meson ninja pkg-config gettext appstream-glib libxml2 desktop-file-utils python3 wrapGAppsHook ];
+  buildInputs = [
+    gtk3 glib libcanberra-gtk3 libhandy gnome.adwaita-icon-theme
+    gsettings-desktop-schemas
+  ];
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://en.wikipedia.org/wiki/GNOME_Screenshot";
+    description = "Utility used in the GNOME desktop environment for taking screenshots";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gnome-session/ctl.nix b/pkgs/desktops/gnome/core/gnome-session/ctl.nix
new file mode 100644
index 00000000000..6a274e35bf5
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-session/ctl.nix
@@ -0,0 +1,42 @@
+{ lib
+, stdenv
+, fetchFromGitHub
+, meson
+, ninja
+, pkg-config
+, glib
+, systemd
+, wrapGAppsHook
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-session-ctl";
+  version = "40.0";
+
+  src = fetchFromGitHub {
+    owner = "nix-community";
+    repo = pname;
+    rev = version;
+    hash = "sha256-gvBmLx8Qoj1vPsOwaZsd9+pTDvU5D7uUts7ZT1pXwNo=";
+  };
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    pkg-config
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    glib
+    systemd
+  ];
+
+  meta = with lib; {
+    description = "gnome-session-ctl extracted from gnome-session for nixpkgs";
+    homepage = "https://github.com/nix-community/gnome-session-ctl";
+    license = licenses.gpl2Plus;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gnome-session/default.nix b/pkgs/desktops/gnome/core/gnome-session/default.nix
new file mode 100644
index 00000000000..c1ebc436207
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-session/default.nix
@@ -0,0 +1,90 @@
+{ fetchurl, lib, stdenv, substituteAll, meson, ninja, pkg-config, gnome, glib, gtk3, gsettings-desktop-schemas
+, gnome-desktop, dbus, json-glib, libICE, xmlto, docbook_xsl, docbook_xml_dtd_412, python3
+, libxslt, gettext, makeWrapper, systemd, xorg, epoxy, gnugrep, bash, gnome-session-ctl }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-session";
+  version = "40.1.1";
+
+  outputs = ["out" "sessions"];
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-session/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "10nzyhmgkrzk6i70kj7690na0hmsv6qy5bmr10akxq9jxqlphy4w";
+  };
+
+  patches = [
+    (substituteAll {
+      src = ./fix-paths.patch;
+      gsettings = "${glib.bin}/bin/gsettings";
+      dbusLaunch = "${dbus.lib}/bin/dbus-launch";
+      grep = "${gnugrep}/bin/grep";
+      bash = "${bash}/bin/bash";
+    })
+  ];
+
+  mesonFlags = [ "-Dsystemd=true" "-Dsystemd_session=default" ];
+
+  nativeBuildInputs = [
+    meson ninja pkg-config gettext makeWrapper
+    xmlto libxslt docbook_xsl docbook_xml_dtd_412 python3
+    dbus # for DTD
+  ];
+
+  buildInputs = [
+    glib gtk3 libICE gnome-desktop json-glib xorg.xtrans gnome.adwaita-icon-theme
+    gnome.gnome-settings-daemon gsettings-desktop-schemas systemd epoxy
+  ];
+
+  postPatch = ''
+    chmod +x meson_post_install.py # patchShebangs requires executable file
+    patchShebangs meson_post_install.py
+
+    # Use our provided `gnome-session-ctl`
+    original="@libexecdir@/gnome-session-ctl"
+    replacement="${gnome-session-ctl}/libexec/gnome-session-ctl"
+
+    find data/ -type f -name "*.service.in" -exec sed -i \
+      -e s,$original,$replacement,g \
+      {} +
+  '';
+
+  # `bin/gnome-session` will reset the environment when run in wayland, we
+  # therefor wrap `libexec/gnome-session-binary` instead which is the actual
+  # binary needing wrapping
+  preFixup = ''
+    wrapProgram "$out/libexec/gnome-session-binary" \
+      --prefix GI_TYPELIB_PATH : "$GI_TYPELIB_PATH" \
+      --suffix XDG_DATA_DIRS : "$out/share:$GSETTINGS_SCHEMAS_PATH" \
+      --suffix XDG_DATA_DIRS : "${gnome.gnome-shell}/share"\
+      --suffix XDG_CONFIG_DIRS : "${gnome.gnome-settings-daemon}/etc/xdg"
+  '';
+
+  # We move the GNOME sessions to another output since gnome-session is a dependency of
+  # GDM itself. If we do not hide them, it will show broken GNOME sessions when GDM is
+  # enabled without proper GNOME installation.
+  postInstall = ''
+    mkdir $sessions
+    moveToOutput share/wayland-sessions "$sessions"
+    moveToOutput share/xsessions "$sessions"
+
+    # Our provided one is being used
+    rm -rf $out/libexec/gnome-session-ctl
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "gnome-session";
+      attrPath = "gnome.gnome-session";
+    };
+    providedSessions = [ "gnome" "gnome-xorg" ];
+  };
+
+  meta = with lib; {
+    description = "GNOME session manager";
+    homepage = "https://wiki.gnome.org/Projects/SessionManagement";
+    license = licenses.gpl2Plus;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gnome-session/fix-paths.patch b/pkgs/desktops/gnome/core/gnome-session/fix-paths.patch
new file mode 100644
index 00000000000..320b3024dee
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-session/fix-paths.patch
@@ -0,0 +1,42 @@
+diff --git a/gnome-session/gnome-session.in b/gnome-session/gnome-session.in
+index ddd1a591..46a3488b 100755
+--- a/gnome-session/gnome-session.in
++++ b/gnome-session/gnome-session.in
+@@ -3,17 +3,19 @@
+ if [ "x$XDG_SESSION_TYPE" = "xwayland" ] &&
+    [ "x$XDG_SESSION_CLASS" != "xgreeter" ] &&
+    [  -n "$SHELL" ] &&
+-   grep -q "$SHELL" /etc/shells &&
+-   ! (echo "$SHELL" | grep -q "false") &&
+-   ! (echo "$SHELL" | grep -q "nologin"); then
++   @grep@ -q "$SHELL" /etc/shells &&
++   ! (echo "$SHELL" | @grep@ -q "false") &&
++   ! (echo "$SHELL" | @grep@ -q "nologin"); then
+   if [ "$1" != '-l' ]; then
+-    exec bash -c "exec -l '$SHELL' -c '$0 -l $*'"
++    # Make sure the shell actually sets up the environment.
++    unset __NIXOS_SET_ENVIRONMENT_DONE
++    exec @bash@ -c "exec -l '$SHELL' -c '$0 -l $*'"
+   else
+     shift
+   fi
+ fi
+ 
+-SETTING=$(G_MESSAGES_DEBUG='' gsettings get org.gnome.system.locale region)
++SETTING=$(G_MESSAGES_DEBUG='' @gsettings@ get org.gnome.system.locale region)
+ REGION=${SETTING#\'}
+ REGION=${REGION%\'}
+ 
+diff --git a/gnome-session/main.c b/gnome-session/main.c
+index 84edfbe5..e5285489 100644
+--- a/gnome-session/main.c
++++ b/gnome-session/main.c
+@@ -215,7 +215,7 @@ require_dbus_session (int      argc,
+         }
+         new_argv[i + 2] = NULL;
+         
+-        if (!execvp ("dbus-launch", new_argv)) {
++        if (!execvp ("@dbusLaunch@", new_argv)) {
+                 g_set_error (error, 
+                              G_SPAWN_ERROR,
+                              G_SPAWN_ERROR_FAILED,
diff --git a/pkgs/desktops/gnome/core/gnome-settings-daemon/default.nix b/pkgs/desktops/gnome/core/gnome-settings-daemon/default.nix
new file mode 100644
index 00000000000..e091cf2365a
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-settings-daemon/default.nix
@@ -0,0 +1,133 @@
+{ lib, stdenv
+, fetchpatch
+, substituteAll
+, fetchurl
+, meson
+, ninja
+, pkg-config
+, gnome
+, perl
+, gettext
+, gtk3
+, glib
+, libnotify
+, libgnomekbd
+, lcms2
+, libpulseaudio
+, alsaLib
+, libcanberra-gtk3
+, upower
+, colord
+, libgweather
+, polkit
+, gsettings-desktop-schemas
+, geoclue2
+, systemd
+, libgudev
+, libwacom
+, libxslt
+, libxml2
+, modemmanager
+, networkmanager
+, gnome-desktop
+, geocode-glib
+, docbook_xsl
+, wrapGAppsHook
+, python3
+, tzdata
+, nss
+, gcr
+, gnome-session-ctl
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-settings-daemon";
+  version = "40.0.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-settings-daemon/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "08bv32hvsmd8izw0llvldg0c2d71srch4hi8j94jwgm5d4dsrprp";
+  };
+
+  patches = [
+    # https://gitlab.gnome.org/GNOME/gnome-settings-daemon/-/merge_requests/202
+    (fetchpatch {
+      url = "https://gitlab.gnome.org/GNOME/gnome-settings-daemon/commit/aae1e774dd9de22fe3520cf9eb2bfbf7216f5eb0.patch";
+      sha256 = "O4m0rOW8Zrgu3Q0p0OA8b951VC0FjYbOUk9MLzB9icI=";
+    })
+
+    (substituteAll {
+      src = ./fix-paths.patch;
+      inherit tzdata;
+    })
+  ];
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    pkg-config
+    perl
+    gettext
+    libxml2
+    libxslt
+    docbook_xsl
+    wrapGAppsHook
+    python3
+  ];
+
+  buildInputs = [
+    gtk3
+    glib
+    gsettings-desktop-schemas
+    modemmanager
+    networkmanager
+    libnotify
+    libgnomekbd # for org.gnome.libgnomekbd.keyboard schema
+    gnome-desktop
+    lcms2
+    libpulseaudio
+    alsaLib
+    libcanberra-gtk3
+    upower
+    colord
+    libgweather
+    nss
+    polkit
+    geocode-glib
+    geoclue2
+    systemd
+    libgudev
+    libwacom
+    gcr
+  ];
+
+  mesonFlags = [
+    "-Dudev_dir=${placeholder "out"}/lib/udev"
+    "-Dgnome_session_ctl_path=${gnome-session-ctl}/libexec/gnome-session-ctl"
+  ];
+
+  # Default for release buildtype but passed manually because
+  # we're using plain
+  NIX_CFLAGS_COMPILE = "-DG_DISABLE_CAST_CHECKS";
+
+
+  postPatch = ''
+    for f in gnome-settings-daemon/codegen.py plugins/power/gsd-power-constants-update.pl meson_post_install.py; do
+      chmod +x $f
+      patchShebangs $f
+    done
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    license = licenses.gpl2Plus;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gnome-settings-daemon/fix-paths.patch b/pkgs/desktops/gnome/core/gnome-settings-daemon/fix-paths.patch
new file mode 100644
index 00000000000..2229302cab7
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-settings-daemon/fix-paths.patch
@@ -0,0 +1,15 @@
+--- a/plugins/datetime/tz.h
++++ b/plugins/datetime/tz.h
+@@ -27,11 +27,7 @@
+ 
+ #include <glib.h>
+ 
+-#ifndef __sun
+-#  define TZ_DATA_FILE "/usr/share/zoneinfo/zone.tab"
+-#else
+-#  define TZ_DATA_FILE "/usr/share/lib/zoneinfo/tab/zone_sun.tab"
+-#endif
++#define TZ_DATA_FILE "@tzdata@/share/zoneinfo/zone.tab"
+ 
+ typedef struct _TzDB TzDB;
+ typedef struct _TzLocation TzLocation;
diff --git a/pkgs/desktops/gnome/core/gnome-settings-daemon/global-backlight-helper.patch b/pkgs/desktops/gnome/core/gnome-settings-daemon/global-backlight-helper.patch
new file mode 100644
index 00000000000..8f3951af2da
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-settings-daemon/global-backlight-helper.patch
@@ -0,0 +1,26 @@
+diff --git a/plugins/power/gsd-backlight.c b/plugins/power/gsd-backlight.c
+index d7d10fd2..5619d6ad 100644
+--- a/plugins/power/gsd-backlight.c
++++ b/plugins/power/gsd-backlight.c
+@@ -358,7 +358,7 @@ gsd_backlight_run_set_helper (GsdBacklight *backlight, GTask *task)
+                 proc = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_SILENCE,
+                                          &error,
+                                          "pkexec",
+-                                         LIBEXECDIR "/gsd-backlight-helper",
++                                         "/run/current-system/sw/bin/gnome-settings-daemon/gsd-backlight-helper",
+                                          g_udev_device_get_sysfs_path (backlight->udev_device),
+                                          data->value_str, NULL);
+         } else {
+diff --git a/plugins/power/org.gnome.settings-daemon.plugins.power.policy.in.in b/plugins/power/org.gnome.settings-daemon.plugins.power.policy.in.in
+index f16300f8..79d6bd17 100644
+--- a/plugins/power/org.gnome.settings-daemon.plugins.power.policy.in.in
++++ b/plugins/power/org.gnome.settings-daemon.plugins.power.policy.in.in
+@@ -25,7 +25,7 @@
+       <allow_inactive>no</allow_inactive>
+       <allow_active>yes</allow_active>
+     </defaults>
+-    <annotate key="org.freedesktop.policykit.exec.path">@libexecdir@/gsd-backlight-helper</annotate>
++    <annotate key="org.freedesktop.policykit.exec.path">/run/current-system/sw/bin/gnome-settings-daemon/gsd-backlight-helper</annotate>
+   </action>
+
+ </policyconfig>
diff --git a/pkgs/desktops/gnome/core/gnome-shell-extensions/default.nix b/pkgs/desktops/gnome/core/gnome-shell-extensions/default.nix
new file mode 100644
index 00000000000..6c38b790959
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-shell-extensions/default.nix
@@ -0,0 +1,73 @@
+{ lib, stdenv, fetchurl, fetchpatch, meson, ninja, gettext, pkg-config, spidermonkey_68, glib
+, gnome, gnome-menus, substituteAll }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extensions";
+  version = "40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-shell-extensions/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "15hak4prx2nx1svfii39clxy1lll8crdf7p91if85jcsh6r8ab8p";
+  };
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  patches = [
+    (substituteAll {
+      src = ./fix_gmenu.patch;
+      gmenu_path = "${gnome-menus}/lib/girepository-1.0";
+    })
+
+    # Do not show welcome dialog in gnome-classic.
+    # Needed for gnome-shell 40.1.
+    # https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/169
+    (fetchpatch {
+      url = "https://gitlab.gnome.org/GNOME/gnome-shell-extensions/commit/3e8bbb07ea7109c44d5ac7998f473779e742d041.patch";
+      sha256 = "jSmPwSBgRBfPPP9mGVjw1mSWumIXQqtA6tSqHr3U+3w=";
+    })
+  ];
+
+  doCheck = true;
+  # 60 is required for tests
+  # https://gitlab.gnome.org/GNOME/gnome-shell-extensions/blob/3.34.0/meson.build#L23
+  checkInputs = [ spidermonkey_68 ];
+
+  nativeBuildInputs = [ meson ninja pkg-config gettext glib ];
+
+  mesonFlags = [ "-Dextension_set=all" ];
+
+  preFixup = ''
+    # The meson build doesn't compile the schemas.
+    # Fixup adapted from export-zips.sh in the source.
+
+    extensiondir=$out/share/gnome-shell/extensions
+    schemadir=${glib.makeSchemaPath "$out" "${pname}-${version}"}
+
+    glib-compile-schemas $schemadir
+
+    for f in $extensiondir/*; do
+      name=`basename ''${f%%@*}`
+      uuid=$name@gnome-shell-extensions.gcampax.github.com
+      schema=$schemadir/org.gnome.shell.extensions.$name.gschema.xml
+
+      if [ -f $schema ]; then
+        mkdir $f/schemas
+        ln -s $schema $f/schemas;
+        glib-compile-schemas $f/schemas
+      fi
+    done
+  '';
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Projects/GnomeShell/Extensions";
+    description = "Modify and extend GNOME Shell functionality and behavior";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gnome-shell-extensions/fix_gmenu.patch b/pkgs/desktops/gnome/core/gnome-shell-extensions/fix_gmenu.patch
new file mode 100644
index 00000000000..555664e8ae2
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-shell-extensions/fix_gmenu.patch
@@ -0,0 +1,11 @@
+--- a/extensions/apps-menu/extension.js
++++ b/extensions/apps-menu/extension.js
+@@ -1,6 +1,8 @@
+ /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
+ /* exported init enable disable */
+ 
++imports.gi.GIRepository.Repository.prepend_search_path('@gmenu_path@');
++
+ const {
+     Atk, Clutter, Gio, GLib, GMenu, GObject, Gtk, Meta, Shell, St
+ } = imports.gi;
diff --git a/pkgs/desktops/gnome/core/gnome-shell/default.nix b/pkgs/desktops/gnome/core/gnome-shell/default.nix
new file mode 100644
index 00000000000..66eaafb2cc7
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-shell/default.nix
@@ -0,0 +1,225 @@
+{ fetchurl
+, fetchpatch
+, fetchgit
+, substituteAll
+, lib, stdenv
+, meson
+, ninja
+, pkg-config
+, gnome
+, json-glib
+, gettext
+, libsecret
+, python3
+, polkit
+, networkmanager
+, gtk-doc
+, docbook-xsl-nons
+, at-spi2-core
+, libstartup_notification
+, unzip
+, shared-mime-info
+, libgweather
+, librsvg
+, geoclue2
+, perl
+, docbook_xml_dtd_45
+, desktop-file-utils
+, libpulseaudio
+, libical
+, gobject-introspection
+, wrapGAppsHook
+, libxslt
+, gcr
+, accountsservice
+, gdk-pixbuf
+, gdm
+, upower
+, ibus
+, libnma
+, libgnomekbd
+, gnome-desktop
+, gsettings-desktop-schemas
+, gnome-keyring
+, glib
+, gjs
+, mutter
+, evolution-data-server
+, gtk3
+, gtk4
+, sassc
+, systemd
+, pipewire
+, gst_all_1
+, adwaita-icon-theme
+, gnome-bluetooth
+, gnome-clocks
+, gnome-settings-daemon
+, gnome-autoar
+, asciidoc-full
+, bash-completion
+, mesa
+}:
+
+# http://sources.gentoo.org/cgi-bin/viewvc.cgi/gentoo-x86/gnome-base/gnome-shell/gnome-shell-3.10.2.1.ebuild?revision=1.3&view=markup
+let
+  pythonEnv = python3.withPackages (ps: with ps; [ pygobject3 ]);
+in
+stdenv.mkDerivation rec {
+  pname = "gnome-shell";
+  version = "40.0-unstable-2021-05-01";
+
+  outputs = [ "out" "devdoc" ];
+
+  src = fetchgit {
+    url = "https://gitlab.gnome.org/GNOME/gnome-shell.git";
+    rev = "a8a79c03330427808e776c344f7ebc42782a1b5a";
+    sha256 = "ivHV0SRpnBqsdC7fu1Xhtd/BA55O0UdbUyDLy5KHNYs=";
+    fetchSubmodules = true;
+  };
+  # src = fetchurl {
+  #   url = "mirror://gnome/sources/gnome-shell/${lib.versions.major version}/${pname}-${version}.tar.xz";
+  #   sha256 = "sha256-vOcfQC36qcXiab9lv0iiI0PYlubPmiw0ZpOS1/v2hHg=";
+  # };
+
+  patches = [
+    # Hardcode paths to various dependencies so that they can be found at runtime.
+    (substituteAll {
+      src = ./fix-paths.patch;
+      inherit libgnomekbd unzip;
+      gsettings = "${glib.bin}/bin/gsettings";
+    })
+
+    # Use absolute path for libshew installation to make our patched gobject-introspection
+    # aware of the location to hardcode in the generated GIR file.
+    ./shew-gir-path.patch
+
+    # Make D-Bus services wrappable.
+    ./wrap-services.patch
+
+    # Fix greeter logo being too big.
+    # https://gitlab.gnome.org/GNOME/gnome-shell/issues/2591
+    (fetchpatch {
+      url = "https://gitlab.gnome.org/GNOME/gnome-shell/commit/ffb8bd5fa7704ce70ce7d053e03549dd15dce5ae.patch";
+      revert = true;
+      sha256 = "14h7ahlxgly0n3sskzq9dhxzbyb04fn80pv74vz1526396676dzl";
+    })
+
+    # Work around failing fingerprint auth
+    (fetchpatch {
+      url = "https://src.fedoraproject.org/rpms/gnome-shell/raw/9a647c460b651aaec0b8a21f046cc289c1999416/f/0001-gdm-Work-around-failing-fingerprint-auth.patch";
+      sha256 = "pFvZli3TilUt6YwdZztpB8Xq7O60XfuWUuPMMVSpqLw=";
+    })
+  ];
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    pkg-config
+    gettext
+    docbook-xsl-nons
+    docbook_xml_dtd_45
+    gtk-doc
+    perl
+    wrapGAppsHook
+    sassc
+    desktop-file-utils
+    libxslt.bin
+    python3
+    asciidoc-full
+  ];
+
+  buildInputs = [
+    systemd
+    gsettings-desktop-schemas
+    gnome-keyring
+    glib
+    gcr
+    accountsservice
+    libsecret
+    polkit
+    gdk-pixbuf
+    librsvg
+    networkmanager
+    libstartup_notification
+    gjs
+    mutter
+    libpulseaudio
+    evolution-data-server
+    libical
+    gtk3
+    gtk4
+    gdm
+    geoclue2
+    adwaita-icon-theme
+    gnome-bluetooth
+    gnome-clocks # schemas needed
+    at-spi2-core
+    upower
+    ibus
+    gnome-desktop
+    gnome-settings-daemon
+    gobject-introspection
+    mesa
+
+    # recording
+    pipewire
+    gst_all_1.gstreamer
+    gst_all_1.gst-plugins-base
+    gst_all_1.gst-plugins-good
+
+    # not declared at build time, but typelib is needed at runtime
+    libgweather
+    libnma
+
+    # for gnome-extension tool
+    bash-completion
+    gnome-autoar
+    json-glib
+  ];
+
+  mesonFlags = [
+    "-Dgtk_doc=true"
+  ];
+
+  postPatch = ''
+    patchShebangs src/data-to-c.pl
+    chmod +x meson/postinstall.py
+    patchShebangs meson/postinstall.py
+
+    substituteInPlace src/gnome-shell-extension-tool.in --replace "@PYTHON@" "${pythonEnv}/bin/python"
+    substituteInPlace src/gnome-shell-perf-tool.in --replace "@PYTHON@" "${pythonEnv}/bin/python"
+  '';
+
+  preFixup = ''
+    gappsWrapperArgs+=(
+      # Until glib’s xdgmime is patched
+      # Fixes “Failed to load resource:///org/gnome/shell/theme/noise-texture.png: Unrecognized image file format”
+      --prefix XDG_DATA_DIRS : "${shared-mime-info}/share"
+    )
+  '';
+
+  postFixup = ''
+    # The services need typelibs.
+    for svc in org.gnome.ScreenSaver org.gnome.Shell.Extensions org.gnome.Shell.Notifications org.gnome.Shell.Screencast; do
+      wrapGApp $out/share/gnome-shell/$svc
+    done
+  '';
+
+  passthru = {
+    mozillaPlugin = "/lib/mozilla/plugins";
+    updateScript = gnome.updateScript {
+      packageName = "gnome-shell";
+      attrPath = "gnome.gnome-shell";
+    };
+  };
+
+  meta = with lib; {
+    description = "Core user interface for the GNOME 3 desktop";
+    homepage = "https://wiki.gnome.org/Projects/GnomeShell";
+    license = licenses.gpl2Plus;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+
+}
diff --git a/pkgs/desktops/gnome/core/gnome-shell/fix-paths.patch b/pkgs/desktops/gnome/core/gnome-shell/fix-paths.patch
new file mode 100644
index 00000000000..e17a608a2d8
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-shell/fix-paths.patch
@@ -0,0 +1,30 @@
+--- a/js/ui/extensionDownloader.js
++++ b/js/ui/extensionDownloader.js
+@@ -86,7 +86,7 @@
+     stream.output_stream.write_bytes(contents, null);
+     stream.close(null);
+     let [success, pid] = GLib.spawn_async(null,
+-                                          ['unzip', '-uod', dir.get_path(), '--', file.get_path()],
++                                          ['@unzip@/bin/unzip', '-uod', dir.get_path(), '--', file.get_path()],
+                                           null,
+                                           GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD,
+                                           null);
+--- a/js/ui/status/keyboard.js
++++ b/js/ui/status/keyboard.js
+@@ -1062,6 +1062,6 @@ class InputSourceIndicator extends PanelMenu.Button {
+         if (xkbVariant.length > 0)
+             description = `${description}\t${xkbVariant}`;
+ 
+-        Util.spawn(['gkbd-keyboard-display', '-l', description]);
++        Util.spawn(['@libgnomekbd@/bin/gkbd-keyboard-display', '-l', description]);
+     }
+ });
+--- a/data/org.gnome.Shell-disable-extensions.service
++++ b/data/org.gnome.Shell-disable-extensions.service
+@@ -10,5 +10,5 @@ Requisite=gnome-session-stable.timer
+ [Service]
+ Type=simple
+ # Disable extensions
+-ExecStart=gsettings set org.gnome.shell disable-user-extensions true
++ExecStart=@gsettings@ set org.gnome.shell disable-user-extensions true
+ Restart=no
diff --git a/pkgs/desktops/gnome/core/gnome-shell/shew-gir-path.patch b/pkgs/desktops/gnome/core/gnome-shell/shew-gir-path.patch
new file mode 100644
index 00000000000..6d888725b5d
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-shell/shew-gir-path.patch
@@ -0,0 +1,11 @@
+--- a/subprojects/shew/src/meson.build
++++ b/subprojects/shew/src/meson.build
+@@ -13,7 +13,7 @@ shew_sources = [
+ libshew = library(full_name,
+   sources: shew_sources,
+   dependencies: [gtk_dep, x11_dep],
+-  install_dir: pkglibdir,
++  install_dir: get_option('prefix') / pkglibdir,
+   install: true,
+ )
+ 
diff --git a/pkgs/desktops/gnome/core/gnome-shell/wrap-services.patch b/pkgs/desktops/gnome/core/gnome-shell/wrap-services.patch
new file mode 100644
index 00000000000..bc494caea9d
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-shell/wrap-services.patch
@@ -0,0 +1,57 @@
+diff --git a/js/dbusServices/dbus-service.in b/js/dbusServices/dbus-service.in
+old mode 100644
+new mode 100755
+index 524166102..100b81a63
+--- a/js/dbusServices/dbus-service.in
++++ b/js/dbusServices/dbus-service.in
+@@ -1,3 +1,9 @@
++#!@gjs@
++
++// gjs determines the package name from argv[0], which is .*-wrapped
++// so we need to override it to the original one.
++imports.package._findEffectiveEntryPointName = () => '@service@'
++
+ imports.package.start({
+     name: '@PACKAGE_NAME@',
+     prefix: '@prefix@',
+diff --git a/js/dbusServices/dbus-service.service.in b/js/dbusServices/dbus-service.service.in
+index 3b0d09abe..4fd4bb66d 100644
+--- a/js/dbusServices/dbus-service.service.in
++++ b/js/dbusServices/dbus-service.service.in
+@@ -1,3 +1,3 @@
+ [D-BUS Service]
+ Name=@service@
+-Exec=@gjs@ @pkgdatadir@/@service@
++Exec=@pkgdatadir@/@service@
+diff --git a/js/dbusServices/meson.build b/js/dbusServices/meson.build
+index c749f45dc..11bcb0c9e 100644
+--- a/js/dbusServices/meson.build
++++ b/js/dbusServices/meson.build
+@@ -2,6 +2,7 @@ launcherconf = configuration_data()
+ launcherconf.set('PACKAGE_NAME', meson.project_name())
+ launcherconf.set('prefix', prefix)
+ launcherconf.set('libdir', libdir)
++launcherconf.set('gjs', gjs.path())
+ 
+ dbus_services = {
+   'org.gnome.Shell.Extensions': 'extensions',
+@@ -11,16 +12,17 @@ dbus_services = {
+ config_dir = '@0@/..'.format(meson.current_build_dir())
+ 
+ foreach service, dir : dbus_services
++  svc_launcherconf = launcherconf
++  svc_launcherconf.set('service', service)
+   configure_file(
+     input: 'dbus-service.in',
+     output: service,
+-    configuration: launcherconf,
++    configuration: svc_launcherconf,
+     install_dir: pkgdatadir,
+   )
+ 
+   serviceconf = configuration_data()
+   serviceconf.set('service', service)
+-  serviceconf.set('gjs', gjs.path())
+   serviceconf.set('pkgdatadir', pkgdatadir)
+ 
+   configure_file(
diff --git a/pkgs/desktops/gnome/core/gnome-software/default.nix b/pkgs/desktops/gnome/core/gnome-software/default.nix
new file mode 100644
index 00000000000..64cd214e809
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-software/default.nix
@@ -0,0 +1,120 @@
+{ lib
+, stdenv
+, fetchurl
+, substituteAll
+, pkg-config
+, meson
+, ninja
+, gettext
+, gnome
+, wrapGAppsHook
+, packagekit
+, ostree
+, glib
+, appstream
+, libsoup
+, libhandy
+, polkit
+, isocodes
+, gspell
+, libxslt
+, gobject-introspection
+, flatpak
+, fwupd
+, gtk3
+, gsettings-desktop-schemas
+, gnome-desktop
+, libxmlb
+, gnome-online-accounts
+, json-glib
+, libsecret
+, valgrind-light
+, docbook-xsl-nons
+, docbook_xml_dtd_42
+, docbook_xml_dtd_43
+, gtk-doc
+, desktop-file-utils
+, libsysprof-capture
+}:
+
+let
+  withFwupd = stdenv.isx86_64 || stdenv.isi686;
+in
+
+stdenv.mkDerivation rec {
+  pname = "gnome-software";
+  version = "40.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-software/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "16q2902swxsjdxb1nj335sv1bb76rvq4w6dn4yszkwf3s0fd86in";
+  };
+
+  patches = [
+    (substituteAll {
+      src = ./fix-paths.patch;
+      inherit isocodes;
+    })
+  ];
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    pkg-config
+    gettext
+    wrapGAppsHook
+    libxslt
+    docbook_xml_dtd_42
+    docbook_xml_dtd_43
+    valgrind-light
+    docbook-xsl-nons
+    gtk-doc
+    desktop-file-utils
+    gobject-introspection
+  ];
+
+  buildInputs = [
+    gtk3
+    glib
+    packagekit
+    appstream
+    libsoup
+    libhandy
+    gsettings-desktop-schemas
+    gnome-desktop
+    gspell
+    json-glib
+    libsecret
+    ostree
+    polkit
+    flatpak
+    libxmlb
+    gnome-online-accounts
+    libsysprof-capture
+  ] ++ lib.optionals withFwupd [
+    fwupd
+  ];
+
+  mesonFlags = [
+    "-Dgudev=false"
+    # FIXME: package malcontent parental controls
+    "-Dmalcontent=false"
+  ] ++ lib.optionals (!withFwupd) [
+    "-Dfwupd=false"
+  ];
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.gnome-software";
+    };
+  };
+
+  meta = with lib; {
+    description = "Software store that lets you install and update applications and system extensions";
+    homepage = "https://wiki.gnome.org/Apps/Software";
+    license = licenses.gpl2Plus;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gnome-software/fix-paths.patch b/pkgs/desktops/gnome/core/gnome-software/fix-paths.patch
new file mode 100644
index 00000000000..6f443a8a43e
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-software/fix-paths.patch
@@ -0,0 +1,11 @@
+--- a/src/gs-language.c
++++ b/src/gs-language.c
+@@ -95,7 +95,7 @@
+ 	g_autoptr(GMarkupParseContext) context = NULL;
+ 
+ 	/* find filename */
+-	filename = g_build_filename (DATADIR, "xml", "iso-codes", "iso_639.xml", NULL);
++	filename = g_build_filename ("@isocodes@", "share", "xml", "iso-codes", "iso_639.xml", NULL);
+ 	if (!g_file_test (filename, G_FILE_TEST_EXISTS)) {
+ 		g_free (filename);
+ 		filename = g_build_filename ("/usr", "share", "xml", "iso-codes", "iso_639.xml", NULL);
diff --git a/pkgs/desktops/gnome/core/gnome-system-monitor/default.nix b/pkgs/desktops/gnome/core/gnome-system-monitor/default.nix
new file mode 100644
index 00000000000..77579be6272
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-system-monitor/default.nix
@@ -0,0 +1,81 @@
+{ lib
+, stdenv
+, gettext
+, fetchurl
+, pkg-config
+, gtkmm3
+, libxml2
+, bash
+, gtk3
+, libhandy
+, glib
+, wrapGAppsHook
+, meson
+, ninja
+, python3
+, gsettings-desktop-schemas
+, itstool
+, gnome
+, librsvg
+, gdk-pixbuf
+, libgtop
+, systemd
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-system-monitor";
+  version = "40.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-system-monitor/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "06hxd4igxas2kyind5jwfq5qbfkknykpdfy2sy3anylhcx1hzczx";
+  };
+
+  nativeBuildInputs = [
+    pkg-config
+    gettext
+    itstool
+    wrapGAppsHook
+    meson
+    ninja
+    python3
+  ];
+
+  buildInputs = [
+    bash
+    gtk3
+    libhandy
+    glib
+    libxml2
+    gtkmm3
+    libgtop
+    gdk-pixbuf
+    gnome.adwaita-icon-theme
+    librsvg
+    gsettings-desktop-schemas
+    systemd
+  ];
+
+  doCheck = true;
+
+  postPatch = ''
+    chmod +x meson_post_install.py # patchShebangs requires executable file
+    patchShebangs meson_post_install.py
+    sed -i '/gtk-update-icon-cache/s/^/#/' meson_post_install.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "gnome-system-monitor";
+      attrPath = "gnome.gnome-system-monitor";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/SystemMonitor";
+    description = "System Monitor shows you what programs are running and how much processor time, memory, and disk space are being used";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gnome-terminal/default.nix b/pkgs/desktops/gnome/core/gnome-terminal/default.nix
new file mode 100644
index 00000000000..ab3e3aecc03
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-terminal/default.nix
@@ -0,0 +1,51 @@
+{ lib, stdenv, fetchurl, pkg-config, libxml2, gnome, dconf, nautilus
+, gtk3, gsettings-desktop-schemas, vte, gettext, which, libuuid, vala
+, desktop-file-utils, itstool, wrapGAppsHook, pcre2
+, libxslt, docbook-xsl-nons }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-terminal";
+  version = "3.40.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-terminal/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "1r6qd6w18gk83w32y6bvn4hg2hd7qvngak4ymwpgndyp41rwqw07";
+  };
+
+  buildInputs = [
+    gtk3 gsettings-desktop-schemas vte libuuid dconf
+    # For extension
+    nautilus
+  ];
+
+  nativeBuildInputs = [
+    pkg-config gettext itstool which libxml2 libxslt docbook-xsl-nons
+    vala desktop-file-utils wrapGAppsHook pcre2
+  ];
+
+  # Silly ./configure, it looks for dbus file from gnome-shell in the
+  # installation tree of the package it is configuring.
+  postPatch = ''
+    substituteInPlace configure --replace '$(eval echo $(eval echo $(eval echo ''${dbusinterfacedir})))/org.gnome.ShellSearchProvider2.xml' "${gnome.gnome-shell}/share/dbus-1/interfaces/org.gnome.ShellSearchProvider2.xml"
+    substituteInPlace src/Makefile.in --replace '$(dbusinterfacedir)/org.gnome.ShellSearchProvider2.xml' "${gnome.gnome-shell}/share/dbus-1/interfaces/org.gnome.ShellSearchProvider2.xml"
+  '';
+
+  configureFlags = [ "--disable-migration" ]; # TODO: remove this with 3.30
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "gnome-terminal";
+      attrPath = "gnome.gnome-terminal";
+    };
+  };
+
+  enableParallelBuilding = true;
+
+  meta = with lib; {
+    description = "The GNOME Terminal Emulator";
+    homepage = "https://wiki.gnome.org/Apps/Terminal";
+    platforms = platforms.linux;
+    license = licenses.gpl3Plus;
+    maintainers = teams.gnome.members;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gnome-themes-extra/default.nix b/pkgs/desktops/gnome/core/gnome-themes-extra/default.nix
new file mode 100644
index 00000000000..53f775833a8
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-themes-extra/default.nix
@@ -0,0 +1,35 @@
+{ lib, stdenv, fetchurl, intltool, gtk3, gnome, librsvg, pkg-config, pango, atk, gtk2
+, gdk-pixbuf, hicolor-icon-theme }:
+
+let
+  pname = "gnome-themes-extra";
+  version = "3.28";
+in stdenv.mkDerivation rec {
+  name = "${pname}-${version}";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${name}.tar.xz";
+    sha256 = "06aqg9asq2vqi9wr29bs4v8z2bf4manhbhfghf4nvw01y2zs0jvw";
+  };
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+    };
+  };
+
+  nativeBuildInputs = [ pkg-config intltool ];
+  buildInputs = [ gtk3 librsvg pango atk gtk2 gdk-pixbuf ];
+  propagatedBuildInputs = [ gnome.adwaita-icon-theme hicolor-icon-theme ];
+
+  dontDropIconThemeCache = true;
+
+  postInstall = ''
+    gtk-update-icon-cache "$out"/share/icons/HighContrast
+  '';
+
+  meta = with lib; {
+    platforms = platforms.linux;
+    maintainers = teams.gnome.members;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gnome-tour/default.nix b/pkgs/desktops/gnome/core/gnome-tour/default.nix
new file mode 100644
index 00000000000..7440749e0a9
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-tour/default.nix
@@ -0,0 +1,75 @@
+{ lib
+, stdenv
+, rustPlatform
+, gettext
+, meson
+, ninja
+, fetchurl
+, pkg-config
+, gtk3
+, glib
+, gdk-pixbuf
+, desktop-file-utils
+, appstream-glib
+, wrapGAppsHook
+, python3
+, gnome
+, libhandy
+, librsvg
+, rustc
+, cargo
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-tour";
+  version = "40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    hash = "sha256-cGMiOGmgdHJ0FL7H23ONhQYhbuhMz8O8p9rFLkmMG/k=";
+  };
+
+  cargoVendorDir = "vendor";
+
+  nativeBuildInputs = [
+    appstream-glib
+    cargo
+    desktop-file-utils
+    gettext
+    glib # glib-compile-resources
+    meson
+    ninja
+    pkg-config
+    python3
+    rustPlatform.cargoSetupHook
+    rustc
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    gdk-pixbuf
+    glib
+    gtk3
+    libhandy
+    librsvg
+  ];
+
+  postPatch = ''
+    chmod +x build-aux/meson_post_install.py
+    patchShebangs build-aux/meson_post_install.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://gitlab.gnome.org/GNOME/gnome-tour";
+    description = "GNOME Greeter & Tour";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl3Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gnome-user-share/default.nix b/pkgs/desktops/gnome/core/gnome-user-share/default.nix
new file mode 100644
index 00000000000..211326cfcdb
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gnome-user-share/default.nix
@@ -0,0 +1,96 @@
+{ lib, stdenv
+, gettext
+, meson
+, ninja
+, fetchurl
+, fetchpatch
+, apacheHttpd
+, nautilus
+, pkg-config
+, gtk3
+, glib
+, libxml2
+, systemd
+, wrapGAppsHook
+, itstool
+, libnotify
+, mod_dnssd
+, gnome
+, libcanberra-gtk3
+, python3
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-user-share";
+  version = "3.34.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "04r9ck9v4i0d31grbli1d4slw2d6dcsfkpaybkwbzi7wnj72l30x";
+  };
+
+  patches = [
+    # fix gio-unix-2.0 lookup
+    (fetchpatch {
+      url = "https://gitlab.gnome.org/GNOME/gnome-user-share/commit/8772980d4732c15505b15dccff2ca3c97e96d49d.patch";
+      sha256 = "03clzhrx72pq1cbmg2y24hvw4i1xsvrg9ip113fi5bc3w4gcji7p";
+    })
+  ];
+
+  postPatch = ''
+    chmod +x meson_post_install.py
+    patchShebangs meson_post_install.py
+  '';
+
+  preConfigure = ''
+    sed -e 's,^LoadModule dnssd_module.\+,LoadModule dnssd_module ${mod_dnssd}/modules/mod_dnssd.so,' \
+      -e 's,''${HTTP_MODULES_PATH},${apacheHttpd}/modules,' \
+      -i data/dav_user_2.4.conf
+  '';
+
+  mesonFlags = [
+    "-Dhttpd=${apacheHttpd.out}/bin/httpd"
+    "-Dmodules_path=${apacheHttpd.dev}/modules"
+    "-Dsystemduserunitdir=${placeholder "out"}/etc/systemd/user"
+    # In 3.34.0 it defaults to false but it is silently ignored and always installed.
+    # Let’s add it anyway in case they decide to make build respect the option in the future.
+    "-Dnautilus_extension=true"
+  ];
+
+  nativeBuildInputs = [
+    pkg-config
+    meson
+    ninja
+    gettext
+    itstool
+    libxml2
+    wrapGAppsHook
+    python3
+  ];
+
+  buildInputs = [
+    gtk3
+    glib
+    nautilus
+    libnotify
+    libcanberra-gtk3
+    systemd
+  ];
+
+  doCheck = true;
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://help.gnome.org/users/gnome-user-share/3.8";
+    description = "Service that exports the contents of the Public folder in your home directory on the local network";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/gucharmap/default.nix b/pkgs/desktops/gnome/core/gucharmap/default.nix
new file mode 100644
index 00000000000..336a4d260c4
--- /dev/null
+++ b/pkgs/desktops/gnome/core/gucharmap/default.nix
@@ -0,0 +1,108 @@
+{ lib, stdenv
+, intltool
+, fetchFromGitLab
+, meson
+, ninja
+, pkg-config
+, python3
+, gtk3
+, adwaita-icon-theme
+, glib
+, desktop-file-utils
+, gtk-doc
+, wrapGAppsHook
+, gnome
+, itstool
+, libxml2
+, yelp-tools
+, docbook_xsl
+, docbook_xml_dtd_412
+, gsettings-desktop-schemas
+, callPackage
+, unzip
+, unicode-character-database
+, unihan-database
+, runCommand
+, symlinkJoin
+, gobject-introspection
+}:
+
+let
+  # TODO: make upstream patch allowing to use the uncompressed file,
+  # preferably from XDG_DATA_DIRS.
+  # https://gitlab.gnome.org/GNOME/gucharmap/issues/13
+  unihanZip = runCommand "unihan" {} ''
+    mkdir -p $out/share/unicode
+    ln -s ${unihan-database.src} $out/share/unicode/Unihan.zip
+  '';
+  ucd = symlinkJoin {
+    name = "ucd+unihan";
+    paths = [
+      unihanZip
+      unicode-character-database
+    ];
+  };
+in stdenv.mkDerivation rec {
+  pname = "gucharmap";
+  version = "13.0.2";
+
+  outputs = [ "out" "lib" "dev" "devdoc" ];
+
+  src = fetchFromGitLab {
+    domain = "gitlab.gnome.org";
+    owner = "GNOME";
+    repo = pname;
+    rev = version;
+    sha256 = "099za9mc6qdq9pwcbjp3d7hxjbaa43vk2w9qw4yiyswl1xq3jw62";
+  };
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    pkg-config
+    python3
+    wrapGAppsHook
+    unzip
+    intltool
+    itstool
+    gtk-doc
+    docbook_xsl
+    docbook_xml_dtd_412
+    yelp-tools
+    libxml2
+    desktop-file-utils
+    gobject-introspection
+  ];
+
+  buildInputs = [
+    gtk3
+    glib
+    gsettings-desktop-schemas
+    adwaita-icon-theme
+  ];
+
+  mesonFlags = [
+    "-Ducd_path=${ucd}/share/unicode"
+    "-Dvapi=false"
+  ];
+
+  doCheck = true;
+
+  postPatch = ''
+    patchShebangs data/meson_desktopfile.py gucharmap/gen-guch-unicode-tables.pl gucharmap/meson_compileschemas.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+    };
+  };
+
+  meta = with lib; {
+    description = "GNOME Character Map, based on the Unicode Character Database";
+    homepage = "https://wiki.gnome.org/Apps/Gucharmap";
+    license = licenses.gpl3;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/libgnome-keyring/default.nix b/pkgs/desktops/gnome/core/libgnome-keyring/default.nix
new file mode 100644
index 00000000000..aa3c7ed3981
--- /dev/null
+++ b/pkgs/desktops/gnome/core/libgnome-keyring/default.nix
@@ -0,0 +1,32 @@
+{ lib, stdenv, fetchurl, glib, dbus, libgcrypt, pkg-config, intltool, gobject-introspection, gnome }:
+
+let
+  pname = "libgnome-keyring";
+  version = "3.12.0";
+in
+stdenv.mkDerivation rec {
+  name = "${pname}-${version}";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${name}.tar.xz";
+    sha256 = "c4c178fbb05f72acc484d22ddb0568f7532c409b0a13e06513ff54b91e947783";
+  };
+
+  outputs = [ "out" "dev" ];
+
+  propagatedBuildInputs = [ glib gobject-introspection dbus libgcrypt ];
+  nativeBuildInputs = [ pkg-config intltool ];
+
+  meta = {
+    description = "Framework for managing passwords and other secrets";
+    homepage = "https://wiki.gnome.org/Projects/GnomeKeyring";
+    license = with lib.licenses; [ gpl2Plus lgpl2Plus ];
+    inherit (glib.meta) platforms maintainers;
+
+    longDescription = ''
+      gnome-keyring is a program that keeps password and other secrets for
+      users. The library libgnome-keyring is used by applications to integrate
+      with the gnome-keyring system.
+    '';
+  };
+}
diff --git a/pkgs/desktops/gnome/core/mutter/3.34/0001-EGL-Include-EGL-eglmesaext.h.patch b/pkgs/desktops/gnome/core/mutter/3.34/0001-EGL-Include-EGL-eglmesaext.h.patch
new file mode 100644
index 00000000000..3691c034d1e
--- /dev/null
+++ b/pkgs/desktops/gnome/core/mutter/3.34/0001-EGL-Include-EGL-eglmesaext.h.patch
@@ -0,0 +1,74 @@
+From 7b94f980f2a099dd4b19b60c357cfcf5ff7ada6d Mon Sep 17 00:00:00 2001
+Message-Id: <7b94f980f2a099dd4b19b60c357cfcf5ff7ada6d.1601082838.git-series.worldofpeace@protonmail.ch>
+From: WORLDofPEACE <worldofpeace@protonmail.ch>
+Date: Sun, 20 Oct 2019 12:04:31 +0200
+Subject: [PATCH 1/7] EGL: Include EGL/eglmesaext.h
+
+From: Jan Alexander Steffens (heftig) <jan.steffens@gmail.com>
+
+The eglext.h shipped by libglvnd does not include the Mesa extensions,
+unlike the header shipped in Mesa.
+
+Fixes https://gitlab.gnome.org/GNOME/mutter/issues/876
+
+(cherry picked from commit a444a4c5f58ea516ad3cd9d6ddc0056c3ca9bc90)
+---
+ cogl/cogl/meson.build       | 2 +-
+ src/backends/meta-egl-ext.h | 1 +
+ src/backends/meta-egl.c     | 1 +
+ src/backends/meta-egl.h     | 1 +
+ 4 files changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/cogl/cogl/meson.build b/cogl/cogl/meson.build
+index 1057ef9..9a64294 100644
+--- a/cogl/cogl/meson.build
++++ b/cogl/cogl/meson.build
+@@ -48,7 +48,7 @@ cogl_gl_header_h = configure_file(
+ built_headers += [cogl_gl_header_h]
+ 
+ if have_egl
+-  cogl_egl_includes_string = '#include <EGL/egl.h>\n#include <EGL/eglext.h>'
++  cogl_egl_includes_string = '#include <EGL/egl.h>\n#include <EGL/eglext.h>\n#include <EGL/eglmesaext.h>'
+ else
+   cogl_egl_includes_string = ''
+ endif
+diff --git a/src/backends/meta-egl-ext.h b/src/backends/meta-egl-ext.h
+index 8705e7d..db0b74f 100644
+--- a/src/backends/meta-egl-ext.h
++++ b/src/backends/meta-egl-ext.h
+@@ -29,6 +29,7 @@
+ 
+ #include <EGL/egl.h>
+ #include <EGL/eglext.h>
++#include <EGL/eglmesaext.h>
+ 
+ /*
+  * This is a little different to the tests shipped with EGL implementations,
+diff --git a/src/backends/meta-egl.c b/src/backends/meta-egl.c
+index 6554be9..fdeff4f 100644
+--- a/src/backends/meta-egl.c
++++ b/src/backends/meta-egl.c
+@@ -27,6 +27,7 @@
+ 
+ #include <EGL/egl.h>
+ #include <EGL/eglext.h>
++#include <EGL/eglmesaext.h>
+ #include <gio/gio.h>
+ #include <glib.h>
+ #include <glib-object.h>
+diff --git a/src/backends/meta-egl.h b/src/backends/meta-egl.h
+index f2a8164..4591e7d 100644
+--- a/src/backends/meta-egl.h
++++ b/src/backends/meta-egl.h
+@@ -28,6 +28,7 @@
+ 
+ #include <EGL/egl.h>
+ #include <EGL/eglext.h>
++#include <EGL/eglmesaext.h>
+ #include <glib-object.h>
+ 
+ #define META_EGL_ERROR meta_egl_error_quark ()
+
+base-commit: 48ffbb582404c1d52196eb6cc5f082c31ca4910c
+-- 
+git-series 0.9.1
diff --git a/pkgs/desktops/gnome/core/mutter/3.34/0002-drop-inheritable.patch b/pkgs/desktops/gnome/core/mutter/3.34/0002-drop-inheritable.patch
new file mode 100644
index 00000000000..28f89ac7c0c
--- /dev/null
+++ b/pkgs/desktops/gnome/core/mutter/3.34/0002-drop-inheritable.patch
@@ -0,0 +1,135 @@
+From 14cee101882e65a57dcd66ea0f8399477b23ce7e Mon Sep 17 00:00:00 2001
+Message-Id: <14cee101882e65a57dcd66ea0f8399477b23ce7e.1601082838.git-series.worldofpeace@protonmail.ch>
+In-Reply-To: <7b94f980f2a099dd4b19b60c357cfcf5ff7ada6d.1601082838.git-series.worldofpeace@protonmail.ch>
+References: <7b94f980f2a099dd4b19b60c357cfcf5ff7ada6d.1601082838.git-series.worldofpeace@protonmail.ch>
+From: WORLDofPEACE <worldofpeace@protonmail.ch>
+Date: Sat, 19 Oct 2019 13:26:05 +0200
+Subject: [PATCH 2/7] drop inheritable
+
+From: Tor Hedin Brønner <torhedinbronner@gmail.com>
+
+Adapted from https://gitlab.gnome.org/GNOME/mutter/commit/c53c47ae123b03cc66044d2b846342123ecb3a01
+
+We only want to drop inheritable though, to prevent the ambient set leaking further than gnome-shell.
+---
+ config.h.meson    |  3 +++
+ meson.build       |  5 +++++
+ meson_options.txt |  6 ++++++
+ src/core/main.c   | 10 ++++++++++
+ src/meson.build   |  1 +
+ 5 files changed, 25 insertions(+)
+
+diff --git a/config.h.meson b/config.h.meson
+index 0bab718..202fb7e 100644
+--- a/config.h.meson
++++ b/config.h.meson
+@@ -58,6 +58,9 @@
+ /* Xwayland applications allowed to issue keyboard grabs */
+ #mesondefine XWAYLAND_GRAB_DEFAULT_ACCESS_RULES
+ 
++/* Defined if libcap-ng is available */
++#mesondefine HAVE_LIBCAPNG
++
+ /* XKB base prefix */
+ #mesondefine XKB_BASE
+ 
+diff --git a/meson.build b/meson.build
+index 29d495b..86970df 100644
+--- a/meson.build
++++ b/meson.build
+@@ -35,6 +35,7 @@ libstartup_notification_req = '>= 0.7'
+ libcanberra_req = '>= 0.26'
+ libwacom_req = '>= 0.13'
+ atk_req = '>= 2.5.3'
++libcapng_req = '>= 0.7.9'
+ 
+ # optional version requirements
+ udev_req = '>= 228'
+@@ -125,6 +126,7 @@ xau_dep = dependency('xau')
+ ice_dep = dependency('ice')
+ atk_dep = dependency('atk', version: atk_req)
+ libcanberra_dep = dependency('libcanberra', version: libcanberra_req)
++libcapng_dep = dependency('libcap-ng', required: get_option('libcapng'))
+ 
+ # For now always require X11 support
+ have_x11 = true
+@@ -256,6 +258,7 @@ have_core_tests = false
+ have_cogl_tests = false
+ have_clutter_tests = false
+ have_installed_tests = false
++have_libcapng = libcapng_dep.found()
+ 
+ if have_tests
+   have_core_tests = get_option('core_tests')
+@@ -361,6 +364,7 @@ cdata.set('HAVE_LIBWACOM', have_libwacom)
+ cdata.set('HAVE_SM', have_sm)
+ cdata.set('HAVE_STARTUP_NOTIFICATION', have_startup_notification)
+ cdata.set('HAVE_INTROSPECTION', have_introspection)
++cdata.set('HAVE_LIBCAPNG', have_libcapng)
+ cdata.set('HAVE_PROFILER', have_profiler)
+ 
+ xkb_base = xkeyboard_config_dep.get_pkgconfig_variable('xkb_base')
+@@ -443,6 +447,7 @@ output = [
+   '        Startup notification..... ' + have_startup_notification.to_string(),
+   '        Introspection............ ' + have_introspection.to_string(),
+   '        Profiler................. ' + have_profiler.to_string(),
++  '        libcap-ng................ ' + have_libcapng.to_string(),
+   '',
+   '    Tests:',
+   '',
+diff --git a/meson_options.txt b/meson_options.txt
+index 73aa7ad..8bfaacd 100644
+--- a/meson_options.txt
++++ b/meson_options.txt
+@@ -152,3 +152,9 @@ option('xwayland_grab_default_access_rules',
+   value: 'gnome-boxes,remote-viewer,virt-viewer,virt-manager,vinagre,vncviewer,Xephyr',
+   description: 'Comma delimited list of applications ressources or class allowed to issue X11 grabs in Xwayland'
+ )
++
++option('libcapng',
++  type: 'feature',
++  value: 'auto',
++  description: 'Enable libcap-ng support'
++)
+diff --git a/src/core/main.c b/src/core/main.c
+index 3935f35..ecf3cb2 100644
+--- a/src/core/main.c
++++ b/src/core/main.c
+@@ -66,6 +66,10 @@
+ #include <girepository.h>
+ #endif
+ 
++#ifdef HAVE_LIBCAPNG
++#include <cap-ng.h>
++#endif
++
+ #if defined(HAVE_NATIVE_BACKEND) && defined(HAVE_WAYLAND)
+ #include <systemd/sd-login.h>
+ #endif /* HAVE_WAYLAND && HAVE_NATIVE_BACKEND */
+@@ -673,6 +677,12 @@ meta_run (void)
+   if (!meta_display_open ())
+     meta_exit (META_EXIT_ERROR);
+ 
++#ifdef HAVE_LIBCAPNG
++  capng_clear(CAPNG_SELECT_BOTH);
++  capng_update(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, CAP_SYS_NICE);
++  capng_apply(CAPNG_SELECT_BOTH);
++#endif
++
+   g_main_loop_run (meta_main_loop);
+ 
+   meta_finalize ();
+diff --git a/src/meson.build b/src/meson.build
+index 90d8073..a9fffa2 100644
+--- a/src/meson.build
++++ b/src/meson.build
+@@ -18,6 +18,7 @@ mutter_pkg_deps = [
+   glib_dep,
+   gsettings_desktop_schemas_dep,
+   gtk3_dep,
++  libcapng_dep,
+   pango_dep,
+ ]
+ 
+-- 
+git-series 0.9.1
diff --git a/pkgs/desktops/gnome/core/mutter/3.34/0003-Fix-glitches-in-gala.patch b/pkgs/desktops/gnome/core/mutter/3.34/0003-Fix-glitches-in-gala.patch
new file mode 100644
index 00000000000..9f78a324d9d
--- /dev/null
+++ b/pkgs/desktops/gnome/core/mutter/3.34/0003-Fix-glitches-in-gala.patch
@@ -0,0 +1,33 @@
+From 5d2b9a03f24b4dbc423adff52b2eeb478c4b5913 Mon Sep 17 00:00:00 2001
+Message-Id: <5d2b9a03f24b4dbc423adff52b2eeb478c4b5913.1601082838.git-series.worldofpeace@protonmail.ch>
+In-Reply-To: <7b94f980f2a099dd4b19b60c357cfcf5ff7ada6d.1601082838.git-series.worldofpeace@protonmail.ch>
+References: <7b94f980f2a099dd4b19b60c357cfcf5ff7ada6d.1601082838.git-series.worldofpeace@protonmail.ch>
+From: WORLDofPEACE <worldofpeace@protonmail.ch>
+Date: Sun,  5 Apr 2020 23:06:03 -0400
+Subject: [PATCH 3/7] Fix glitches in gala
+
+From: worldofpeace <worldofpeace@protonmail.ch>
+
+This fixes issues for users of mutter like in gala[0].
+
+Upstream report: https://gitlab.gnome.org/GNOME/mutter/issues/536
+[0]: https://github.com/elementary/gala/issues/605
+---
+ clutter/clutter/clutter-actor.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c
+index ecf9a59..07b8b71 100644
+--- a/clutter/clutter/clutter-actor.c
++++ b/clutter/clutter/clutter-actor.c
+@@ -17831,7 +17831,7 @@ _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
+   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
+     {
+       priv->paint_volume_valid = TRUE;
+-      priv->needs_paint_volume_update = FALSE;
++      //priv->needs_paint_volume_update = FALSE;
+       return &priv->paint_volume;
+     }
+   else
+-- 
+git-series 0.9.1
diff --git a/pkgs/desktops/gnome/core/mutter/3.34/0004-profiler-track-changes-in-GLib-and-Sysprof.patch b/pkgs/desktops/gnome/core/mutter/3.34/0004-profiler-track-changes-in-GLib-and-Sysprof.patch
new file mode 100644
index 00000000000..cd98d395041
--- /dev/null
+++ b/pkgs/desktops/gnome/core/mutter/3.34/0004-profiler-track-changes-in-GLib-and-Sysprof.patch
@@ -0,0 +1,58 @@
+From 5a9f9fbaa1322b2ad0a52fcdd171d4f44d031918 Mon Sep 17 00:00:00 2001
+Message-Id: <5a9f9fbaa1322b2ad0a52fcdd171d4f44d031918.1601082838.git-series.worldofpeace@protonmail.ch>
+In-Reply-To: <7b94f980f2a099dd4b19b60c357cfcf5ff7ada6d.1601082838.git-series.worldofpeace@protonmail.ch>
+References: <7b94f980f2a099dd4b19b60c357cfcf5ff7ada6d.1601082838.git-series.worldofpeace@protonmail.ch>
+From: WORLDofPEACE <worldofpeace@protonmail.ch>
+Date: Wed, 30 Oct 2019 15:23:24 -0700
+Subject: [PATCH 4/7] profiler: track changes in GLib and Sysprof
+
+From: Christian Hergert <chergert@redhat.com>
+
+This tracks the changes to gdbus-codegen in terms of how GUnixFDList is
+done to use the UnixFD annotation.
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/908
+(cherry picked from commit 605171291993460f31d470a8143d6438d0c6169c)
+---
+ src/backends/meta-profiler.c | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+diff --git a/src/backends/meta-profiler.c b/src/backends/meta-profiler.c
+index 10d433a..0d62701 100644
+--- a/src/backends/meta-profiler.c
++++ b/src/backends/meta-profiler.c
+@@ -51,13 +51,12 @@ G_DEFINE_TYPE_WITH_CODE (MetaProfiler,
+ static gboolean
+ handle_start (MetaDBusSysprof3Profiler *dbus_profiler,
+               GDBusMethodInvocation    *invocation,
++              GUnixFDList              *fd_list,
+               GVariant                 *options,
+               GVariant                 *fd_variant)
+ {
+   MetaProfiler *profiler = META_PROFILER (dbus_profiler);
+   GMainContext *main_context = g_main_context_default ();
+-  GDBusMessage *message;
+-  GUnixFDList *fd_list;
+   const char *group_name;
+   int position;
+   int fd = -1;
+@@ -73,8 +72,6 @@ handle_start (MetaDBusSysprof3Profiler *dbus_profiler,
+ 
+   g_variant_get (fd_variant, "h", &position);
+ 
+-  message = g_dbus_method_invocation_get_message (invocation);
+-  fd_list = g_dbus_message_get_unix_fd_list (message);
+   if (fd_list)
+     fd = g_unix_fd_list_get (fd_list, position, NULL);
+ 
+@@ -98,7 +95,7 @@ handle_start (MetaDBusSysprof3Profiler *dbus_profiler,
+ 
+   g_debug ("Profiler running");
+ 
+-  meta_dbus_sysprof3_profiler_complete_start (dbus_profiler, invocation);
++  meta_dbus_sysprof3_profiler_complete_start (dbus_profiler, invocation, NULL);
+   return TRUE;
+ }
+ 
+-- 
+git-series 0.9.1
diff --git a/pkgs/desktops/gnome/core/mutter/3.34/0005-meta-Add-missing-display.h-to-meta-workspace-manager.h.patch b/pkgs/desktops/gnome/core/mutter/3.34/0005-meta-Add-missing-display.h-to-meta-workspace-manager.h.patch
new file mode 100644
index 00000000000..138970ddda0
--- /dev/null
+++ b/pkgs/desktops/gnome/core/mutter/3.34/0005-meta-Add-missing-display.h-to-meta-workspace-manager.h.patch
@@ -0,0 +1,32 @@
+From 2caa072dd8e283a8e43febeab55fe8b76dda69b7 Mon Sep 17 00:00:00 2001
+Message-Id: <2caa072dd8e283a8e43febeab55fe8b76dda69b7.1601082838.git-series.worldofpeace@protonmail.ch>
+In-Reply-To: <7b94f980f2a099dd4b19b60c357cfcf5ff7ada6d.1601082838.git-series.worldofpeace@protonmail.ch>
+References: <7b94f980f2a099dd4b19b60c357cfcf5ff7ada6d.1601082838.git-series.worldofpeace@protonmail.ch>
+From: WORLDofPEACE <worldofpeace@protonmail.ch>
+Date: Wed, 29 Jan 2020 11:02:33 +0100
+Subject: [PATCH 5/7] meta: Add missing display.h to meta-workspace-manager.h
+
+From: Corentin Noël <corentin@elementary.io>
+
+This is required because MetaDisplayCorner is only defined in display.h
+
+https://gitlab.gnome.org/GNOME/mutter/merge_requests/1025
+(cherry picked from commit 9d390ee49fb1f6300336e82ae94cc8061c6bae12)
+---
+ src/meta/meta-workspace-manager.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/meta/meta-workspace-manager.h b/src/meta/meta-workspace-manager.h
+index 0390c44..92cd681 100644
+--- a/src/meta/meta-workspace-manager.h
++++ b/src/meta/meta-workspace-manager.h
+@@ -26,6 +26,7 @@
+ #include <glib-object.h>
+ 
+ #include <meta/common.h>
++#include <meta/display.h>
+ #include <meta/prefs.h>
+ #include <meta/types.h>
+ 
+-- 
+git-series 0.9.1
diff --git a/pkgs/desktops/gnome/core/mutter/3.34/0006-build-bump-ABI-to-sysprof-capture-4.patch b/pkgs/desktops/gnome/core/mutter/3.34/0006-build-bump-ABI-to-sysprof-capture-4.patch
new file mode 100644
index 00000000000..6d88f0f5e76
--- /dev/null
+++ b/pkgs/desktops/gnome/core/mutter/3.34/0006-build-bump-ABI-to-sysprof-capture-4.patch
@@ -0,0 +1,102 @@
+From 0c95e5a5b31eab93f149b90982680f38e8977063 Mon Sep 17 00:00:00 2001
+Message-Id: <0c95e5a5b31eab93f149b90982680f38e8977063.1601082838.git-series.worldofpeace@protonmail.ch>
+In-Reply-To: <7b94f980f2a099dd4b19b60c357cfcf5ff7ada6d.1601082838.git-series.worldofpeace@protonmail.ch>
+References: <7b94f980f2a099dd4b19b60c357cfcf5ff7ada6d.1601082838.git-series.worldofpeace@protonmail.ch>
+From: WORLDofPEACE <worldofpeace@protonmail.ch>
+Date: Sat,  4 Jul 2020 12:01:28 -0700
+Subject: [PATCH 6/7] build: bump ABI to sysprof-capture-4
+
+From: Christian Hergert <chergert@redhat.com>
+
+GLib will now be linking against sysprof-capture-4.a. To support that,
+sysprof had to remove the GLib dependency from sysprof-capture-4 which
+had the side-effect of breaking ABi.
+
+This bumps the dependency and includes a fallback to compile just the
+libsysprof-capture-4.a using a subproject wrap.
+
+https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1352
+(cherry picked from commit 2c08eb6d163b6758efec9eafe1d5c17fc1ab3692)
+---
+ meson.build              | 20 ++++++++++++++++++--
+ src/meson.build          |  8 ++++++--
+ subprojects/sysprof.wrap |  4 ++++
+ 3 files changed, 28 insertions(+), 4 deletions(-)
+ create mode 100644 subprojects/sysprof.wrap
+
+diff --git a/meson.build b/meson.build
+index 86970df..3dc0098 100644
+--- a/meson.build
++++ b/meson.build
+@@ -1,6 +1,6 @@
+ project('mutter', 'c',
+   version: '3.34.6',
+-  meson_version: '>= 0.50.0',
++  meson_version: '>= 0.51.0',
+   license: 'GPLv2+'
+ )
+ 
+@@ -52,6 +52,9 @@ gbm_req = '>= 10.3'
+ # screen cast version requirements
+ libpipewire_req = '>= 0.2.5'
+ 
++# profiler requirements
++sysprof_req = '>= 3.37.2'
++
+ gnome = import('gnome')
+ pkg = import('pkgconfig')
+ i18n  = import('i18n')
+@@ -275,7 +278,20 @@ endif
+ 
+ have_profiler = get_option('profiler')
+ if have_profiler
+-  sysprof_dep = dependency('sysprof-capture-3')
++  # libsysprof-capture support
++  sysprof_dep = dependency('sysprof-capture-4',
++    required: true,
++    default_options: [
++      'enable_examples=false',
++      'enable_gtk=false',
++      'enable_tests=false',
++      'enable_tools=false',
++      'libsysprof=false',
++      'with_sysprofd=none',
++      'help=false',
++    ],
++    fallback: ['sysprof', 'libsysprof_capture_dep'],
++  )
+ endif
+ 
+ required_functions = [
+diff --git a/src/meson.build b/src/meson.build
+index a9fffa2..a91baa1 100644
+--- a/src/meson.build
++++ b/src/meson.build
+@@ -711,9 +711,13 @@ if have_profiler
+     'backends/meta-profiler.h',
+   ]
+ 
+-  dbus_interfaces_dir = join_paths(datadir, 'dbus-1', 'interfaces')
+-  sysprof3_dbus_file = join_paths(dbus_interfaces_dir, 'org.gnome.Sysprof3.Profiler.xml')
++  if sysprof_dep.type_name() == 'pkgconfig'
++    sysprof_dbus_interfaces_dir = join_paths(sysprof_dep.get_pkgconfig_variable('datadir'), 'dbus-1', 'interfaces')
++  else
++    sysprof_dbus_interfaces_dir = join_paths(meson.source_root(), 'subprojects', 'sysprof', 'src')
++  endif
+ 
++  sysprof3_dbus_file = join_paths(sysprof_dbus_interfaces_dir, 'org.gnome.Sysprof3.Profiler.xml')
+   dbus_sysprof3_profiler_built_sources = gnome.gdbus_codegen('meta-dbus-sysprof3-profiler',
+       sysprof3_dbus_file,
+       interface_prefix: 'org.gnome.',
+diff --git a/subprojects/sysprof.wrap b/subprojects/sysprof.wrap
+new file mode 100644
+index 0000000..c8f5883
+--- /dev/null
++++ b/subprojects/sysprof.wrap
+@@ -0,0 +1,4 @@
++[wrap-git]
++directory=sysprof
++url=https://gitlab.gnome.org/GNOME/sysprof.git
++revision=cae28263ff5dd4a510d82f3dc2e3a3b3d9b386fb
+-- 
+git-series 0.9.1
diff --git a/pkgs/desktops/gnome/core/mutter/3.34/0007-fix-paths.patch b/pkgs/desktops/gnome/core/mutter/3.34/0007-fix-paths.patch
new file mode 100644
index 00000000000..8376fc649b5
--- /dev/null
+++ b/pkgs/desktops/gnome/core/mutter/3.34/0007-fix-paths.patch
@@ -0,0 +1,27 @@
+From 7bbbf082599ec786f64f2135c9acc0b4fe2ecbf4 Mon Sep 17 00:00:00 2001
+Message-Id: <7bbbf082599ec786f64f2135c9acc0b4fe2ecbf4.1601082838.git-series.worldofpeace@protonmail.ch>
+In-Reply-To: <7b94f980f2a099dd4b19b60c357cfcf5ff7ada6d.1601082838.git-series.worldofpeace@protonmail.ch>
+References: <7b94f980f2a099dd4b19b60c357cfcf5ff7ada6d.1601082838.git-series.worldofpeace@protonmail.ch>
+From: WORLDofPEACE <worldofpeace@protonmail.ch>
+Date: Fri, 25 Sep 2020 20:48:33 -0400
+Subject: [PATCH 7/7] fix paths
+
+---
+ src/core/util.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/core/util.c b/src/core/util.c
+index 79bcfdc..87ce549 100644
+--- a/src/core/util.c
++++ b/src/core/util.c
+@@ -623,7 +623,7 @@ meta_show_dialog (const char *type,
+ 
+   args = g_ptr_array_new ();
+ 
+-  append_argument (args, "zenity");
++  append_argument (args, "@zenity@/bin/zenity");
+   append_argument (args, type);
+ 
+   if (display)
+-- 
+git-series 0.9.1
diff --git a/pkgs/desktops/gnome/core/mutter/3.34/default.nix b/pkgs/desktops/gnome/core/mutter/3.34/default.nix
new file mode 100644
index 00000000000..42f07d45e62
--- /dev/null
+++ b/pkgs/desktops/gnome/core/mutter/3.34/default.nix
@@ -0,0 +1,134 @@
+{ fetchurl
+, fetchpatch
+, substituteAll
+, lib, stdenv
+, pkg-config
+, gnome
+, pantheon
+, gettext
+, gobject-introspection
+, upower
+, cairo
+, pango
+, cogl
+, json-glib
+, libstartup_notification
+, zenity
+, libcanberra-gtk3
+, ninja
+, xkeyboard_config
+, libxkbfile
+, libxkbcommon
+, libXtst
+, libinput
+, gsettings-desktop-schemas
+, glib
+, gtk3
+, gnome-desktop
+, geocode-glib
+, pipewire_0_2
+, libgudev
+, libwacom
+, xwayland
+, meson
+, gnome-settings-daemon
+, xorgserver
+, python3
+, wrapGAppsHook
+, sysprof
+, desktop-file-utils
+, libcap_ng
+, egl-wayland
+}:
+
+stdenv.mkDerivation rec {
+  pname = "mutter";
+  version = "3.34.6";
+
+  outputs = [ "out" "dev" "man" ];
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/mutter/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    hash = "sha256-I73ofTO4mBNYgxzsiRW7X/Hq+cHedMkM0WYLG5WINSY=";
+  };
+
+  mesonFlags = [
+    "-Degl_device=true"
+    "-Dinstalled_tests=false" # TODO: enable these
+    "-Dwayland_eglstream=true"
+  ];
+
+  propagatedBuildInputs = [
+    # required for pkg-config to detect mutter-clutter
+    json-glib
+    libXtst
+    libcap_ng
+  ];
+
+  nativeBuildInputs = [
+    desktop-file-utils
+    gettext
+    meson
+    ninja
+    pkg-config
+    python3
+    wrapGAppsHook
+    xorgserver # for cvt command
+  ];
+
+  buildInputs = [
+    cairo
+    cogl
+    egl-wayland
+    geocode-glib
+    glib
+    gnome-desktop
+    gnome-settings-daemon
+    gobject-introspection
+    gsettings-desktop-schemas
+    gtk3
+    libcanberra-gtk3
+    libgudev
+    libinput
+    libstartup_notification
+    libwacom
+    libxkbcommon
+    libxkbfile
+    pango
+    pipewire_0_2 # TODO: backport pipewire 0.3 support
+    sysprof
+    upower
+    xkeyboard_config
+    xwayland
+    zenity
+  ];
+
+  patches = [
+    ./0001-EGL-Include-EGL-eglmesaext.h.patch
+    ./0002-drop-inheritable.patch
+    ./0003-Fix-glitches-in-gala.patch
+    ./0004-profiler-track-changes-in-GLib-and-Sysprof.patch
+    ./0005-meta-Add-missing-display.h-to-meta-workspace-manager.h.patch
+    ./0006-build-bump-ABI-to-sysprof-capture-4.patch
+    (substituteAll {
+      src = ./0007-fix-paths.patch;
+      inherit zenity;
+    })
+  ];
+
+  postPatch = ''
+    patchShebangs src/backends/native/gen-default-modes.py
+  '';
+
+  postInstall = ''
+    ${glib.dev}/bin/glib-compile-schemas "$out/share/glib-2.0/schemas"
+  '';
+
+  meta = with lib; {
+    description = "A window manager for GNOME";
+    homepage = "https://gitlab.gnome.org/GNOME/mutter";
+    license = licenses.gpl2;
+    maintainers = pantheon.maintainers;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/mutter/default.nix b/pkgs/desktops/gnome/core/mutter/default.nix
new file mode 100644
index 00000000000..9f6a64ef182
--- /dev/null
+++ b/pkgs/desktops/gnome/core/mutter/default.nix
@@ -0,0 +1,170 @@
+{ fetchurl
+, fetchpatch
+, substituteAll
+, runCommand
+, lib, stdenv
+, pkg-config
+, gnome
+, gettext
+, gobject-introspection
+, cairo
+, pango
+, json-glib
+, libstartup_notification
+, zenity
+, libcanberra
+, ninja
+, xkeyboard_config
+, libxkbfile
+, libXdamage
+, libxkbcommon
+, libXtst
+, libinput
+, libdrm
+, gsettings-desktop-schemas
+, glib
+, gtk3
+, gnome-desktop
+, pipewire
+, libgudev
+, libwacom
+, xwayland
+, mesa
+, meson
+, gnome-settings-daemon
+, xorgserver
+, python3
+, wrapGAppsHook
+, sysprof
+, desktop-file-utils
+, libcap_ng
+, egl-wayland
+, graphene
+, wayland-protocols
+}:
+
+let self = stdenv.mkDerivation rec {
+  pname = "mutter";
+  version = "40.0";
+
+  outputs = [ "out" "dev" "man" ];
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/mutter/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "sha256-enGzEuWmZ8U3SJUYilBqP2tnF2i8s2K2jv3FYnc9GY4=";
+  };
+
+  patches = [
+    # Drop inheritable cap_sys_nice, to prevent the ambient set from leaking
+    # from mutter/gnome-shell, see https://github.com/NixOS/nixpkgs/issues/71381
+    # ./drop-inheritable.patch
+
+    (substituteAll {
+      src = ./fix-paths.patch;
+      inherit zenity;
+    })
+
+    # Fix non-deterministic build failure:
+    # https://gitlab.gnome.org/GNOME/mutter/-/issues/1682
+    (fetchpatch {
+      url = "https://gitlab.gnome.org/GNOME/mutter/commit/91117bb052ed0d69c8ea4159c1df15c814d90627.patch";
+      sha256 = "ek8hEoPP4S2TGOm6SGGOhUVIp4OT68nz0SQzZrceFUU=";
+    })
+  ];
+
+  mesonFlags = [
+    "-Degl_device=true"
+    "-Dinstalled_tests=false" # TODO: enable these
+    "-Dwayland_eglstream=true"
+    "-Dprofiler=true"
+    "-Dxwayland_path=${xwayland}/bin/Xwayland"
+    # This should be auto detected, but it looks like it manages a false
+    # positive.
+    "-Dxwayland_initfd=disabled"
+  ];
+
+  propagatedBuildInputs = [
+    # required for pkg-config to detect mutter-clutter
+    json-glib
+    libXtst
+    libcap_ng
+    graphene
+  ];
+
+  nativeBuildInputs = [
+    desktop-file-utils
+    gettext
+    mesa # needed for gbm
+    meson
+    ninja
+    pkg-config
+    python3
+    wrapGAppsHook
+    xorgserver # for cvt command
+  ];
+
+  buildInputs = [
+    cairo
+    egl-wayland
+    glib
+    gnome-desktop
+    gnome-settings-daemon
+    gobject-introspection
+    gsettings-desktop-schemas
+    gtk3
+    libcanberra
+    libdrm
+    libgudev
+    libinput
+    libstartup_notification
+    libwacom
+    libxkbcommon
+    libxkbfile
+    libXdamage
+    pango
+    pipewire
+    sysprof
+    xkeyboard_config
+    xwayland
+    wayland-protocols
+  ];
+
+  postPatch = ''
+    patchShebangs src/backends/native/gen-default-modes.py
+  '';
+
+  postInstall = ''
+    ${glib.dev}/bin/glib-compile-schemas "$out/share/glib-2.0/schemas"
+  '';
+
+  # Install udev files into our own tree.
+  PKG_CONFIG_UDEV_UDEVDIR = "${placeholder "out"}/lib/udev";
+
+  passthru = {
+    libdir = "${self}/lib/mutter-7";
+
+    tests = {
+      libdirExists = runCommand "mutter-libdir-exists" {} ''
+        if [[ ! -d ${self.libdir} ]]; then
+          echo "passthru.libdir should contain a directory, “${self.libdir}” is not one."
+          exit 1
+        fi
+        touch $out
+      '';
+    };
+
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    description = "A window manager for GNOME";
+    homepage = "https://gitlab.gnome.org/GNOME/mutter";
+    license = licenses.gpl2Plus;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+};
+in self
diff --git a/pkgs/desktops/gnome/core/mutter/drop-inheritable.patch b/pkgs/desktops/gnome/core/mutter/drop-inheritable.patch
new file mode 100644
index 00000000000..7374e1b8693
--- /dev/null
+++ b/pkgs/desktops/gnome/core/mutter/drop-inheritable.patch
@@ -0,0 +1,132 @@
+From e9c772e265b2293af031c79f4bbc99b5847dfe3c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Tor=20Hedin=20Br=C3=B8nner?= <torhedinbronner@gmail.com>
+Date: Sat, 19 Oct 2019 13:26:05 +0200
+Subject: [PATCH] drop inheritable
+
+Adapted from https://gitlab.gnome.org/GNOME/mutter/commit/c53c47ae123b03cc66044d2b846342123ecb3a01
+
+We only want to drop inheritable though, to prevent the ambient set leaking further than gnome-shell.
+
+---
+ config.h.meson    |  3 +++
+ meson.build       |  5 +++++
+ meson_options.txt |  6 ++++++
+ src/core/main.c   | 11 +++++++++++
+ src/meson.build   |  1 +
+ 5 files changed, 26 insertions(+)
+
+diff --git a/config.h.meson b/config.h.meson
+index 0bab71848..202fb7ed1 100644
+--- a/config.h.meson
++++ b/config.h.meson
+@@ -58,6 +58,9 @@
+ /* Xwayland applications allowed to issue keyboard grabs */
+ #mesondefine XWAYLAND_GRAB_DEFAULT_ACCESS_RULES
+ 
++/* Defined if libcap-ng is available */
++#mesondefine HAVE_LIBCAPNG
++
+ /* XKB base prefix */
+ #mesondefine XKB_BASE
+ 
+diff --git a/meson.build b/meson.build
+index 3322bd3b1..01c8020fa 100644
+--- a/meson.build
++++ b/meson.build
+@@ -35,6 +35,7 @@ libstartup_notification_req = '>= 0.7'
+ libcanberra_req = '>= 0.26'
+ libwacom_req = '>= 0.13'
+ atk_req = '>= 2.5.3'
++libcapng_req = '>= 0.7.9'
+ 
+ # optional version requirements
+ udev_req = '>= 228'
+@@ -131,6 +131,7 @@ ice_dep = dependency('ice')
+ atk_dep = dependency('atk', version: atk_req)
+ libcanberra_dep = dependency('libcanberra', version: libcanberra_req)
+ dbus_dep = dependency('dbus-1')
++libcapng_dep = dependency('libcap-ng', required: get_option('libcapng'))
+
+ # For now always require X11 support
+ have_x11 = true
+@@ -256,6 +258,7 @@ have_core_tests = false
+ have_cogl_tests = false
+ have_clutter_tests = false
+ have_installed_tests = false
++have_libcapng = libcapng_dep.found()
+ 
+ if have_tests
+   have_core_tests = get_option('core_tests')
+@@ -361,6 +364,7 @@ cdata.set('HAVE_LIBWACOM', have_libwacom)
+ cdata.set('HAVE_SM', have_sm)
+ cdata.set('HAVE_STARTUP_NOTIFICATION', have_startup_notification)
+ cdata.set('HAVE_INTROSPECTION', have_introspection)
++cdata.set('HAVE_LIBCAPNG', have_libcapng)
+ cdata.set('HAVE_PROFILER', have_profiler)
+ 
+ xkb_base = xkeyboard_config_dep.get_pkgconfig_variable('xkb_base')
+@@ -465,6 +465,7 @@ output = [
+   '        Introspection............ ' + have_introspection.to_string(),
+   '        Profiler................. ' + have_profiler.to_string(),
+   '        Xwayland initfd.......... ' + have_xwayland_initfd.to_string(),
++  '        libcap-ng................ ' + have_libcapng.to_string(),
+   '',
+   '    Tests:',
+   '',
+diff --git a/meson_options.txt b/meson_options.txt
+index 73aa7adde..8bfaacd9a 100644
+--- a/meson_options.txt
++++ b/meson_options.txt
+@@ -152,3 +152,9 @@ option('xwayland_grab_default_access_rules',
+   value: 'gnome-boxes,remote-viewer,virt-viewer,virt-manager,vinagre,vncviewer,Xephyr',
+   description: 'Comma delimited list of applications ressources or class allowed to issue X11 grabs in Xwayland'
+ )
++
++option('libcapng',
++  type: 'feature',
++  value: 'auto',
++  description: 'Enable libcap-ng support'
++)
+diff --git a/src/core/main.c b/src/core/main.c
+index 7f4f666d2..b27968f13 100644
+--- a/src/core/main.c
++++ b/src/core/main.c
+@@ -66,6 +66,10 @@
+ #include <girepository.h>
+ #endif
+ 
++#ifdef HAVE_LIBCAPNG
++#include <cap-ng.h>
++#endif
++
+ #if defined(HAVE_NATIVE_BACKEND) && defined(HAVE_WAYLAND)
+ #include <systemd/sd-login.h>
+ #endif /* HAVE_WAYLAND && HAVE_NATIVE_BACKEND */
+@@ -670,5 +674,12 @@ int
+ meta_run (void)
+ {
+   meta_start ();
++
++#ifdef HAVE_LIBCAPNG
++  capng_clear(CAPNG_SELECT_BOTH);
++  capng_update(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, CAP_SYS_NICE);
++  capng_apply(CAPNG_SELECT_BOTH);
++#endif
++
+   meta_run_main_loop ();
+   meta_finalize ();
+diff --git a/src/meson.build b/src/meson.build
+index 90d80734f..a9fffa2c2 100644
+--- a/src/meson.build
++++ b/src/meson.build
+@@ -18,6 +18,7 @@ mutter_pkg_deps = [
+   glib_dep,
+   gsettings_desktop_schemas_dep,
+   gtk3_dep,
++  libcapng_dep,
+   pango_dep,
+ ]
+ 
+-- 
+2.23.0
+
diff --git a/pkgs/desktops/gnome/core/mutter/fix-paths.patch b/pkgs/desktops/gnome/core/mutter/fix-paths.patch
new file mode 100644
index 00000000000..6ac0a431f61
--- /dev/null
+++ b/pkgs/desktops/gnome/core/mutter/fix-paths.patch
@@ -0,0 +1,13 @@
+diff --git a/src/core/util.c b/src/core/util.c
+index 57b73747d..f424cc81c 100644
+--- a/src/core/util.c
++++ b/src/core/util.c
+@@ -636,7 +636,7 @@ meta_show_dialog (const char *type,
+ 
+   args = g_ptr_array_new ();
+ 
+-  append_argument (args, "zenity");
++  append_argument (args, "@zenity@/bin/zenity");
+   append_argument (args, type);
+ 
+   if (display)
diff --git a/pkgs/desktops/gnome/core/nautilus/default.nix b/pkgs/desktops/gnome/core/nautilus/default.nix
new file mode 100644
index 00000000000..f3ccdbce98c
--- /dev/null
+++ b/pkgs/desktops/gnome/core/nautilus/default.nix
@@ -0,0 +1,118 @@
+{ lib, stdenv
+, fetchurl
+, meson
+, ninja
+, pkg-config
+, gettext
+, libxml2
+, desktop-file-utils
+, python3
+, wrapGAppsHook
+, gtk3
+, libhandy
+, libportal
+, gnome
+, gnome-autoar
+, glib-networking
+, shared-mime-info
+, libnotify
+, libexif
+, libseccomp
+, exempi
+, librsvg
+, tracker
+, tracker-miners
+, gexiv2
+, libselinux
+, gdk-pixbuf
+, substituteAll
+, gnome-desktop
+, gst_all_1
+, gsettings-desktop-schemas
+, gobject-introspection
+}:
+
+stdenv.mkDerivation rec {
+  pname = "nautilus";
+  version = "40.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "0cwxr7bfa19dvzra81s9wfshzv0zv7ycpfffn4amigd0fh0vkkwf";
+  };
+
+  patches = [
+    # Allow changing extension directory using environment variable.
+    ./extension_dir.patch
+
+    # Hardcode required paths.
+    (substituteAll {
+      src = ./fix-paths.patch;
+      inherit tracker;
+    })
+  ];
+
+  nativeBuildInputs = [
+    desktop-file-utils
+    gettext
+    gobject-introspection
+    libxml2
+    meson
+    ninja
+    pkg-config
+    python3
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    exempi
+    gexiv2
+    glib-networking
+    gnome-desktop
+    gnome.adwaita-icon-theme
+    gsettings-desktop-schemas
+    gst_all_1.gst-plugins-base
+    gtk3
+    libhandy
+    libportal
+    libexif
+    libnotify
+    libseccomp
+    libselinux
+    shared-mime-info
+    tracker
+    tracker-miners
+  ];
+
+  propagatedBuildInputs = [
+    gnome-autoar
+  ];
+
+  preFixup = ''
+    gappsWrapperArgs+=(
+      # Thumbnailers
+      --prefix XDG_DATA_DIRS : "${gdk-pixbuf}/share"
+      --prefix XDG_DATA_DIRS : "${librsvg}/share"
+      --prefix XDG_DATA_DIRS : "${shared-mime-info}/share"
+    )
+  '';
+
+  postPatch = ''
+    patchShebangs build-aux/meson/postinstall.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    description = "The file manager for GNOME";
+    homepage = "https://wiki.gnome.org/Apps/Files";
+    license = licenses.gpl3Plus;
+    platforms = platforms.linux;
+    maintainers = teams.gnome.members;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/nautilus/extension_dir.patch b/pkgs/desktops/gnome/core/nautilus/extension_dir.patch
new file mode 100644
index 00000000000..e1313999675
--- /dev/null
+++ b/pkgs/desktops/gnome/core/nautilus/extension_dir.patch
@@ -0,0 +1,24 @@
+diff --git a/src/nautilus-module.c b/src/nautilus-module.c
+index 6273a76..4adcc8a 100644
+--- a/src/nautilus-module.c
++++ b/src/nautilus-module.c
+@@ -242,11 +242,17 @@ void
+ nautilus_module_setup (void)
+ {
+     static gboolean initialized = FALSE;
++    const gchar* extensiondir = NULL;
+ 
+     if (!initialized)
+     {
+         initialized = TRUE;
+ 
+-        load_module_dir (NAUTILUS_EXTENSIONDIR);
++        extensiondir = g_getenv ("NAUTILUS_EXTENSION_DIR");
++        if (extensiondir == NULL) {
++            extensiondir = NAUTILUS_EXTENSIONDIR;
++        }
++
++        load_module_dir (extensiondir);
+ 
+         eel_debug_call_at_shutdown (free_module_objects);
+     }
diff --git a/pkgs/desktops/gnome/core/nautilus/fix-paths.patch b/pkgs/desktops/gnome/core/nautilus/fix-paths.patch
new file mode 100644
index 00000000000..dc9874359b2
--- /dev/null
+++ b/pkgs/desktops/gnome/core/nautilus/fix-paths.patch
@@ -0,0 +1,13 @@
+diff --git a/src/nautilus-tag-manager.c b/src/nautilus-tag-manager.c
+index 28b96c996..0b1fad9ab 100644
+--- a/src/nautilus-tag-manager.c
++++ b/src/nautilus-tag-manager.c
+@@ -962,7 +962,7 @@ child_watch_cb (GPid     pid,
+ static void
+ export_tracker2_data (NautilusTagManager *self)
+ {
+-    gchar *argv[] = {"tracker3", "export", "--2to3", "files-starred", "--keyfile", NULL};
++    gchar *argv[] = {"@tracker@/bin/tracker3", "export", "--2to3", "files-starred", "--keyfile", NULL};
+     gint stdout_fd;
+     GPid child_pid;
+     g_autoptr (GError) error = NULL;
diff --git a/pkgs/desktops/gnome/core/rygel/add-option-for-installation-sysconfdir.patch b/pkgs/desktops/gnome/core/rygel/add-option-for-installation-sysconfdir.patch
new file mode 100644
index 00000000000..6fe651b9cbb
--- /dev/null
+++ b/pkgs/desktops/gnome/core/rygel/add-option-for-installation-sysconfdir.patch
@@ -0,0 +1,38 @@
+diff --git a/meson.build b/meson.build
+index 4aa683d6..a930d533 100644
+--- a/meson.build
++++ b/meson.build
+@@ -20,7 +20,11 @@ if not get_option('uninstalled')
+     rygel_datadir = join_paths(get_option('prefix'), get_option('datadir'), 'rygel')
+     rygel_libexecdir = join_paths(get_option('prefix'), get_option('libexecdir'),
+     'rygel')
+-    rygel_sysconfdir = join_paths(get_option('prefix'), get_option('sysconfdir'))
++    if get_option('sysconfdir_install') != ''
++        rygel_sysconfdir = join_paths(get_option('prefix'), get_option('sysconfdir_install'))
++    else
++        rygel_sysconfdir = join_paths(get_option('prefix'), get_option('sysconfdir'))
++    endif
+     rygel_plugindir = join_paths(rygel_libdir, 'rygel-2.6', 'plugins')
+     rygel_enginedir = join_paths(rygel_libdir, 'rygel-2.6', 'engines')
+     rygel_presetdir = join_paths(rygel_datadir, 'presets')
+@@ -55,7 +59,7 @@ conf.set_quoted('DATA_DIR', rygel_datadir)
+ conf.set_quoted('PLUGIN_DIR', rygel_plugindir)
+ conf.set_quoted('BIG_ICON_DIR', rygel_bigicondir)
+ conf.set_quoted('SMALL_ICON_DIR', rygel_smallicondir)
+-conf.set_quoted('SYS_CONFIG_DIR', rygel_sysconfdir)
++conf.set_quoted('SYS_CONFIG_DIR', get_option('sysconfdir'))
+ conf.set_quoted('LOCALEDIR', join_paths(get_option('prefix'), get_option('localedir')))
+ conf.set_quoted('MX_EXTRACT_PATH', join_paths(rygel_libexecdir, 'mx-extract'))
+ conf.set_quoted('DESKTOP_DIR', join_paths(get_option('prefix'), get_option('datadir'), 'applications'))
+diff --git a/meson_options.txt b/meson_options.txt
+index cb604c4e..1b049b77 100644
+--- a/meson_options.txt
++++ b/meson_options.txt
+@@ -1,6 +1,7 @@
+ option('uninstalled', type: 'boolean', value: 'false', description: 'Run Rygel from build directory only')
+ option('api-docs', type: 'boolean', value: 'false', description: 'Build the API documentation')
+ option('systemd-user-units-dir', type : 'string', value : 'auto', description : 'Where to install the systemd user unit (use special values "auto" or "none", or pass a path')
++option('sysconfdir_install', type: 'string', value: '', description: 'sysconfdir to use during installation')
+ option('plugins', type : 'array', choices : ['external', 'gst-launch', 'lms', 'media-export', 'mpris', 'playbin', 'ruih', 'tracker', 'tracker3'])
+ option('engines', type : 'array', choices : ['simple', 'gstreamer'])
+ option('examples', type : 'boolean', value : 'true')
diff --git a/pkgs/desktops/gnome/core/rygel/default.nix b/pkgs/desktops/gnome/core/rygel/default.nix
new file mode 100644
index 00000000000..f43df23f44a
--- /dev/null
+++ b/pkgs/desktops/gnome/core/rygel/default.nix
@@ -0,0 +1,110 @@
+{ lib, stdenv
+, fetchurl
+, meson
+, ninja
+, pkg-config
+, vala
+, gettext
+, libxml2
+, gobject-introspection
+, wrapGAppsHook
+, python3
+, glib
+, gssdp
+, gupnp
+, gupnp-av
+, gupnp-dlna
+, gst_all_1
+, libgee
+, libsoup
+, gtk3
+, libmediaart
+, sqlite
+, systemd
+, tracker
+, shared-mime-info
+, gnome
+}:
+
+stdenv.mkDerivation rec {
+  pname = "rygel";
+  version = "0.40.1";
+
+  # TODO: split out lib
+  outputs = [ "out" "dev" ];
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "QkDXd1mcjNCeZ9pEzLOV0KbceEedgJzWIZgixbVooy0=";
+  };
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    pkg-config
+    vala
+    gettext
+    libxml2
+    gobject-introspection
+    wrapGAppsHook
+    python3
+  ];
+
+  buildInputs = [
+    glib
+    gssdp
+    gupnp
+    gupnp-av
+    gupnp-dlna
+    libgee
+    libsoup
+    gtk3
+    libmediaart
+    sqlite
+    systemd
+    tracker
+    shared-mime-info
+  ] ++ (with gst_all_1; [
+    gstreamer
+    gst-editing-services
+    gst-plugins-base
+    gst-plugins-good
+    gst-plugins-bad
+    gst-plugins-ugly
+  ]);
+
+  mesonFlags = [
+    "-Dsystemd-user-units-dir=${placeholder "out"}/lib/systemd/user"
+    "-Dapi-docs=false"
+    "--sysconfdir=/etc"
+    "-Dsysconfdir_install=${placeholder "out"}/etc"
+    # Build all plug-ins except for tracker 2
+    "-Dplugins=external,gst-launch,lms,media-export,mpris,playbin,ruih,tracker3"
+  ];
+
+  doCheck = true;
+
+  patches = [
+    ./add-option-for-installation-sysconfdir.patch
+  ];
+
+  postPatch = ''
+    patchShebangs data/xml/process-xml.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+      versionPolicy = "odd-unstable";
+    };
+  };
+
+  meta = with lib; {
+    description = "A home media solution (UPnP AV MediaServer) that allows you to easily share audio, video and pictures to other devices";
+    homepage = "https://wiki.gnome.org/Projects/Rygel";
+    license = licenses.lgpl21Plus;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/simple-scan/default.nix b/pkgs/desktops/gnome/core/simple-scan/default.nix
new file mode 100644
index 00000000000..91ac4f14b22
--- /dev/null
+++ b/pkgs/desktops/gnome/core/simple-scan/default.nix
@@ -0,0 +1,89 @@
+{ lib, stdenv
+, fetchurl
+, meson
+, ninja
+, pkg-config
+, gettext
+, itstool
+, python3
+, wrapGAppsHook
+, cairo
+, gdk-pixbuf
+, colord
+, glib
+, gtk3
+, gusb
+, packagekit
+, libhandy
+, libwebp
+, libxml2
+, sane-backends
+, vala
+, gnome
+, gobject-introspection
+}:
+
+stdenv.mkDerivation rec {
+  pname = "simple-scan";
+  version = "40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "sha256-E4EbsqhhnmOkP8Lva3E1ny1cQITG1cizqtYXJLIHUa8=";
+  };
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    gettext
+    itstool
+    pkg-config
+    python3
+    wrapGAppsHook
+    libxml2
+    gobject-introspection # For setup hook
+  ];
+
+  buildInputs = [
+    cairo
+    gdk-pixbuf
+    colord
+    glib
+    gnome.adwaita-icon-theme
+    gusb
+    gtk3
+    libhandy
+    libwebp
+    packagekit
+    sane-backends
+    vala
+  ];
+
+  postPatch = ''
+    patchShebangs data/meson_compile_gschema.py
+  '';
+
+  doCheck = true;
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "simple-scan";
+    };
+  };
+
+  meta = with lib; {
+    description = "Simple scanning utility";
+    longDescription = ''
+      A really easy way to scan both documents and photos. You can crop out the
+      bad parts of a photo and rotate it if it is the wrong way round. You can
+      print your scans, export them to pdf, or save them in a range of image
+      formats. Basically a frontend for SANE - which is the same backend as
+      XSANE uses. This means that all existing scanners will work and the
+      interface is well tested.
+    '';
+    homepage = "https://gitlab.gnome.org/GNOME/simple-scan";
+    license = licenses.gpl3Plus;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/sushi/default.nix b/pkgs/desktops/gnome/core/sushi/default.nix
new file mode 100644
index 00000000000..c42b6964bf6
--- /dev/null
+++ b/pkgs/desktops/gnome/core/sushi/default.nix
@@ -0,0 +1,83 @@
+{ lib, stdenv
+, fetchurl
+, pkg-config
+, meson
+, gettext
+, gobject-introspection
+, glib
+, gnome
+, gtksourceview4
+, gjs
+, webkitgtk
+, libmusicbrainz5
+, icu
+, wrapGAppsHook
+, gst_all_1
+, gdk-pixbuf
+, librsvg
+, gtk3
+, harfbuzz
+, ninja
+, epoxy
+}:
+
+stdenv.mkDerivation rec {
+  pname = "sushi";
+  version = "3.38.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/sushi/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "0vlqqk916dymv4asbyvalp1m096a5hh99nx23i4xavzvgygh4h2h";
+  };
+
+  nativeBuildInputs = [
+    pkg-config
+    meson
+    ninja
+    gettext
+    gobject-introspection
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    glib
+    gtk3
+    gnome.evince
+    icu
+    harfbuzz
+    gjs
+    gtksourceview4
+    gdk-pixbuf
+    librsvg
+    libmusicbrainz5
+    webkitgtk
+    epoxy
+    gst_all_1.gstreamer
+    gst_all_1.gst-plugins-base
+    gst_all_1.gst-plugins-good
+  ];
+
+  # See https://github.com/NixOS/nixpkgs/issues/31168
+  postInstall = ''
+    for file in $out/libexec/org.gnome.NautilusPreviewer
+    do
+      sed -e $"2iimports.package._findEffectiveEntryPointName = () => \'$(basename $file)\' " \
+        -i $file
+    done
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "sushi";
+      attrPath = "gnome.sushi";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://en.wikipedia.org/wiki/Sushi_(software)";
+    description = "A quick previewer for Nautilus";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/totem/default.nix b/pkgs/desktops/gnome/core/totem/default.nix
new file mode 100644
index 00000000000..f7541fe12ed
--- /dev/null
+++ b/pkgs/desktops/gnome/core/totem/default.nix
@@ -0,0 +1,123 @@
+{ lib, stdenv
+, fetchurl
+, meson
+, ninja
+, gettext
+, gst_all_1
+, clutter-gtk
+, clutter-gst
+, python3Packages
+, shared-mime-info
+, pkg-config
+, gtk3
+, glib
+, gobject-introspection
+, totem-pl-parser
+, wrapGAppsHook
+, itstool
+, libxml2
+, vala
+, gnome
+, grilo
+, grilo-plugins
+, libpeas
+, adwaita-icon-theme
+, gnome-desktop
+, gsettings-desktop-schemas
+, gdk-pixbuf
+, xvfb_run
+}:
+
+stdenv.mkDerivation rec {
+  pname = "totem";
+  version = "3.38.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/totem/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "0bs33ijvxbr2prb9yj4dxglsszslsn9k258n311sld84masz4ad8";
+  };
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    vala
+    pkg-config
+    gettext
+    python3Packages.python
+    itstool
+    gobject-introspection
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    gtk3
+    glib
+    grilo
+    clutter-gtk
+    clutter-gst
+    totem-pl-parser
+    grilo-plugins
+    gst_all_1.gstreamer
+    gst_all_1.gst-plugins-base
+    gst_all_1.gst-plugins-good
+    gst_all_1.gst-plugins-bad
+    gst_all_1.gst-plugins-ugly
+    gst_all_1.gst-libav
+    libpeas
+    shared-mime-info
+    gdk-pixbuf
+    libxml2
+    adwaita-icon-theme
+    gnome-desktop
+    gsettings-desktop-schemas
+    # for plug-ins
+    python3Packages.pygobject3
+    python3Packages.dbus-python
+  ];
+
+  checkInputs = [
+    xvfb_run
+  ];
+
+  mesonFlags = [
+    # TODO: https://github.com/NixOS/nixpkgs/issues/36468
+    "-Dc_args=-I${glib.dev}/include/gio-unix-2.0"
+  ];
+
+  # Tests do not work with GStreamer 1.18.
+  # https://gitlab.gnome.org/GNOME/totem/-/issues/450
+  doCheck = false;
+
+  postPatch = ''
+    chmod +x meson_compile_python.py meson_post_install.py # patchShebangs requires executable file
+    patchShebangs \
+      ./meson_compile_python.py \
+      ./meson_post_install.py
+  '';
+
+  checkPhase = ''
+    runHook preCheck
+
+    xvfb-run -s '-screen 0 800x600x24' \
+      ninja test
+
+    runHook postCheck
+  '';
+
+  wrapPrefixVariables = [ "PYTHONPATH" ];
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "totem";
+      attrPath = "gnome.totem";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Videos";
+    description = "Movie player for the GNOME desktop based on GStreamer";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2Plus; # with exception to allow use of non-GPL compatible plug-ins
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/yelp-xsl/default.nix b/pkgs/desktops/gnome/core/yelp-xsl/default.nix
new file mode 100644
index 00000000000..7c9b4eb839c
--- /dev/null
+++ b/pkgs/desktops/gnome/core/yelp-xsl/default.nix
@@ -0,0 +1,52 @@
+{ lib, stdenv
+, gettext
+, fetchurl
+, pkg-config
+, itstool
+, libxml2
+, libxslt
+, gnome
+}:
+
+stdenv.mkDerivation rec {
+  pname = "yelp-xsl";
+  version = "40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/yelp-xsl/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "sha256-Nh7NTTP8zbO7CKaH9g5cPpCdLp47Ai2ETgSYINDPYrA=";
+  };
+
+  nativeBuildInputs = [
+    pkg-config
+    gettext
+    itstool
+    libxml2
+    libxslt
+  ];
+
+  doCheck = true;
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Yelp";
+    description = "Yelp's universal stylesheets for Mallard and DocBook";
+    maintainers = teams.gnome.members;
+    license = with licenses; [
+      # See https://gitlab.gnome.org/GNOME/yelp-xsl/blob/master/COPYING
+      # Stylesheets
+      lgpl2Plus
+      # Icons, unclear: https://gitlab.gnome.org/GNOME/yelp-xsl/issues/25
+      gpl2
+      # highlight.js
+      bsd3
+    ];
+    platforms = platforms.unix;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/yelp/default.nix b/pkgs/desktops/gnome/core/yelp/default.nix
new file mode 100644
index 00000000000..f4df80f5611
--- /dev/null
+++ b/pkgs/desktops/gnome/core/yelp/default.nix
@@ -0,0 +1,36 @@
+{ lib, stdenv, gettext, fetchurl, webkitgtk, pkg-config, gtk3, glib
+, gnome, sqlite
+, itstool, libxml2, libxslt, gst_all_1
+, wrapGAppsHook }:
+
+stdenv.mkDerivation rec {
+  pname = "yelp";
+  version = "40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/yelp/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "sha256-B3dfoGzSg2Xs2Cm7FqhaaCiXqyHYzONFlrvvXNRVquA=";
+  };
+
+  nativeBuildInputs = [ pkg-config gettext itstool wrapGAppsHook ];
+  buildInputs = [
+    gtk3 glib webkitgtk sqlite
+    libxml2 libxslt gnome.yelp-xsl
+    gnome.adwaita-icon-theme
+    gst_all_1.gst-plugins-base gst_all_1.gst-plugins-good
+  ];
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "yelp";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Yelp";
+    description = "The help viewer in Gnome";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/core/zenity/default.nix b/pkgs/desktops/gnome/core/zenity/default.nix
new file mode 100644
index 00000000000..51ad81a77a4
--- /dev/null
+++ b/pkgs/desktops/gnome/core/zenity/default.nix
@@ -0,0 +1,50 @@
+{ lib, stdenv
+, fetchurl
+, pkg-config
+, libxml2
+, gnome
+, gtk3
+, yelp-tools
+, gettext
+, libX11
+, itstool
+, wrapGAppsHook
+}:
+
+stdenv.mkDerivation rec {
+  pname = "zenity";
+  version = "3.32.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/zenity/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "15fdh8xfdhnwcynyh4byx3mrjxbyprqnwxzi7qn3g5wwaqryg1p7";
+  };
+
+  nativeBuildInputs = [
+    pkg-config
+    gettext
+    yelp-tools
+    itstool
+    libxml2
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    gtk3
+    libX11
+  ];
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "zenity";
+      attrPath = "gnome.zenity";
+    };
+  };
+
+  meta = with lib; {
+    description = "Tool to display dialogs from the commandline and shell scripts";
+    homepage = "https://wiki.gnome.org/Projects/Zenity";
+    platforms = platforms.linux;
+    maintainers = teams.gnome.members;
+  };
+}
diff --git a/pkgs/desktops/gnome/default.nix b/pkgs/desktops/gnome/default.nix
new file mode 100644
index 00000000000..b529a65026d
--- /dev/null
+++ b/pkgs/desktops/gnome/default.nix
@@ -0,0 +1,366 @@
+{ config, pkgs, lib }:
+
+lib.makeScope pkgs.newScope (self: with self; {
+  updateScript = callPackage ./update.nix { };
+
+  /* Remove packages of packagesToRemove from packages, based on their names
+
+     Type:
+       removePackagesByName :: [package] -> [package] -> [package]
+
+     Example:
+       removePackagesByName [ nautilus file-roller ] [ file-roller totem ]
+       => [ nautilus ]
+  */
+  removePackagesByName = packages: packagesToRemove:
+    let
+      namesToRemove = map lib.getName packagesToRemove;
+    in
+      lib.filter (x: !(builtins.elem (lib.getName x) namesToRemove)) packages;
+
+  libsoup = pkgs.libsoup.override { gnomeSupport = true; };
+  libchamplain = pkgs.libchamplain.override { libsoup = libsoup; };
+
+# ISO installer
+# installerIso = callPackage ./installer.nix {};
+
+#### Core (http://ftp.acc.umu.se/pub/GNOME/core/)
+
+  adwaita-icon-theme = callPackage ./core/adwaita-icon-theme { };
+
+  baobab = callPackage ./core/baobab { };
+
+  caribou = callPackage ./core/caribou { };
+
+  dconf-editor = callPackage ./core/dconf-editor { };
+
+  empathy = callPackage ./core/empathy { };
+
+  epiphany = callPackage ./core/epiphany { };
+
+  evince = callPackage ./core/evince { }; # ToDo: dbus would prevent compilation, enable tests
+
+  evolution-data-server = callPackage ./core/evolution-data-server { };
+
+  gdm = callPackage ./core/gdm { };
+
+  gnome-backgrounds = callPackage ./core/gnome-backgrounds { };
+
+  gnome-bluetooth = callPackage ./core/gnome-bluetooth { };
+
+  gnome-color-manager = callPackage ./core/gnome-color-manager { };
+
+  gnome-contacts = callPackage ./core/gnome-contacts { };
+
+  gnome-control-center = callPackage ./core/gnome-control-center { };
+
+  gnome-calculator = callPackage ./core/gnome-calculator { };
+
+  gnome-common = callPackage ./core/gnome-common { };
+
+  gnome-desktop = callPackage ./core/gnome-desktop { };
+
+  gnome-dictionary = callPackage ./core/gnome-dictionary { };
+
+  gnome-disk-utility = callPackage ./core/gnome-disk-utility { };
+
+  gnome-font-viewer = callPackage ./core/gnome-font-viewer { };
+
+  gnome-keyring = callPackage ./core/gnome-keyring { };
+
+  libgnome-keyring = callPackage ./core/libgnome-keyring { };
+
+  gnome-initial-setup = callPackage ./core/gnome-initial-setup { };
+
+  gnome-online-miners = callPackage ./core/gnome-online-miners { };
+
+  gnome-remote-desktop = callPackage ./core/gnome-remote-desktop { };
+
+  gnome-session = callPackage ./core/gnome-session { };
+
+  gnome-session-ctl = callPackage ./core/gnome-session/ctl.nix { };
+
+  gnome-shell = callPackage ./core/gnome-shell { };
+
+  gnome-shell-extensions = callPackage ./core/gnome-shell-extensions { };
+
+  gnome-screenshot = callPackage ./core/gnome-screenshot { };
+
+  gnome-settings-daemon = callPackage ./core/gnome-settings-daemon { };
+
+  gnome-software = callPackage ./core/gnome-software { };
+
+  gnome-system-monitor = callPackage ./core/gnome-system-monitor { };
+
+  gnome-terminal = callPackage ./core/gnome-terminal { };
+
+  gnome-themes-extra = callPackage ./core/gnome-themes-extra { };
+
+  gnome-user-share = callPackage ./core/gnome-user-share { };
+
+  gucharmap = callPackage ./core/gucharmap { };
+
+  gvfs = pkgs.gvfs.override { gnomeSupport = true; };
+
+  eog = callPackage ./core/eog { };
+
+  mutter = callPackage ./core/mutter { };
+
+  # Needed for elementary's gala and greeter until 3.36 support has more bugfixes
+  # https://github.com/elementary/gala/issues/763
+  mutter334 = callPackage ./core/mutter/3.34 { };
+
+  nautilus = callPackage ./core/nautilus { };
+
+  networkmanager-openvpn = pkgs.networkmanager-openvpn.override {
+    withGnome = true;
+  };
+
+  networkmanager-vpnc = pkgs.networkmanager-vpnc.override {
+    withGnome = true;
+  };
+
+  networkmanager-openconnect = pkgs.networkmanager-openconnect.override {
+    withGnome = true;
+  };
+
+  networkmanager-fortisslvpn = pkgs.networkmanager-fortisslvpn.override {
+    withGnome = true;
+  };
+
+  networkmanager-l2tp = pkgs.networkmanager-l2tp.override {
+    withGnome = true;
+  };
+
+  networkmanager-iodine = pkgs.networkmanager-iodine.override {
+    withGnome = true;
+  };
+
+  rygel = callPackage ./core/rygel { };
+
+  simple-scan = callPackage ./core/simple-scan { };
+
+  sushi = callPackage ./core/sushi { };
+
+  totem = callPackage ./core/totem { };
+
+  yelp = callPackage ./core/yelp { };
+
+  yelp-xsl = callPackage ./core/yelp-xsl { };
+
+  zenity = callPackage ./core/zenity { };
+
+
+#### Apps (http://ftp.acc.umu.se/pub/GNOME/apps/)
+
+  accerciser = callPackage ./apps/accerciser { };
+
+  cheese = callPackage ./apps/cheese { };
+
+  file-roller = callPackage ./apps/file-roller { };
+
+  gedit = callPackage ./apps/gedit { };
+
+  ghex = callPackage ./apps/ghex { };
+
+  gnome-books = callPackage ./apps/gnome-books { };
+
+  gnome-boxes = callPackage ./apps/gnome-boxes { };
+
+  gnome-calendar = callPackage ./apps/gnome-calendar { };
+
+  gnome-characters = callPackage ./apps/gnome-characters { };
+
+  gnome-clocks = callPackage ./apps/gnome-clocks { };
+
+  gnome-documents = callPackage ./apps/gnome-documents { };
+
+  gnome-logs = callPackage ./apps/gnome-logs { };
+
+  gnome-maps = callPackage ./apps/gnome-maps { };
+
+  gnome-music = callPackage ./apps/gnome-music { };
+
+  gnome-nettool = callPackage ./apps/gnome-nettool { };
+
+  gnome-notes = callPackage ./apps/gnome-notes { };
+
+  gnome-power-manager = callPackage ./apps/gnome-power-manager { };
+
+  gnome-sound-recorder = callPackage ./apps/gnome-sound-recorder { };
+
+  gnome-todo = callPackage ./apps/gnome-todo {};
+
+  gnome-weather = callPackage ./apps/gnome-weather { };
+
+  polari = callPackage ./apps/polari { };
+
+  seahorse = callPackage ./apps/seahorse { };
+
+  vinagre = callPackage ./apps/vinagre { };
+
+#### Dev http://ftp.gnome.org/pub/GNOME/devtools/
+
+  anjuta = callPackage ./devtools/anjuta { };
+
+  devhelp = callPackage ./devtools/devhelp { };
+
+  gnome-devel-docs = callPackage ./devtools/gnome-devel-docs { };
+
+#### Games
+
+  aisleriot = callPackage ./games/aisleriot { };
+
+  atomix = callPackage ./games/atomix { };
+
+  five-or-more = callPackage ./games/five-or-more { };
+
+  four-in-a-row = callPackage ./games/four-in-a-row { };
+
+  gnome-chess = callPackage ./games/gnome-chess { };
+
+  gnome-klotski = callPackage ./games/gnome-klotski { };
+
+  gnome-mahjongg = callPackage ./games/gnome-mahjongg { };
+
+  gnome-mines = callPackage ./games/gnome-mines { };
+
+  gnome-nibbles = callPackage ./games/gnome-nibbles { };
+
+  gnome-robots = callPackage ./games/gnome-robots { };
+
+  gnome-sudoku = callPackage ./games/gnome-sudoku { };
+
+  gnome-taquin = callPackage ./games/gnome-taquin { };
+
+  gnome-tetravex = callPackage ./games/gnome-tetravex { };
+
+  hitori = callPackage ./games/hitori { };
+
+  iagno = callPackage ./games/iagno { };
+
+  lightsoff = callPackage ./games/lightsoff { };
+
+  swell-foop = callPackage ./games/swell-foop { };
+
+  tali = callPackage ./games/tali { };
+
+  quadrapassel = callPackage ./games/quadrapassel { };
+
+#### Misc -- other packages on http://ftp.gnome.org/pub/GNOME/sources/
+
+  geary = callPackage ./misc/geary { };
+
+  gitg = callPackage ./misc/gitg { };
+
+  libgnome-games-support = callPackage ./misc/libgnome-games-support { };
+
+  gnome-applets = callPackage ./misc/gnome-applets { };
+
+  gnome-flashback = callPackage ./misc/gnome-flashback { };
+
+  gnome-panel = callPackage ./misc/gnome-panel {
+    autoreconfHook = pkgs.autoreconfHook269;
+  };
+
+  gnome-tweaks = callPackage ./misc/gnome-tweaks { };
+
+  gpaste = callPackage ./misc/gpaste { };
+
+  metacity = callPackage ./misc/metacity { };
+
+  nautilus-python = callPackage ./misc/nautilus-python { };
+
+  gtkhtml = callPackage ./misc/gtkhtml { enchant = pkgs.enchant1; };
+
+  pomodoro = callPackage ./misc/pomodoro { };
+
+  gnome-autoar = callPackage ./misc/gnome-autoar { };
+
+  gnome-packagekit = callPackage ./misc/gnome-packagekit { };
+} // lib.optionalAttrs (config.allowAliases or true) {
+#### Legacy aliases
+
+  bijiben = gnome-notes; # added 2018-09-26
+  evolution_data_server = evolution-data-server; # added 2018-02-25
+  geocode_glib = pkgs.geocode-glib; # added 2018-02-25
+  glib_networking = pkgs.glib-networking; # added 2018-02-25
+  gnome_common = gnome-common; # added 2018-02-25
+  gnome_control_center = gnome-control-center; # added 2018-02-25
+  gnome_desktop = gnome-desktop; # added 2018-02-25
+  gnome_keyring = gnome-keyring; # added 2018-02-25
+  gnome_online_accounts = gnome-online-accounts; # added 2018-02-25
+  gnome_session = gnome-session; # added 2018-02-25
+  gnome_settings_daemon = gnome-settings-daemon; # added 2018-02-25
+  gnome_shell = gnome-shell; # added 2018-02-25
+  gnome_terminal = gnome-terminal; # added 2018-02-25
+  gnome-themes-standard = gnome-themes-extra; # added 2018-03-14
+  gnome_themes_standard = gnome-themes-standard; # added 2018-02-25
+  gnome-tweak-tool = gnome-tweaks; # added 2018-03-21
+  gsettings_desktop_schemas = gsettings-desktop-schemas; # added 2018-02-25
+  libgames-support = libgnome-games-support; # added 2018-03-14
+  libgnome_keyring = libgnome-keyring; # added 2018-02-25
+  inherit (pkgs) rarian; # added 2018-04-25
+  networkmanager_fortisslvpn = networkmanager-fortisslvpn; # added 2018-02-25
+  networkmanager_iodine = networkmanager-iodine; # added 2018-02-25
+  networkmanager_l2tp = networkmanager-l2tp; # added 2018-02-25
+  networkmanager_openconnect = networkmanager-openconnect; # added 2018-02-25
+  networkmanager_openvpn = networkmanager-openvpn; # added 2018-02-25
+  networkmanager_vpnc = networkmanager-vpnc; # added 2018-02-25
+  yelp_xsl = yelp-xsl; # added 2018-02-25
+  yelp_tools = yelp-tools; # added 2018-02-25
+
+  # added 2019-02-08
+  inherit (pkgs) atk glib gobject-introspection gspell webkitgtk gtk3 gtkmm3
+      libgtop libgudev libhttpseverywhere librsvg libsecret gdk_pixbuf gtksourceview gtksourceviewmm gtksourceview4
+      easytag meld orca rhythmbox shotwell gnome-usage
+      clutter clutter-gst clutter-gtk cogl gtk-vnc libdazzle libgda libgit2-glib libgxps libgdata libgepub libpeas libgee geocode-glib libgweather librest libzapojit libmediaart gfbgraph gexiv2 folks totem-pl-parser gcr gsound libgnomekbd vte vte_290 gnome-menus gdl;
+  inherit (pkgs) gsettings-desktop-schemas; # added 2019-04-16
+  inherit (pkgs) gnome-video-effects; # added 2019-08-19
+  inherit (pkgs) gnome-online-accounts grilo grilo-plugins tracker tracker-miners gnome-photos; # added 2019-08-23
+  inherit (pkgs) glib-networking; # added 2019-09-02
+  inherit (pkgs) nemiver; # added 2019-09-09
+
+  defaultIconTheme = adwaita-icon-theme;
+  gtk = gtk3;
+  gtkmm = gtkmm3;
+  rest = librest;
+
+  pidgin-im-gnome-shell-extension = pkgs.gnomeExtensions.pidgin-im-integration; # added 2019-08-01
+
+  # added 2019-08-25
+  corePackages = throw "gnome.corePackages is removed since 2019-08-25: please use `services.gnome.core-shell.enable`";
+  optionalPackages = throw "gnome.optionalPackages is removed since 2019-08-25: please use `services.gnome.core-utilities.enable`";
+  gamesPackages = throw "gnome.gamesPackages is removed since 2019-08-25: please use `services.gnome.games.enable`";
+
+  nautilus-sendto = throw "nautilus-sendto is removed since 2019-09-17: abandoned upstream";
+
+  inherit (pkgs) vala; # added 2019-10-10
+
+  inherit (pkgs) gnome-user-docs; # added 2019-11-20
+
+  inherit (pkgs) gegl_0_4; # added 2019-10-31
+
+  inherit (pkgs) gjs; # added 2019-01-05
+
+  inherit (pkgs) yelp-tools; # added 2019-11-20
+
+  inherit (pkgs) dconf; # added 2019-11-30
+
+  inherit (pkgs) networkmanagerapplet; # added 2019-12-12
+
+  inherit (pkgs) glade; # added 2020-05-15
+
+  vino = throw "vino is deprecated, use gnome-remote-desktop instead."; # added 2020-03-13
+
+  gnome-screensaver = throw "gnome-screensaver is deprecated. If you are using GNOME Flashback, it now has a built-in lock screen. If you are using it elsewhere, you can try xscreenlock or other alternatives."; # added 2020-03-19
+
+  maintainers = lib.teams.gnome.members;
+
+  mutter328 = throw "Removed as Pantheon is upgraded to mutter334.";
+
+  gnome-getting-started-docs = throw "Removed in favour of gnome-tour.";
+
+  # Added 2021-05-07
+  gnome3 = self // { recurseForDerivations = false; };
+})
diff --git a/pkgs/desktops/gnome/devtools/anjuta/default.nix b/pkgs/desktops/gnome/devtools/anjuta/default.nix
new file mode 100644
index 00000000000..5b841557b6b
--- /dev/null
+++ b/pkgs/desktops/gnome/devtools/anjuta/default.nix
@@ -0,0 +1,44 @@
+{ lib, stdenv, fetchurl, pkg-config, gnome, gtk3, gjs, flex, bison, libxml2, intltool,
+  gdl, libgda, gtksourceview, gsettings-desktop-schemas,
+  itstool, python3, ncurses, makeWrapper }:
+
+stdenv.mkDerivation rec {
+  pname = "anjuta";
+  version = "3.34.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/anjuta/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "13ql7axw6zz387s7pa1m7wmh7qps3x7fk53h9832vq1yxlq33aa2";
+  };
+
+  passthru = {
+    updateScript = gnome.updateScript { packageName = "anjuta"; attrPath = "gnome.anjuta"; };
+  };
+
+  enableParallelBuilding = true;
+
+  nativeBuildInputs = [
+    pkg-config intltool itstool python3 makeWrapper
+    # Required by python3
+    ncurses
+  ];
+  buildInputs = [
+    flex bison gtk3 libxml2 gjs gdl
+    libgda gtksourceview
+    gsettings-desktop-schemas
+  ];
+
+  preFixup = ''
+    wrapProgram $out/bin/anjuta \
+      --prefix XDG_DATA_DIRS : \
+        "$GSETTINGS_SCHEMAS_PATH"
+  '';
+
+  meta = with lib; {
+    description = "Software development studio";
+    homepage = "http://anjuta.org/";
+    license = licenses.gpl2;
+    maintainers = with maintainers; [];
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/devtools/devhelp/default.nix b/pkgs/desktops/gnome/devtools/devhelp/default.nix
new file mode 100644
index 00000000000..46491cffc5f
--- /dev/null
+++ b/pkgs/desktops/gnome/devtools/devhelp/default.nix
@@ -0,0 +1,80 @@
+{ lib, stdenv
+, fetchurl
+, meson
+, ninja
+, pkg-config
+, gnome
+, gtk3
+, wrapGAppsHook
+, glib
+, amtk
+, appstream-glib
+, gobject-introspection
+, python3
+, webkitgtk
+, gettext
+, itstool
+, gsettings-desktop-schemas
+, shared-mime-info
+}:
+
+stdenv.mkDerivation rec {
+  pname = "devhelp";
+  version = "40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/devhelp/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "0zr64qp5c6jcc3x5hmfp7jhzpi96qwr6xplyfkmz4kjzvr9xidjd";
+  };
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    pkg-config
+    gettext
+    itstool
+    wrapGAppsHook
+    appstream-glib
+    gobject-introspection
+    python3
+  ];
+
+  buildInputs = [
+    glib
+    gtk3
+    webkitgtk
+    amtk
+    gnome.adwaita-icon-theme
+    gsettings-desktop-schemas
+  ];
+
+  doCheck = true;
+
+  postPatch = ''
+    chmod +x meson_post_install.py # patchShebangs requires executable file
+    patchShebangs meson_post_install.py
+  '';
+
+  preFixup = ''
+    gappsWrapperArgs+=(
+      # Fix pages being blank
+      # https://gitlab.gnome.org/GNOME/devhelp/issues/14
+      --prefix XDG_DATA_DIRS : "${shared-mime-info}/share"
+    )
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "devhelp";
+      attrPath = "gnome.devhelp";
+    };
+  };
+
+  meta = with lib; {
+    description = "API documentation browser for GNOME";
+    homepage = "https://wiki.gnome.org/Apps/Devhelp";
+    license = licenses.gpl3Plus;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/devtools/gnome-devel-docs/default.nix b/pkgs/desktops/gnome/devtools/gnome-devel-docs/default.nix
new file mode 100644
index 00000000000..501aaa91c97
--- /dev/null
+++ b/pkgs/desktops/gnome/devtools/gnome-devel-docs/default.nix
@@ -0,0 +1,25 @@
+{ lib, stdenv, fetchurl, gnome, intltool, itstool, libxml2 }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-devel-docs";
+  version = "40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-devel-docs/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "0zqp01ks8m3s6jn5xqd05rw4fwbvxy5qvcfg9g50b2ar2j7v1ar8";
+  };
+
+  passthru = {
+    updateScript = gnome.updateScript { packageName = "gnome-devel-docs"; attrPath = "gnome.gnome-devel-docs"; };
+  };
+
+  buildInputs = [ intltool itstool libxml2 ];
+
+  meta = with lib; {
+    homepage = "https://github.com/GNOME/gnome-devel-docs";
+    description = "Developer documentation for GNOME";
+    maintainers = teams.gnome.members;
+    license = licenses.fdl12;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/EasyScreenCast/default.nix b/pkgs/desktops/gnome/extensions/EasyScreenCast/default.nix
new file mode 100644
index 00000000000..57d78bf756a
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/EasyScreenCast/default.nix
@@ -0,0 +1,38 @@
+{ lib, stdenv, fetchFromGitHub, substituteAll, glib, gnome, gettext }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-EasyScreenCast";
+  version = "unstable-2020-11-25";
+
+  src = fetchFromGitHub {
+    # To make it work with gnome 3.38, using effectively: https://github.com/EasyScreenCast/EasyScreenCast/pull/276
+    owner = "Ian2020";
+    repo = "EasyScreenCast";
+    rev = "b1ab4a999bc7110ecbf68b5fe42c37fa67d7cb0d";
+    sha256 = "s9b0ITKUzgG6XOd1bK7i3mGxfc+T+UHrTZhBp0Ff8zQ=";
+  };
+
+  patches = [
+    (substituteAll {
+      src = ./fix-gi-path.patch;
+      gnomeShell = gnome.gnome-shell;
+    })
+  ];
+
+  nativeBuildInputs = [
+    glib gettext
+  ];
+
+  makeFlags = [ "INSTALLBASE=$(out)/share/gnome-shell/extensions" ];
+
+  uuid = "EasyScreenCast@iacopodeenosee.gmail.com";
+
+  meta = with lib; {
+    description = "Simplifies the use of the video recording function integrated in gnome shell";
+    homepage = "https://github.com/EasyScreenCast/EasyScreenCast";
+    license = licenses.gpl3Plus;
+    maintainers = with maintainers; [ doronbehar ];
+    platforms = platforms.linux;
+  };
+}
+
diff --git a/pkgs/desktops/gnome/extensions/EasyScreenCast/fix-gi-path.patch b/pkgs/desktops/gnome/extensions/EasyScreenCast/fix-gi-path.patch
new file mode 100644
index 00000000000..2d32021b6c6
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/EasyScreenCast/fix-gi-path.patch
@@ -0,0 +1,16 @@
+diff --git i/utilaudio.js w/utilaudio.js
+index 983b29c..7a94de8 100644
+--- i/utilaudio.js
++++ w/utilaudio.js
+@@ -11,10 +11,7 @@
+ */
+ 
+ const GIRepository = imports.gi.GIRepository;
+-GIRepository.Repository.prepend_search_path("/usr/lib/gnome-shell");
+-GIRepository.Repository.prepend_library_path("/usr/lib/gnome-shell");
+-GIRepository.Repository.prepend_search_path("/usr/lib64/gnome-shell");
+-GIRepository.Repository.prepend_library_path("/usr/lib64/gnome-shell");
++GIRepository.Repository.prepend_search_path("@gnomeShell@/lib/gnome-shell");
+ const Gvc = imports.gi.Gvc;
+ const Lang = imports.lang;
+ 
diff --git a/pkgs/desktops/gnome/extensions/appindicator/default.nix b/pkgs/desktops/gnome/extensions/appindicator/default.nix
new file mode 100644
index 00000000000..0906d762956
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/appindicator/default.nix
@@ -0,0 +1,36 @@
+{ lib, stdenv, fetchFromGitHub, gnome }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-appindicator";
+  version = "36";
+
+  src = fetchFromGitHub {
+    owner = "Ubuntu";
+    repo = "gnome-shell-extension-appindicator";
+    rev = "v${version}";
+    sha256 = "1nx1lgrrp3w5z5hymb91frjdvdkk7x677my5v4jjd330ihqa02dq";
+  };
+
+  # This package has a Makefile, but it's used for building a zip for
+  # publication to extensions.gnome.org. Disable the build phase so
+  # installing doesn't build an unnecessary release.
+  dontBuild = true;
+
+  uuid = "appindicatorsupport@rgcjonas.gmail.com";
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/share/gnome-shell/extensions/${uuid}
+    cp *.js $out/share/gnome-shell/extensions/${uuid}
+    cp -r interfaces-xml $out/share/gnome-shell/extensions/${uuid}
+    cp metadata.json $out/share/gnome-shell/extensions/${uuid}
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "AppIndicator/KStatusNotifierItem support for GNOME Shell";
+    license = licenses.gpl2Plus;
+    maintainers = with maintainers; [ jonafato ];
+    platforms = gnome.gnome-shell.meta.platforms;
+    homepage = "https://github.com/Ubuntu/gnome-shell-extension-appindicator";
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/arcmenu/default.nix b/pkgs/desktops/gnome/extensions/arcmenu/default.nix
new file mode 100644
index 00000000000..851a816c61c
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/arcmenu/default.nix
@@ -0,0 +1,35 @@
+{ lib, stdenv, fetchFromGitLab, glib, gettext, substituteAll, gnome-menus }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-arcmenu";
+  version = "5";
+
+  src = fetchFromGitLab {
+    owner = "arcmenu";
+    repo = "ArcMenu";
+    rev = "v${version}";
+    sha256 = "1w4avvnp08l7lkf76vc7wvfn1cd81l4r4dhz8qnai49rvrjgqcg3";
+  };
+
+  patches = [
+    (substituteAll {
+      src = ./fix_gmenu.patch;
+      gmenu_path = "${gnome-menus}/lib/girepository-1.0";
+    })
+  ];
+
+  buildInputs = [
+    glib gettext
+  ];
+
+  makeFlags = [ "INSTALLBASE=${placeholder "out"}/share/gnome-shell/extensions" ];
+
+  uuid = "arcmenu@arcmenu.com";
+
+  meta = with lib; {
+    description = "Application menu for GNOME Shell, designed to provide a more traditional user experience and workflow";
+    license = licenses.gpl2Plus;
+    maintainers = with maintainers; [ dkabot ];
+    homepage = "https://gitlab.com/arcmenu/ArcMenu";
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/arcmenu/fix_gmenu.patch b/pkgs/desktops/gnome/extensions/arcmenu/fix_gmenu.patch
new file mode 100644
index 00000000000..5d8584f52a6
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/arcmenu/fix_gmenu.patch
@@ -0,0 +1,11 @@
+--- a/extension.js
++++ b/extension.js
+@@ -23,6 +23,8 @@
+
+ const Me = imports.misc.extensionUtils.getCurrentExtension();
+
++imports.gi.GIRepository.Repository.prepend_search_path('@gmenu_path@');
++
+ const {GLib, Gio, St} = imports.gi;
+ const Constants = Me.imports.constants;
+ const Controller = Me.imports.controller;
diff --git a/pkgs/desktops/gnome/extensions/caffeine/default.nix b/pkgs/desktops/gnome/extensions/caffeine/default.nix
new file mode 100644
index 00000000000..3085a4461e7
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/caffeine/default.nix
@@ -0,0 +1,40 @@
+{ lib, stdenv, fetchFromGitHub, glib, gettext, bash, gnome }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-caffeine";
+  version = "37";
+
+  src = fetchFromGitHub {
+    owner = "eonpatapon";
+    repo = "gnome-shell-extension-caffeine";
+    rev = "v${version}";
+    sha256 = "1mpa0fbpmv3pblb20dxj8iykn4ayvx89qffpcs67bzlq597zsbkb";
+  };
+
+  uuid = "caffeine@patapon.info";
+
+  nativeBuildInputs = [
+    glib gettext
+  ];
+
+  buildPhase = ''
+    runHook preBuild
+    ${bash}/bin/bash ./update-locale.sh
+    glib-compile-schemas --strict --targetdir=caffeine@patapon.info/schemas/ caffeine@patapon.info/schemas
+    runHook postBuild
+  '';
+
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/share/gnome-shell/extensions
+    cp -r ${uuid} $out/share/gnome-shell/extensions
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "Fill the cup to inhibit auto suspend and screensaver";
+    license = licenses.gpl2;
+    maintainers = with maintainers; [ eperuffo ];
+    homepage = "https://github.com/eonpatapon/gnome-shell-extension-caffeine";
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/chrome-gnome-shell/default.nix b/pkgs/desktops/gnome/extensions/chrome-gnome-shell/default.nix
new file mode 100644
index 00000000000..779d7506abf
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/chrome-gnome-shell/default.nix
@@ -0,0 +1,71 @@
+{ lib, stdenv
+, fetchurl
+, cmake
+, ninja
+, jq
+, python3
+, gnome
+, wrapGAppsHook
+, gobject-introspection
+}:
+
+let
+  inherit (python3.pkgs) python pygobject3 requests;
+in
+stdenv.mkDerivation rec {
+  pname = "chrome-gnome-shell";
+  version = "10.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/chrome-gnome-shell/${version}/${pname}-${version}.tar.xz";
+    sha256 = "0f54xyamm383ypbh0ndkza0pif6ljddg2f947p265fkqj3p4zban";
+  };
+
+  nativeBuildInputs = [
+    cmake
+    ninja
+    jq
+    wrapGAppsHook
+    gobject-introspection # for setup-hook
+  ];
+
+  buildInputs = [
+    gnome.gnome-shell
+    python
+    pygobject3
+    requests
+    gobject-introspection # for Gio typelib
+  ];
+
+  cmakeFlags = [
+    "-DBUILD_EXTENSION=OFF"
+  ];
+
+  wrapPrefixVariables = [
+    "PYTHONPATH"
+  ];
+
+  # cmake setup hook changes /etc/opt into /var/empty
+  dontFixCmake = true;
+
+  preConfigure = ''
+    substituteInPlace CMakeLists.txt --replace "/etc" "$out/etc"
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "chrome-gnome-shell";
+    };
+  };
+
+  meta = with lib; {
+    description = "GNOME Shell integration for Chrome";
+    homepage = "https://wiki.gnome.org/Projects/GnomeShellIntegrationForChrome";
+    longDescription = ''
+      To use the integration, install the <link xlink:href="https://wiki.gnome.org/Projects/GnomeShellIntegrationForChrome/Installation">browser extension</link>, and then set <option>services.gnome.chrome-gnome-shell.enable</option> to <literal>true</literal>.
+    '';
+    license = licenses.gpl3;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/clipboard-indicator/default.nix b/pkgs/desktops/gnome/extensions/clipboard-indicator/default.nix
new file mode 100644
index 00000000000..ee64fc5113d
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/clipboard-indicator/default.nix
@@ -0,0 +1,30 @@
+{ lib, stdenv, fetchFromGitHub }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-clipboard-indicator";
+  version = "37";
+
+  src = fetchFromGitHub {
+    owner = "Tudmotu";
+    repo = "gnome-shell-extension-clipboard-indicator";
+    rev = "v${version}";
+    sha256 = "0npxhaam2ra2b9zh2gk2q0n5snlhx6glz86m3jf8hz037w920k41";
+  };
+
+  uuid = "clipboard-indicator@tudmotu.com";
+
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/share/gnome-shell/extensions/${uuid}
+    cp -r * $out/share/gnome-shell/extensions/${uuid}
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "Adds a clipboard indicator to the top panel and saves clipboard history";
+    license = licenses.mit;
+    maintainers = with maintainers; [ jonafato ];
+    platforms = platforms.linux;
+    homepage = "https://github.com/Tudmotu/gnome-shell-extension-clipboard-indicator";
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/clock-override/default.nix b/pkgs/desktops/gnome/extensions/clock-override/default.nix
new file mode 100644
index 00000000000..3e02d33857a
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/clock-override/default.nix
@@ -0,0 +1,37 @@
+{ lib, stdenv, fetchzip, gnome, gettext, glib }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-clock-override";
+  version = "12";
+
+  src = fetchzip {
+    url = "https://extensions.gnome.org/extension-data/clock-overridegnomeshell.kryogenix.org.v${version}.shell-extension.zip";
+    sha256 = "1cyaszks6bwnbgacqsl1pmr24mbj05mad59d4253la9am8ibb4m6";
+    stripRoot = false;
+  };
+
+  uuid = "clock-override@gnomeshell.kryogenix.org";
+
+  nativeBuildInputs = [ gettext glib ];
+
+  buildPhase = ''
+    runHook preBuild
+    glib-compile-schemas --strict --targetdir=schemas schemas
+    runHook postBuild
+  '';
+
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/share/gnome-shell/extensions/${uuid}
+    cp -r {convenience.js,extension.js,format.js,locale,metadata.json,prefs.js,schemas} $out/share/gnome-shell/extensions/${uuid}
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "Customize the date and time format displayed in clock in the top bar in GNOME Shell";
+    license = licenses.mit;
+    maintainers = with maintainers; [ rhoriguchi ];
+    homepage = "https://github.com/stuartlangridge/gnome-shell-clock-override";
+    broken = versionOlder gnome.gnome-shell.version "3.18";
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/dash-to-dock/default.nix b/pkgs/desktops/gnome/extensions/dash-to-dock/default.nix
new file mode 100644
index 00000000000..45233e52f89
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/dash-to-dock/default.nix
@@ -0,0 +1,35 @@
+{ lib, stdenv
+, fetchFromGitHub
+, glib
+, gettext
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-dash-to-dock";
+  version = "69";
+
+  src = fetchFromGitHub {
+    owner = "micheleg";
+    repo = "dash-to-dock";
+    rev = "extensions.gnome.org-v" + version;
+    hash = "sha256-YuLtC7E8dK57JSuFdbDQe5Ml+KQfl9qSdrHdVhFaNiE=";
+  };
+
+  nativeBuildInputs = [
+    glib
+    gettext
+  ];
+
+  makeFlags = [
+    "INSTALLBASE=${placeholder "out"}/share/gnome-shell/extensions"
+  ];
+
+  uuid = "dash-to-dock@micxgx.gmail.com";
+
+  meta = with lib; {
+    description = "A dock for the Gnome Shell";
+    homepage = "https://micheleg.github.io/dash-to-dock/";
+    license = licenses.gpl2;
+    maintainers = with maintainers; [ eperuffo jtojnar ];
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/dash-to-panel/default.nix b/pkgs/desktops/gnome/extensions/dash-to-panel/default.nix
new file mode 100644
index 00000000000..7a9dc066cc7
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/dash-to-panel/default.nix
@@ -0,0 +1,28 @@
+{ lib, stdenv, fetchFromGitHub, glib, gettext }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-dash-to-panel";
+  version = "40";
+
+  src = fetchFromGitHub {
+    owner = "home-sweet-gnome";
+    repo = "dash-to-panel";
+    rev = "v${version}";
+    sha256 = "07jq8d16nn62ikis896nyfn3q02f5srj754fmiblhz472q4ljc3p";
+  };
+
+  buildInputs = [
+    glib gettext
+  ];
+
+  makeFlags = [ "INSTALLBASE=$(out)/share/gnome-shell/extensions" ];
+
+  uuid = "dash-to-panel@jderose9.github.com";
+
+  meta = with lib; {
+    description = "An icon taskbar for Gnome Shell";
+    license = licenses.gpl2;
+    maintainers = with maintainers; [ mounium ];
+    homepage = "https://github.com/jderose9/dash-to-panel";
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/disable-unredirect/default.nix b/pkgs/desktops/gnome/extensions/disable-unredirect/default.nix
new file mode 100644
index 00000000000..0a9145de3db
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/disable-unredirect/default.nix
@@ -0,0 +1,31 @@
+{ lib, stdenv, fetchFromGitHub }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-disable-unredirect";
+  version = "unstable-2021-01-17";
+
+  src = fetchFromGitHub {
+    owner = "kazysmaster";
+    repo = "gnome-shell-extension-disable-unredirect";
+    rev = "2ecb2f489ea3316b77d04f03a0c885f322c67e79";
+    sha256 = "1rjyrg8qya0asndxr7189a9npww0rcxk02wkxrxjy7fdp5m89p7y";
+  };
+
+  uuid = "unredirect@vaina.lt";
+
+  installPhase = ''
+    runHook preInstall
+
+    mkdir -p $out/share/gnome-shell/extensions
+    cp -R ${uuid} $out/share/gnome-shell/extensions/${uuid}
+
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "Disables unredirect fullscreen windows in gnome-shell to avoid tearing";
+    license = licenses.gpl3Only;
+    homepage = "https://github.com/kazysmaster/gnome-shell-extension-disable-unredirect";
+    maintainers = with maintainers; [ eduardosm ];
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/draw-on-your-screen/default.nix b/pkgs/desktops/gnome/extensions/draw-on-your-screen/default.nix
new file mode 100644
index 00000000000..90e8bffeec9
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/draw-on-your-screen/default.nix
@@ -0,0 +1,29 @@
+{ lib, stdenv, fetchgit, gettext, gnome }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-draw-on-your-screen";
+  version = "10";
+
+  src = fetchgit {
+    url = "https://framagit.org/abakkk/DrawOnYourScreen/";
+    rev = "v${version}";
+    sha256 = "07adzg3mf6k0pmd9lc358w0w3l4pr3p6374day1qhmci2p4zxq6p";
+  };
+
+  uuid = "drawOnYourScreen@abakkk.framagit.org";
+
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/share/gnome-shell/extensions/${uuid}
+    cp -r . $out/share/gnome-shell/extensions/${uuid}
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "A drawing extension for GNOME Shell";
+    license = licenses.gpl2Plus;
+    maintainers = with maintainers; [ ericdallo ahuzik ];
+    platforms = gnome.gnome-shell.meta.platforms;
+    homepage = "https://framagit.org/abakkk/DrawOnYourScreen";
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/drop-down-terminal/default.nix b/pkgs/desktops/gnome/extensions/drop-down-terminal/default.nix
new file mode 100644
index 00000000000..a994e427fb0
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/drop-down-terminal/default.nix
@@ -0,0 +1,36 @@
+{ lib, stdenv, fetchFromGitHub, substituteAll, gjs, vte, gnome }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-drop-down-terminal";
+  version = "unstable-2020-03-25";
+
+  src = fetchFromGitHub {
+    owner = "zzrough";
+    repo = "gs-extensions-drop-down-terminal";
+    rev = "a59669afdb395b3315619f62c1f740f8b2f0690d";
+    sha256 = "0igfxgrjdqq6z6xg4rsawxn261pk25g5dw2pm3bhwz5sqsy4bq3i";
+  };
+
+  uuid = "drop-down-terminal@gs-extensions.zzrough.org";
+
+  patches = [
+    (substituteAll {
+      src = ./fix_vte_and_gjs.patch;
+      inherit gjs vte;
+    })
+  ];
+
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/share/gnome-shell/extensions
+    cp -r ${uuid} $out/share/gnome-shell/extensions/
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "Configurable drop down terminal shell";
+    license = licenses.gpl3;
+    maintainers = with maintainers; [ ericdallo ];
+    homepage = "https://github.com/zzrough/gs-extensions-drop-down-terminal";
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/drop-down-terminal/fix_vte_and_gjs.patch b/pkgs/desktops/gnome/extensions/drop-down-terminal/fix_vte_and_gjs.patch
new file mode 100644
index 00000000000..3544c91ee89
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/drop-down-terminal/fix_vte_and_gjs.patch
@@ -0,0 +1,32 @@
+--- a/drop-down-terminal@gs-extensions.zzrough.org/extension.js
++++ b/drop-down-terminal@gs-extensions.zzrough.org/extension.js
+@@ -15,6 +15,8 @@
+ 
+ // Author: Stéphane Démurget <stephane.demurget@free.fr>
+ 
++imports.gi.GIRepository.Repository.prepend_search_path('@vte@/lib/girepository-1.0')
++
+ const Lang = imports.lang;
+ const Gettext = imports.gettext.domain("drop-down-terminal");
+ const Mainloop = imports.mainloop;
+@@ -653,7 +655,7 @@ const DropDownTerminalExtension = new Lang.Class({
+         this._killingChild = false;
+ 
+         // finds the forking arguments
+-        let args = ["gjs", GLib.build_filenamev([Me.path, "terminal.js"]), Me.path];
++        let args = ["@gjs@/bin/gjs", GLib.build_filenamev([Me.path, "terminal.js"]), Me.path];
+ 
+         // forks the process
+         debug("forking '" + args.join(" ") + "'");
+--- a/drop-down-terminal@gs-extensions.zzrough.org/terminal.js
++++ b/drop-down-terminal@gs-extensions.zzrough.org/terminal.js
+@@ -14,6 +14,9 @@
+ // along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ 
+ // Author: Stéphane Démurget <stephane.demurget@free.fr>
++
++imports.gi.GIRepository.Repository.prepend_search_path('@vte@/lib/girepository-1.0')
++
+ const Lang = imports.lang;
+ 
+ const Pango = imports.gi.Pango;
diff --git a/pkgs/desktops/gnome/extensions/dynamic-panel-transparency/default.nix b/pkgs/desktops/gnome/extensions/dynamic-panel-transparency/default.nix
new file mode 100644
index 00000000000..f31e170b975
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/dynamic-panel-transparency/default.nix
@@ -0,0 +1,38 @@
+{ lib, stdenv, fetchFromGitHub, gnome, glib }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-dynamic-panel-transparency";
+  version = "35";
+
+  src = fetchFromGitHub {
+    owner = "ewlsh";
+    repo = "dynamic-panel-transparency";
+    rev = "0800c0a921bb25f51f6a5ca2e6981b1669a69aec";
+    sha256 = "0200mx861mlsi9lf7h108yam02jfqqw55r521chkgmk4fy6z99pq";
+  };
+
+  uuid = "dynamic-panel-transparency@rockon999.github.io";
+
+  nativeBuildInputs = [ glib ];
+
+  buildPhase = ''
+    runHook preBuild
+    glib-compile-schemas --strict --targetdir=${uuid}/schemas/ ${uuid}/schemas
+    runHook postBuild
+  '';
+
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/share/gnome-shell/extensions/${uuid}
+    cp -r ${uuid} $out/share/gnome-shell/extensions
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "This extension fades your top panel to nothingness when there are no maximized windows present";
+    license = licenses.gpl3Only;
+    maintainers = with maintainers; [ rhoriguchi ];
+    homepage = "https://github.com/ewlsh/dynamic-panel-transparency";
+    broken = versionOlder gnome.gnome-shell.version "3.36";
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/emoji-selector/default.nix b/pkgs/desktops/gnome/extensions/emoji-selector/default.nix
new file mode 100644
index 00000000000..5470dc996be
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/emoji-selector/default.nix
@@ -0,0 +1,38 @@
+{ lib, stdenv, fetchFromGitHub, glib, gettext }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-emoji-selector";
+  version = "19";
+
+  src = fetchFromGitHub {
+    owner = "maoschanz";
+    repo = "emoji-selector-for-gnome";
+    rev = version;
+    sha256 = "0x60pg5nl5d73av494dg29hyfml7fbf2d03wm053vx1q8a3pxbyb";
+  };
+
+  uuid = "emoji-selector@maestroschan.fr";
+
+  nativeBuildInputs = [ glib ];
+
+  buildPhase = ''
+    runHook preBuild
+    glib-compile-schemas ./${uuid}/schemas
+    runHook postBuild
+  '';
+
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/share/gnome-shell/extensions
+    cp -r ${uuid} $out/share/gnome-shell/extensions
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description =
+      "GNOME Shell extension providing a searchable popup menu displaying most emojis";
+    license = licenses.gpl3Plus;
+    maintainers = with maintainers; [ rawkode ];
+    homepage = "https://github.com/maoschanz/emoji-selector-for-gnome";
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/freon/default.nix b/pkgs/desktops/gnome/extensions/freon/default.nix
new file mode 100644
index 00000000000..f30e2f6f8a2
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/freon/default.nix
@@ -0,0 +1,37 @@
+{ lib, stdenv, fetchFromGitHub, glib }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-freon";
+  version = "40";
+
+  uuid = "freon@UshakovVasilii_Github.yahoo.com";
+
+  src = fetchFromGitHub {
+    owner = "UshakovVasilii";
+    repo = "gnome-shell-extension-freon";
+    rev = "EGO-${version}";
+    sha256 = "0ak6f5dds9kk3kqww681gs3l1mj3vf22icrvb5m257s299rq8yzl";
+  };
+
+  nativeBuildInputs = [ glib ];
+
+  buildPhase = ''
+    runHook preBuild
+    glib-compile-schemas --strict --targetdir=${uuid}/schemas ${uuid}/schemas
+    runHook postBuild
+  '';
+
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/share/gnome-shell/extensions
+    cp -r ${uuid} $out/share/gnome-shell/extensions
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "GNOME Shell extension for displaying CPU, GPU, disk temperatures, voltage and fan RPM in the top panel";
+    license = licenses.gpl2;
+    maintainers = with maintainers; [ justinas ];
+    homepage = "https://github.com/UshakovVasilii/gnome-shell-extension-freon";
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/fuzzy-app-search/default.nix b/pkgs/desktops/gnome/extensions/fuzzy-app-search/default.nix
new file mode 100755
index 00000000000..302b21f2aef
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/fuzzy-app-search/default.nix
@@ -0,0 +1,29 @@
+{ lib, stdenv, fetchFromGitLab, gnome, glib }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-fuzzy-app-search";
+  version = "4";
+
+  src = fetchFromGitLab {
+    owner = "Czarlie";
+    repo = "gnome-fuzzy-app-search";
+    rev = "da9c15d39958d9c3b38df3b616fd40b85aed24e5";
+    sha256 = "1r3qha530s97x818znn1wi76f4x9bhlgi7jlxfwjnrwys62cv5fn";
+  };
+
+  uuid = "gnome-fuzzy-app-search@gnome-shell-extensions.Czarlie.gitlab.com";
+
+  nativeBuildInputs = [ glib ];
+
+  patches = [ ./fix-desktop-file-paths.patch ];
+
+  makeFlags = [ "INSTALL_PATH=$(out)/share/gnome-shell/extensions" ];
+
+  meta = with lib; {
+    description = "Fuzzy application search results for Gnome Search";
+    license = licenses.gpl3Only;
+    maintainers = with maintainers; [ rhoriguchi ];
+    homepage = "https://gitlab.com/Czarlie/gnome-fuzzy-app-search";
+    broken = versionOlder gnome.gnome-shell.version "3.18";
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/fuzzy-app-search/fix-desktop-file-paths.patch b/pkgs/desktops/gnome/extensions/fuzzy-app-search/fix-desktop-file-paths.patch
new file mode 100755
index 00000000000..1795f998c9b
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/fuzzy-app-search/fix-desktop-file-paths.patch
@@ -0,0 +1,50 @@
+diff --git a/applicationsUtils.js b/applicationsUtils.js
+index 728223b..aa9f291 100644
+--- a/applicationsUtils.js
++++ b/applicationsUtils.js
+@@ -44,27 +44,24 @@ var Search = new Lang.Class({
+      * @return {Void}
+      */
+     _init: function () {
+-        let dir = [
+-            "/usr/share/applications",
+-            GLib.get_home_dir() + "/.local/share/applications",
+-        ];
+-
+-        // listen object - file/monitor list
+-        this._listen = dir.map((path) => {
+-            let file = Gio.File.new_for_path(path);
+-            let monitor = file.monitor(Gio.FileMonitorFlags.NONE, null);
+-
+-            // refresh on each directory change
+-            monitor.connect(
+-                "changed",
+-                Lang.bind(this, this._handleMonitorChanged)
+-            );
+-
+-            return {
+-                file: file,
+-                monitor: monitor,
+-            };
+-        });
++        this._listen = [...new Set(GLib.get_system_data_dirs())]
++            .filter((path) => path.endsWith("/share"))
++            .map((path) => Gio.File.new_for_path(path + "/applications"))
++            .filter((file) => file.query_exists(null))
++            .map((file) => {
++                let monitor = file.monitor(Gio.FileMonitorFlags.NONE, null);
++
++                // refresh on each directory change
++                monitor.connect(
++                    "changed",
++                    Lang.bind(this, this._handleMonitorChanged)
++                );
++
++                return {
++                    file: file,
++                    monitor: monitor,
++                };
++            });
+         this._interval = null;
+         this._data = {};
+ 
\ No newline at end of file
diff --git a/pkgs/desktops/gnome/extensions/gsconnect/default.nix b/pkgs/desktops/gnome/extensions/gsconnect/default.nix
new file mode 100644
index 00000000000..c924b4e3eca
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/gsconnect/default.nix
@@ -0,0 +1,116 @@
+{ lib, stdenv
+, fetchFromGitHub
+, substituteAll
+, openssl
+, gsound
+, meson
+, ninja
+, pkg-config
+, gobject-introspection
+, wrapGAppsHook
+, glib
+, glib-networking
+, gtk3
+, openssh
+, gnome
+, gjs
+, nixosTests
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-gsconnect";
+  version = "46";
+
+  outputs = [ "out" "installedTests" ];
+
+  src = fetchFromGitHub {
+    owner = "andyholmes";
+    repo = "gnome-shell-extension-gsconnect";
+    rev = "v${version}";
+    sha256 = "161379kipr6z6gbhchb5b17djrkg5fbvblyyabzkc2gv05r3h6fw";
+  };
+
+  patches = [
+    # Make typelibs available in the extension
+    (substituteAll {
+      src = ./fix-paths.patch;
+      gapplication = "${glib.bin}/bin/gapplication";
+    })
+
+    # Allow installing installed tests to a separate output
+    ./installed-tests-path.patch
+  ];
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    pkg-config
+    gobject-introspection # for locating typelibs
+    wrapGAppsHook # for wrapping daemons
+  ];
+
+  buildInputs = [
+    glib # libgobject
+    glib-networking
+    gtk3
+    gsound
+    gjs # for running daemon
+    gnome.evolution-data-server # for libebook-contacts typelib
+  ];
+
+  mesonFlags = [
+    "-Dgnome_shell_libdir=${gnome.gnome-shell}/lib"
+    "-Dgsettings_schemadir=${glib.makeSchemaPath (placeholder "out") "${pname}-${version}"}"
+    "-Dchrome_nmhdir=${placeholder "out"}/etc/opt/chrome/native-messaging-hosts"
+    "-Dchromium_nmhdir=${placeholder "out"}/etc/chromium/native-messaging-hosts"
+    "-Dopenssl_path=${openssl}/bin/openssl"
+    "-Dsshadd_path=${openssh}/bin/ssh-add"
+    "-Dsshkeygen_path=${openssh}/bin/ssh-keygen"
+    "-Dsession_bus_services_dir=${placeholder "out"}/share/dbus-1/services"
+    "-Dpost_install=true"
+    "-Dinstalled_test_prefix=${placeholder "installedTests"}"
+  ];
+
+  postPatch = ''
+    patchShebangs meson/nmh.sh
+    patchShebangs meson/post-install.sh
+    patchShebangs installed-tests/prepare-tests.sh
+
+    # TODO: do not include every typelib everywhere
+    # for example, we definitely do not need nautilus
+    for file in src/extension.js src/prefs.js; do
+      substituteInPlace "$file" \
+        --subst-var-by typelibPath "$GI_TYPELIB_PATH"
+    done
+  '';
+
+  postFixup = ''
+    # Let’s wrap the daemons
+    for file in $out/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/{daemon,nativeMessagingHost}.js; do
+      echo "Wrapping program $file"
+      wrapGApp "$file"
+    done
+
+    # Wrap jasmine runner for tests
+    for file in $installedTests/libexec/installed-tests/gsconnect/minijasmine; do
+      echo "Wrapping program $file"
+      wrapGApp "$file"
+    done
+  '';
+
+  uuid = "gsconnect@andyholmes.github.io";
+
+  passthru = {
+    tests = {
+      installedTests = nixosTests.installed-tests.gsconnect;
+    };
+  };
+
+  meta = with lib; {
+    description = "KDE Connect implementation for Gnome Shell";
+    homepage = "https://github.com/andyholmes/gnome-shell-extension-gsconnect/wiki";
+    license = licenses.gpl2Plus;
+    maintainers = with maintainers; [ etu ];
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/gsconnect/fix-paths.patch b/pkgs/desktops/gnome/extensions/gsconnect/fix-paths.patch
new file mode 100644
index 00000000000..58c02a92eb2
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/gsconnect/fix-paths.patch
@@ -0,0 +1,37 @@
+diff --git i/data/org.gnome.Shell.Extensions.GSConnect.desktop.in w/data/org.gnome.Shell.Extensions.GSConnect.desktop.in
+index ffb23342..b405c73b 100644
+--- i/data/org.gnome.Shell.Extensions.GSConnect.desktop.in
++++ w/data/org.gnome.Shell.Extensions.GSConnect.desktop.in
+@@ -1,7 +1,7 @@
+ [Desktop Entry]
+ Type=Application
+ Name=GSConnect
+-Exec=gapplication launch org.gnome.Shell.Extensions.GSConnect %U
++Exec=@gapplication@ launch org.gnome.Shell.Extensions.GSConnect %U
+ Terminal=false
+ NoDisplay=true
+ Icon=org.gnome.Shell.Extensions.GSConnect
+diff --git i/src/extension.js w/src/extension.js
+index 5f32aa68..872c0c61 100644
+--- i/src/extension.js
++++ w/src/extension.js
+@@ -1,5 +1,7 @@
+ 'use strict';
+ 
++'@typelibPath@'.split(':').forEach(path => imports.gi.GIRepository.Repository.prepend_search_path(path));
++
+ const Gio = imports.gi.Gio;
+ const GObject = imports.gi.GObject;
+ const Gtk = imports.gi.Gtk;
+diff --git i/src/prefs.js w/src/prefs.js
+index 07e93099..1c166710 100644
+--- i/src/prefs.js
++++ w/src/prefs.js
+@@ -1,5 +1,7 @@
+ 'use strict';
+ 
++'@typelibPath@'.split(':').forEach(path => imports.gi.GIRepository.Repository.prepend_search_path(path));
++
+ const Gio = imports.gi.Gio;
+ const GLib = imports.gi.GLib;
+ const Gtk = imports.gi.Gtk;
diff --git a/pkgs/desktops/gnome/extensions/gsconnect/installed-tests-path.patch b/pkgs/desktops/gnome/extensions/gsconnect/installed-tests-path.patch
new file mode 100644
index 00000000000..78e1ad96d74
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/gsconnect/installed-tests-path.patch
@@ -0,0 +1,30 @@
+diff --git a/installed-tests/meson.build b/installed-tests/meson.build
+index c7eff2fb..ef4f6052 100644
+--- a/installed-tests/meson.build
++++ b/installed-tests/meson.build
+@@ -1,5 +1,5 @@
+-installed_tests_execdir = join_paths(libexecdir, 'installed-tests', meson.project_name())
+-installed_tests_metadir = join_paths(datadir, 'installed-tests', meson.project_name())
++installed_tests_execdir = join_paths(get_option('installed_test_prefix'), 'libexec', 'installed-tests', meson.project_name())
++installed_tests_metadir = join_paths(get_option('installed_test_prefix'), 'share', 'installed-tests', meson.project_name())
+ 
+ installed_tests_srcdir = meson.current_source_dir()
+ installed_tests_builddir = meson.current_build_dir()
+diff --git a/meson_options.txt b/meson_options.txt
+index 8912e052..ca6ee5eb 100644
+--- a/meson_options.txt
++++ b/meson_options.txt
+@@ -116,6 +116,13 @@ option(
+   description: 'Native Messaging Host directory for Mozilla'
+ )
+ 
++option(
++  'installed_test_prefix',
++  type: 'string',
++  value: '',
++  description: 'Prefix for installed tests'
++)
++
+ option(
+   'installed_tests',
+   type: 'boolean',
diff --git a/pkgs/desktops/gnome/extensions/hot-edge/default.nix b/pkgs/desktops/gnome/extensions/hot-edge/default.nix
new file mode 100644
index 00000000000..aaa5870996a
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/hot-edge/default.nix
@@ -0,0 +1,33 @@
+{ lib
+, stdenv
+, fetchFromGitHub
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-hot-edge";
+  version = "jdoda";
+
+  src = fetchFromGitHub {
+    owner = "jdoda";
+    repo = "hotedge";
+    rev = "bb7f651becea5287241caf7cda246a68ab07dac8";
+    sha256 = "oeTs0kRan6b5relxzhK1IKbV0Yv2d5YdvvUPJ3fM9ik=";
+  };
+
+  dontBuild = true;
+
+  uuid = "hotedge@jonathan.jdoda.ca";
+
+  installPhase = ''
+    runHook preInstall
+    install -Dt $out/share/gnome-shell/extensions/${uuid} extension.js metadata.json stylesheet.css
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "Replace the top-left hot corner with a bottom hot edge";
+    license = licenses.gpl2Plus;
+    maintainers = with maintainers; [ jtojnar ];
+    homepage = "https://github.com/jdoda/hotedge";
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/icon-hider/default.nix b/pkgs/desktops/gnome/extensions/icon-hider/default.nix
new file mode 100644
index 00000000000..820d96988c9
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/icon-hider/default.nix
@@ -0,0 +1,31 @@
+{ lib, stdenv, fetchFromGitHub, gnome }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-icon-hider";
+  version = "23";
+
+  src = fetchFromGitHub {
+    owner = "ikalnytskyi";
+    repo = "gnome-shell-extension-icon-hider";
+    rev = "v${version}";
+    sha256 = "18c8zkdrmdbghqqz7b450vhgpykgz25mgigwn2nggcb2lxmvm9ks";
+  };
+
+  uuid = "icon-hider@kalnitsky.org";
+
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/share/gnome-shell/extensions
+    cp -r ${uuid} $out/share/gnome-shell/extensions
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "Icon Hider is a GNOME Shell extension for managing status area items";
+    license = licenses.bsd3;
+    maintainers = with maintainers; [ jonafato ];
+    platforms = gnome.gnome-shell.meta.platforms;
+    homepage = "https://github.com/ikalnytskyi/gnome-shell-extension-icon-hider";
+    broken = versionAtLeast gnome.gnome-shell.version "3.32"; # Doesn't support 3.34
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/impatience/default.nix b/pkgs/desktops/gnome/extensions/impatience/default.nix
new file mode 100644
index 00000000000..82551efef3c
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/impatience/default.nix
@@ -0,0 +1,39 @@
+{ lib, stdenv, fetchFromGitHub, glib }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-impatience";
+  version = "unstable-2019-09-23";
+
+  src = fetchFromGitHub {
+    owner = "timbertson";
+    repo = "gnome-shell-impatience";
+    rev = "43e4e0a1e0eeb334a2da5224ce3ab4fdddf4f1b2";
+    sha256 = "0kvdhlz41fjyqdgcfw6mrr9nali6wg2qwji3dvykzfi0aypljzpx";
+  };
+
+  buildInputs = [
+    glib
+  ];
+
+  buildPhase = ''
+    runHook preBuild
+    make schemas
+    runHook postBuild
+  '';
+
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/share/gnome-shell/extensions
+    cp -r impatience $out/share/gnome-shell/extensions/${uuid}
+    runHook postInstall
+  '';
+
+  uuid = "impatience@gfxmonk.net";
+
+  meta = with lib; {
+    description = "Speed up builtin gnome-shell animations";
+    license = licenses.gpl3Plus;
+    maintainers = with maintainers; [ timbertson tiramiseb ];
+    homepage = "http://gfxmonk.net/dist/0install/gnome-shell-impatience.xml";
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/material-shell/default.nix b/pkgs/desktops/gnome/extensions/material-shell/default.nix
new file mode 100644
index 00000000000..9b683c1af6b
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/material-shell/default.nix
@@ -0,0 +1,35 @@
+{ stdenv, lib, fetchFromGitHub, gnome }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-material-shell";
+  version = "12";
+
+  src = fetchFromGitHub {
+    owner = "material-shell";
+    repo = "material-shell";
+    rev = version;
+    sha256 = "0ikrh70drwr0pqjcdz7l1ky8xllpnk7myprjd4s61nqkx9j2iz44";
+  };
+
+  # This package has a Makefile, but it's used for building a zip for
+  # publication to extensions.gnome.org. Disable the build phase so
+  # installing doesn't build an unnecessary release.
+  dontBuild = true;
+
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/share/gnome-shell/extensions/${uuid}
+    cp -r * $out/share/gnome-shell/extensions/${uuid}/
+    runHook postInstall
+  '';
+
+  uuid = "material-shell@papyelgringo";
+
+  meta = with lib; {
+    description = "A modern desktop interface for Linux";
+    license = licenses.mit;
+    maintainers = with maintainers; [ benley ];
+    homepage = "https://github.com/material-shell/material-shell";
+    platforms = gnome.gnome-shell.meta.platforms;
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/mpris-indicator-button/default.nix b/pkgs/desktops/gnome/extensions/mpris-indicator-button/default.nix
new file mode 100644
index 00000000000..b0dfc9b8dec
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/mpris-indicator-button/default.nix
@@ -0,0 +1,42 @@
+{ lib, stdenv
+, fetchFromGitHub
+, nix-update-script
+, gnome
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-mpris-indicator-button-unstable";
+  version = "2020-03-21";
+
+  src = fetchFromGitHub {
+    owner = "JasonLG1979";
+    repo = "gnome-shell-extension-mpris-indicator-button";
+    rev = "de54160e7d905b8c48c0fe30a437f7c51efc1aa3";
+    sha256 = "0n5qlx51fxjq1nn10zhdwfy905j20sv7pwh2jc6fns757ac4pwwk";
+  };
+
+  uuid = "mprisindicatorbutton@JasonLG1979.github.io";
+
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/share/gnome-shell/extensions
+    cp -r ${uuid} $out/share/gnome-shell/extensions
+    runHook postInstall
+  '';
+
+  passthru = {
+    updateScript = nix-update-script {
+      attrPath = "gnomeExtensions.${pname}";
+    };
+  };
+
+
+  meta = with lib; {
+    description = "A simple MPRIS indicator button for GNOME Shell";
+    license = licenses.gpl3;
+    maintainers = with maintainers; [ worldofpeace ];
+    platforms = gnome.gnome-shell.meta.platforms;
+    homepage = "https://github.com/JasonLG1979/gnome-shell-extension-mpris-indicator-button";
+    broken = versionOlder gnome.gnome-shell.version "3.34";
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/night-theme-switcher/default.nix b/pkgs/desktops/gnome/extensions/night-theme-switcher/default.nix
new file mode 100644
index 00000000000..fd0d2dbb578
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/night-theme-switcher/default.nix
@@ -0,0 +1,32 @@
+{ lib, stdenv, fetchFromGitLab, glib, gnome, unzip }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-night-theme-switcher";
+  version = "40";
+
+  src = fetchFromGitLab {
+    owner = "rmnvgr";
+    repo = "nightthemeswitcher-gnome-shell-extension";
+    rev = "v${version}";
+    sha256 = "0z11y18bgdc0y41hrrzzgi4lagm2cg06x12jgdnary1ycng7xja0";
+  };
+
+  nativeBuildInputs = [ unzip ];
+  buildInputs = [ glib gnome.gnome-shell ];
+
+  uuid = "nightthemeswitcher@romainvigier.fr";
+
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/share/gnome-shell/extensions/
+    unzip build/${uuid}.shell-extension.zip -d $out/share/gnome-shell/extensions/${uuid}
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "Automatically change the GTK theme to dark variant when Night Light activates";
+    license = licenses.gpl3;
+    maintainers = with maintainers; [ jonafato ];
+    homepage = "https://gitlab.com/rmnvgr/nightthemeswitcher-gnome-shell-extension/";
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/no-title-bar/default.nix b/pkgs/desktops/gnome/extensions/no-title-bar/default.nix
new file mode 100644
index 00000000000..ad588be18ce
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/no-title-bar/default.nix
@@ -0,0 +1,35 @@
+{ lib, stdenv, fetchFromGitHub, substituteAll, glib, gettext, xorg }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-no-title-bar";
+  version = "11";
+
+  src = fetchFromGitHub {
+    owner = "poehlerj";
+    repo = "no-title-bar";
+    rev = "V_${version}";
+    sha256 = "07ddw47binlsbyvgy4xkdjvd40zyp7nwd17r6k7w54d50vmnwhvb";
+  };
+
+  nativeBuildInputs = [ glib gettext ];
+
+  patches = [
+    (substituteAll {
+      src = ./fix-paths.patch;
+      xprop = "${xorg.xprop}/bin/xprop";
+      xwininfo = "${xorg.xwininfo}/bin/xwininfo";
+    })
+  ];
+
+  makeFlags = [ "INSTALLBASE=$(out)/share/gnome-shell/extensions" ];
+
+  uuid = "no-title-bar@jonaspoehler.de";
+
+  meta = with lib; {
+    description = "Integrates maximized windows with the top panel";
+    homepage = "https://github.com/poehlerj/no-title-bar";
+    license = licenses.gpl2;
+    maintainers = with maintainers; [ jonafato svsdep maxeaubrey ];
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/no-title-bar/fix-paths.patch b/pkgs/desktops/gnome/extensions/no-title-bar/fix-paths.patch
new file mode 100644
index 00000000000..fb2d3d57e51
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/no-title-bar/fix-paths.patch
@@ -0,0 +1,56 @@
+diff --git a/decoration.js b/decoration.js
+index d1ff3dd..ff4193f 100644
+--- a/decoration.js
++++ b/decoration.js
+@@ -223,7 +223,7 @@ var Decoration = class {
+ 
+         let winId = this._guessWindowXID(win);
+ 
+-        let xprops = GLib.spawn_command_line_sync(`xprop -id ${winId}`);
++        let xprops = GLib.spawn_command_line_sync(`@xprop@ -id ${winId}`);
+         if (!xprops[0]) {
+             Utils.log_debug(`Unable to determine windows '${win.get_title()}' original state`);
+             return win._noTitleBarOriginalState = WindowState.UNKNOWN;
+@@ -237,7 +237,7 @@ var Decoration = class {
+         let prop = '_MOTIF_WM_HINTS';
+         let value = '0x2, 0x0, %s, 0x0, 0x0'.format(hide ? '0x2' : '0x1');
+ 
+-        GLib.spawn_command_line_sync(`xprop -id ${windId} -f ${prop} 32c -set ${prop} "${value}"`);
++        GLib.spawn_command_line_sync(`@xprop@ -id ${windId} -f ${prop} 32c -set ${prop} "${value}"`);
+         if (!hide && !win.titlebar_is_onscreen()) {
+             Utils.log_debug(`Shoving titlebar onscreen for window '${win.get_title()}'`);
+             win.shove_titlebar_onscreen();
+@@ -354,7 +354,7 @@ var Decoration = class {
+         let act = win.get_compositor_private();
+         let xwindow = act && act['x-window'];
+         if (xwindow) {
+-            let xwininfo = GLib.spawn_command_line_sync('xwininfo -children -id 0x%x'.format(xwindow));
++            let xwininfo = GLib.spawn_command_line_sync('@xwininfo@ -children -id 0x%x'.format(xwindow));
+             if (xwininfo[0]) {
+                 let str = ByteArray.toString(xwininfo[1]);
+ 
+@@ -384,7 +384,7 @@ var Decoration = class {
+         // Try enumerating all available windows and match the title. Note that this
+         // may be necessary if the title contains special characters and `x-window`
+         // is not available.
+-        let result = GLib.spawn_command_line_sync('xprop -root _NET_CLIENT_LIST');
++        let result = GLib.spawn_command_line_sync('@xprop@ -root _NET_CLIENT_LIST');
+         if (result[0]) {
+             let str = ByteArray.toString(result[1]);
+ 
+@@ -395,7 +395,7 @@ var Decoration = class {
+ 
+             // For each window ID, check if the title matches the desired title.
+             for (var i = 0; i < windowList.length; ++i) {
+-                let cmd = 'xprop -id "' + windowList[i] + '" _NET_WM_NAME _NO_TITLE_BAR_ORIGINAL_STATE';
++                let cmd = '@xprop@ -id "' + windowList[i] + '" _NET_WM_NAME _NO_TITLE_BAR_ORIGINAL_STATE';
+                 let result = GLib.spawn_command_line_sync(cmd);
+ 
+                 if (result[0]) {
+@@ -455,4 +455,4 @@ var Decoration = class {
+         let styleContent = this._updateUserStyles();
+         GLib.file_set_contents(this._userStylesPath, styleContent);
+     }
+-}
+\ No newline at end of file
++}
diff --git a/pkgs/desktops/gnome/extensions/noannoyance/default.nix b/pkgs/desktops/gnome/extensions/noannoyance/default.nix
new file mode 100644
index 00000000000..4763d905755
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/noannoyance/default.nix
@@ -0,0 +1,31 @@
+{ stdenv
+, lib
+, fetchFromGitHub }:
+
+stdenv.mkDerivation rec {
+  pname = "noannoyance";
+  version = "unstable-2021-01-17";
+
+  src = fetchFromGitHub {
+    owner = "BjoernDaase";
+    repo = "noannoyance";
+    rev = "f6e76916336aee2f7c4141796f3c40c870d2b347";
+    sha256 = "1iy3nif8rjjcwf83fg9ds93fi7vmhliynmlwqnx036s3msmxvgs3";
+  };
+
+  uuid = "noannoyance@daase.net";
+
+  dontBuild = true;
+
+  installPhase = ''
+    mkdir -p $out/share/gnome-shell/extensions/${uuid}
+    cp metadata.json extension.js $out/share/gnome-shell/extensions/${uuid}
+  '';
+
+  meta = with lib; {
+    description = "Removes the 'Window is ready' notification and puts the window into focus";
+    homepage = "https://github.com/BjoernDaase/noannoyance";
+    license = licenses.gpl2Only;
+    maintainers = with maintainers; [ tu-maurice ];
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/paperwm/default.nix b/pkgs/desktops/gnome/extensions/paperwm/default.nix
new file mode 100644
index 00000000000..201628b4b42
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/paperwm/default.nix
@@ -0,0 +1,31 @@
+{ lib, stdenv, fetchFromGitHub }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-paperwm";
+  version = "38.1";
+
+  src = fetchFromGitHub {
+    owner = "paperwm";
+    repo = "PaperWM";
+    rev = version;
+    sha256 = "1jq15qrq3khqpjsjbcc17amdr1k53jkvambdacdf56xbqkycvlgs";
+  };
+
+  uuid = "paperwm@hedning:matrix.org";
+
+  dontBuild = true;
+
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/share/gnome-shell/extensions/${uuid}
+    cp -r . $out/share/gnome-shell/extensions/${uuid}
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "Tiled scrollable window management for Gnome Shell";
+    homepage = "https://github.com/paperwm/PaperWM";
+    license = licenses.gpl3;
+    maintainers = with maintainers; [ hedning ];
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/pidgin-im-integration/default.nix b/pkgs/desktops/gnome/extensions/pidgin-im-integration/default.nix
new file mode 100644
index 00000000000..93ffcda830a
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/pidgin-im-integration/default.nix
@@ -0,0 +1,36 @@
+{ lib, stdenv, fetchFromGitHub, glib, gnome }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-pidgin-im-integration";
+  version = "32";
+
+  src = fetchFromGitHub {
+    owner = "muffinmad";
+    repo = "pidgin-im-gnome-shell-extension";
+    rev = "v${version}";
+    sha256 = "1jyg8r0s1v83sgg6y0jbsj2v37mglh8rvd8vi27fxnjq9xmg8kpc";
+  };
+
+  dontConfigure = true;
+  dontBuild = true;
+
+  installPhase = ''
+    runHook preInstall
+    share_dir="$prefix/share"
+    extensions_dir="$share_dir/gnome-shell/extensions/pidgin@muffinmad"
+    mkdir -p "$extensions_dir"
+    mv *.js metadata.json dbus.xml schemas locale "$extensions_dir"
+    runHook postInstall
+  '';
+
+  uuid = "pidgin@muffinmad";
+
+  meta = with lib; {
+    homepage = "https://github.com/muffinmad/pidgin-im-gnome-shell-extension";
+    description = "Make Pidgin IM conversations appear in the Gnome Shell message tray";
+    license = licenses.gpl2;
+    platforms = platforms.linux;
+    maintainers = with maintainers; [ ];
+    broken = versionAtLeast gnome.gnome-shell.version "3.32"; # Doesn't support 3.34
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/remove-dropdown-arrows/default.nix b/pkgs/desktops/gnome/extensions/remove-dropdown-arrows/default.nix
new file mode 100644
index 00000000000..e310f5dcf10
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/remove-dropdown-arrows/default.nix
@@ -0,0 +1,34 @@
+{ lib, stdenv, fetchFromGitHub }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-remove-dropdown-arrows";
+  version = "13";
+
+  src = fetchFromGitHub {
+    owner = "mpdeimos";
+    repo = "gnome-shell-remove-dropdown-arrows";
+    rev = "version/${version}";
+    sha256 = "09b2hnfbqym20pb1sfc8xiz7gs2kbs6b1s7xl8swc8dydhsbambk";
+  };
+
+  # This package has a Makefile, but it's used for publishing and linting, not
+  # for building. Disable the build phase so installing doesn't attempt to
+  # publish the extension.
+  dontBuild = true;
+
+  uuid = "remove-dropdown-arrows@mpdeimos.com";
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/share/gnome-shell/extensions/${uuid}
+    cp extension.js $out/share/gnome-shell/extensions/${uuid}
+    cp metadata.json $out/share/gnome-shell/extensions/${uuid}
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "Remove dropdown arrows from GNOME Shell Menus";
+    license = licenses.gpl3;
+    maintainers = with maintainers; [ jonafato ];
+    homepage = "https://github.com/mpdeimos/gnome-shell-remove-dropdown-arrows";
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/sound-output-device-chooser/default.nix b/pkgs/desktops/gnome/extensions/sound-output-device-chooser/default.nix
new file mode 100644
index 00000000000..e58d8ce6e42
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/sound-output-device-chooser/default.nix
@@ -0,0 +1,44 @@
+{ lib, stdenv
+, substituteAll
+, fetchFromGitHub
+, libpulseaudio
+, python3
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-sound-output-device-chooser";
+  version = "35";
+
+  src = fetchFromGitHub {
+    owner = "kgshank";
+    repo = "gse-sound-output-device-chooser";
+    rev = version;
+    sha256 = "sha256-Yl5ut6kJAkAAdCBiNFpwDgshXCLMmFH3/zhnFGpyKqs=";
+  };
+
+  patches = [
+    # Fix paths to libpulse and python
+    (substituteAll {
+      src = ./fix-paths.patch;
+      libpulse = "${libpulseaudio}/lib/libpulse.so";
+      python = python3.interpreter;
+    })
+  ];
+
+  dontBuild = true;
+
+  uuid = "sound-output-device-chooser@kgshank.net";
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/share/gnome-shell/extensions
+    cp -r ${uuid} $out/share/gnome-shell/extensions
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "GNOME Shell extension adding audio device chooser to panel";
+    license = licenses.gpl3Plus;
+    maintainers = with maintainers; [ jtojnar ];
+    homepage = "https://github.com/kgshank/gse-sound-output-device-chooser";
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/sound-output-device-chooser/fix-paths.patch b/pkgs/desktops/gnome/extensions/sound-output-device-chooser/fix-paths.patch
new file mode 100644
index 00000000000..1971bf1e5e7
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/sound-output-device-chooser/fix-paths.patch
@@ -0,0 +1,26 @@
+diff --git a/sound-output-device-chooser@kgshank.net/convenience.js b/sound-output-device-chooser@kgshank.net/convenience.js
+index 54ad06f..0860531 100644
+--- a/sound-output-device-chooser@kgshank.net/convenience.js
++++ b/sound-output-device-chooser@kgshank.net/convenience.js
+@@ -142,7 +142,7 @@ function refreshCards() {
+     if (newProfLogic) {
+         _log("New logic");
+         let pyLocation = Me.dir.get_child("utils/pa_helper.py").get_path();
+-        let pythonExec = ["python", "python3", "python2"].find(cmd => isCmdFound(cmd));
++        let pythonExec = '@python@';
+         if (!pythonExec) {
+             _log("ERROR: Python not found. fallback to default mode");
+             _settings.set_boolean(Prefs.NEW_PROFILE_ID, false);
+diff --git a/sound-output-device-chooser@kgshank.net/utils/libpulse_introspect.py b/sound-output-device-chooser@kgshank.net/utils/libpulse_introspect.py
+index c4d2484..262608d 100644
+--- a/sound-output-device-chooser@kgshank.net/utils/libpulse_introspect.py
++++ b/sound-output-device-chooser@kgshank.net/utils/libpulse_introspect.py
+@@ -82,7 +82,7 @@ else:
+ 
+ _libraries = {}
+ 
+-libpulse_library_name = find_library('pulse')
++libpulse_library_name = '@libpulse@'
+ if libpulse_library_name is None:
+     raise Exception('No libpulse.so library found!')
+ 
diff --git a/pkgs/desktops/gnome/extensions/system-monitor/default.nix b/pkgs/desktops/gnome/extensions/system-monitor/default.nix
new file mode 100644
index 00000000000..e7b5e8a1a9c
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/system-monitor/default.nix
@@ -0,0 +1,50 @@
+{ lib, stdenv, substituteAll, fetchFromGitHub, glib, glib-networking, libgtop, gnome }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-system-monitor";
+  version = "unstable-2021-04-08";
+
+  src = fetchFromGitHub {
+    owner = "paradoxxxzero";
+    repo = "gnome-shell-system-monitor-applet";
+    rev = "942603da39de12f50b1f86efbde92d7526d1290e";
+    sha256 = "0lzb7064bigw2xsqkzr8qfhp9wfmxyi3823j2782v99jpcz423aw";
+  };
+
+  buildInputs = [
+    glib
+    glib-networking
+    libgtop
+  ];
+
+  patches = [
+    (substituteAll {
+      src = ./paths_and_nonexisting_dirs.patch;
+      clutter_path = gnome.mutter.libdir; # this should not be used in settings but 🤷‍♀️
+      gtop_path = "${libgtop}/lib/girepository-1.0";
+      glib_net_path = "${glib-networking}/lib/girepository-1.0";
+    })
+  ];
+
+  buildPhase = ''
+    runHook preBuild
+    glib-compile-schemas --targetdir=${uuid}/schemas ${uuid}/schemas
+    runHook postBuild
+  '';
+
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/share/gnome-shell/extensions
+    cp -r ${uuid} $out/share/gnome-shell/extensions
+    runHook postInstall
+  '';
+
+  uuid = "system-monitor@paradoxxx.zero.gmail.com";
+
+  meta = with lib; {
+    description = "Display system informations in gnome shell status bar";
+    license = licenses.gpl3Plus;
+    maintainers = with maintainers; [ tiramiseb ];
+    homepage = "https://github.com/paradoxxxzero/gnome-shell-system-monitor-applet";
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/system-monitor/paths_and_nonexisting_dirs.patch b/pkgs/desktops/gnome/extensions/system-monitor/paths_and_nonexisting_dirs.patch
new file mode 100644
index 00000000000..280af965af3
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/system-monitor/paths_and_nonexisting_dirs.patch
@@ -0,0 +1,33 @@
+diff --git a/system-monitor@paradoxxx.zero.gmail.com/extension.js b/system-monitor@paradoxxx.zero.gmail.com/extension.js
+index de5e3d7..2d7824d 100644
+--- a/system-monitor@paradoxxx.zero.gmail.com/extension.js
++++ b/system-monitor@paradoxxx.zero.gmail.com/extension.js
+@@ -18,6 +18,9 @@
+ 
+ // Author: Florian Mounier aka paradoxxxzero
+ 
++imports.gi.GIRepository.Repository.prepend_search_path('@gtop_path@');
++imports.gi.GIRepository.Repository.prepend_search_path('@glib_net_path@');
++
+ /* Ugly. This is here so that we don't crash old libnm-glib based shells unnecessarily
+  * by loading the new libnm.so. Should go away eventually */
+ 
+@@ -407,7 +410,7 @@ const smMountsMonitor = class SystemMonitor_smMountsMonitor {
+         this.connected = false;
+ 
+         this._volumeMonitor = Gio.VolumeMonitor.get();
+-        let sys_mounts = ['/home', '/tmp', '/boot', '/usr', '/usr/local'];
++        let sys_mounts = ['/home', '/tmp', '/boot'];
+         this.base_mounts = ['/'];
+         sys_mounts.forEach((sMount) => {
+             if (this.is_sys_mount(sMount + '/')) {
+diff --git a/system-monitor@paradoxxx.zero.gmail.com/prefs.js b/system-monitor@paradoxxx.zero.gmail.com/prefs.js
+index 81d667c..0da4809 100644
+--- a/system-monitor@paradoxxx.zero.gmail.com/prefs.js
++++ b/system-monitor@paradoxxx.zero.gmail.com/prefs.js
+@@ -1,3 +1,5 @@
++imports.gi.GIRepository.Repository.prepend_search_path('@clutter_path@');
++
+ const Gtk = imports.gi.Gtk;
+ const Gio = imports.gi.Gio;
+ const Gdk = imports.gi.Gdk;
diff --git a/pkgs/desktops/gnome/extensions/taskwhisperer/default.nix b/pkgs/desktops/gnome/extensions/taskwhisperer/default.nix
new file mode 100644
index 00000000000..68d07e2d142
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/taskwhisperer/default.nix
@@ -0,0 +1,42 @@
+{ lib, stdenv, substituteAll, fetchFromGitHub, taskwarrior, gettext, runtimeShell }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-taskwhisperer";
+  version = "16";
+
+  src = fetchFromGitHub {
+    owner = "cinatic";
+    repo = "taskwhisperer";
+    rev = "v${version}";
+    sha256 = "05w2dfpr5vrydb7ij4nd2gb7c31nxix3j48rb798r4jzl1rakyah";
+  };
+
+  nativeBuildInputs = [
+    gettext
+  ];
+
+  buildInputs = [
+    taskwarrior
+  ];
+
+  uuid = "taskwhisperer-extension@infinicode.de";
+
+  makeFlags = [
+    "INSTALLBASE=${placeholder "out"}/share/gnome-shell/extensions"
+  ];
+
+  patches = [
+    (substituteAll {
+      src = ./fix-paths.patch;
+      task = "${taskwarrior}/bin/task";
+      shell = runtimeShell;
+    })
+  ];
+
+  meta = with lib; {
+    description = "GNOME Shell TaskWarrior GUI";
+    license = licenses.gpl3Plus;
+    maintainers = with maintainers; [ jonafato ];
+    homepage = "https://github.com/cinatic/taskwhisperer";
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/taskwhisperer/fix-paths.patch b/pkgs/desktops/gnome/extensions/taskwhisperer/fix-paths.patch
new file mode 100644
index 00000000000..2ea54f4b089
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/taskwhisperer/fix-paths.patch
@@ -0,0 +1,99 @@
+diff --git a/taskwhisperer-extension@infinicode.de/extra/create.sh b/taskwhisperer-extension@infinicode.de/extra/create.sh
+index a69e369..35d5ea1 100755
+--- a/taskwhisperer-extension@infinicode.de/extra/create.sh
++++ b/taskwhisperer-extension@infinicode.de/extra/create.sh
+@@ -1 +1 @@
+-bash -c "task add $1"
++bash -c "@task@ add $1"
+diff --git a/taskwhisperer-extension@infinicode.de/extra/modify.sh b/taskwhisperer-extension@infinicode.de/extra/modify.sh
+index 7964a26..8edd21b 100755
+--- a/taskwhisperer-extension@infinicode.de/extra/modify.sh
++++ b/taskwhisperer-extension@infinicode.de/extra/modify.sh
+@@ -1 +1 @@
+-bash -c "task $1 modify $2"
++bash -c "@task@ $1 modify $2"
+diff --git a/taskwhisperer-extension@infinicode.de/taskService.js b/taskwhisperer-extension@infinicode.de/taskService.js
+index ead7a12..aa36db4 100644
+--- a/taskwhisperer-extension@infinicode.de/taskService.js
++++ b/taskwhisperer-extension@infinicode.de/taskService.js
+@@ -182,7 +182,7 @@ const TaskService = class TaskService {
+ 
+         let project = projectName ? "project:" + projectName : "";
+ 
+-        let command = ['task', 'rc.json.array=on', status, project, 'export'];
++        let command = ['@task@', 'rc.json.array=on', status, project, 'export'];
+         let reader = new SpawnReader.SpawnReader();
+ 
+         let buffer = "";
+@@ -220,7 +220,7 @@ const TaskService = class TaskService {
+                 break;
+         }
+ 
+-        let shellProc = Gio.Subprocess.new(['task', status, 'projects'], Gio.SubprocessFlags.STDOUT_PIPE);
++        let shellProc = Gio.Subprocess.new(['@task@', status, 'projects'], Gio.SubprocessFlags.STDOUT_PIPE);
+ 
+         shellProc.wait_async(null, function (obj, result) {
+             let shellProcExited = true;
+@@ -261,7 +261,7 @@ const TaskService = class TaskService {
+             return;
+         }
+ 
+-        let shellProc = Gio.Subprocess.new(['task', taskID.toString(), 'done'], Gio.SubprocessFlags.STDOUT_PIPE);
++        let shellProc = Gio.Subprocess.new(['@task@', taskID.toString(), 'done'], Gio.SubprocessFlags.STDOUT_PIPE);
+ 
+         shellProc.wait_async(null, function (obj, result) {
+             let shellProcExited = true;
+@@ -290,7 +290,7 @@ const TaskService = class TaskService {
+             return;
+         }
+ 
+-        let shellProc = Gio.Subprocess.new(['task', 'modify', taskID.toString(), 'status:pending'], Gio.SubprocessFlags.STDOUT_PIPE);
++        let shellProc = Gio.Subprocess.new(['@task@', 'modify', taskID.toString(), 'status:pending'], Gio.SubprocessFlags.STDOUT_PIPE);
+ 
+         shellProc.wait_async(null, function (obj, result) {
+             let shellProcExited = true;
+@@ -318,7 +318,7 @@ const TaskService = class TaskService {
+         if (!taskID) {
+             return;
+         }
+-        let shellProc = Gio.Subprocess.new(['task', taskID.toString(), 'start'], Gio.SubprocessFlags.STDOUT_PIPE);
++        let shellProc = Gio.Subprocess.new(['@task@', taskID.toString(), 'start'], Gio.SubprocessFlags.STDOUT_PIPE);
+         shellProc.wait_async(null, function (obj, result) {
+             let shellProcExited = true;
+             shellProc.wait_finish(result);
+@@ -344,7 +344,7 @@ const TaskService = class TaskService {
+         if (!taskID) {
+             return;
+         }
+-        let shellProc = Gio.Subprocess.new(['task', taskID.toString(), 'stop'], Gio.SubprocessFlags.STDOUT_PIPE);
++        let shellProc = Gio.Subprocess.new(['@task@', taskID.toString(), 'stop'], Gio.SubprocessFlags.STDOUT_PIPE);
+         shellProc.wait_async(null, function (obj, result) {
+             let shellProcExited = true;
+             shellProc.wait_finish(result);
+@@ -374,7 +374,7 @@ const TaskService = class TaskService {
+         // FIXME: Gio.Subprocess: due to only passing string vector is allowed, it's not possible to directly pass the
+         //        input of the user to subprocess (why & how, if you can answer then please send msg to fh@infinicode.de)
+         //        bypassing problem with own shell script
+-        let shellProc = Gio.Subprocess.new(['/bin/sh', EXTENSIONDIR + '/extra/modify.sh', taskID.toString(), params], Gio.SubprocessFlags.STDOUT_PIPE + Gio.SubprocessFlags.STDERR_MERGE);
++        let shellProc = Gio.Subprocess.new(['@shell@', EXTENSIONDIR + '/extra/modify.sh', taskID.toString(), params], Gio.SubprocessFlags.STDOUT_PIPE + Gio.SubprocessFlags.STDERR_MERGE);
+ 
+         shellProc.wait_async(null, function (obj, result) {
+             let shellProcExited = true;
+@@ -403,7 +403,7 @@ const TaskService = class TaskService {
+         // FIXME: Gio.Subprocess: due to only passing string vector is allowed, it's not possible to directly pass the
+         //        input of the user to subprocess (why & how, if you can answer then please send msg to fh@infinicode.de)
+         //        bypassing problem with own shell script
+-        let shellProc = Gio.Subprocess.new(['/bin/sh', EXTENSIONDIR + '/extra/create.sh', params], Gio.SubprocessFlags.STDOUT_PIPE + Gio.SubprocessFlags.STDERR_MERGE);
++        let shellProc = Gio.Subprocess.new(['@shell@', EXTENSIONDIR + '/extra/create.sh', params], Gio.SubprocessFlags.STDOUT_PIPE + Gio.SubprocessFlags.STDERR_MERGE);
+ 
+         shellProc.wait_async(null, function (obj, result) {
+             let shellProcExited = true;
+@@ -432,7 +432,7 @@ const TaskService = class TaskService {
+         let shellProc;
+ 
+         try {
+-            shellProc = Gio.Subprocess.new(['task', 'sync'], Gio.SubprocessFlags.STDOUT_PIPE);
++            shellProc = Gio.Subprocess.new(['@task@', 'sync'], Gio.SubprocessFlags.STDOUT_PIPE);
+         } catch (err) {
+             onError(err);
+             return;
diff --git a/pkgs/desktops/gnome/extensions/tilingnome/default.nix b/pkgs/desktops/gnome/extensions/tilingnome/default.nix
new file mode 100644
index 00000000000..c1ca77d9d73
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/tilingnome/default.nix
@@ -0,0 +1,38 @@
+{ stdenv, lib, fetchFromGitHub, glib, gnome }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-tilingnome-unstable";
+  version = "unstable-2019-09-19";
+
+  src = fetchFromGitHub {
+    owner = "rliang";
+    repo = "gnome-shell-extension-tilingnome";
+    rev = "f401c20c9721d85e6b3e30d1e822a200db370407";
+    sha256 = "1hq9g9bxqpzqrdj9zm0irld8r6q4w1m4b00jya7wsny8rzb1s0y2";
+  };
+
+  nativeBuildInputs = [ glib ];
+
+  buildPhase = ''
+    runHook preBuild
+    glib-compile-schemas .
+    runHook postBuild
+  '';
+
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/share/gnome-shell/extensions/${uuid}
+    cp -r * $out/share/gnome-shell/extensions/${uuid}/
+    runHook postInstall
+  '';
+
+  uuid = "tilingnome@rliang.github.com";
+
+  meta = with lib; {
+    description = "Tiling window management for GNOME Shell";
+    license = licenses.gpl2;
+    maintainers = with maintainers; [ benley ];
+    homepage = "https://github.com/rliang/gnome-shell-extension-tilingnome";
+    platforms = gnome.gnome-shell.meta.platforms;
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/timepp/default.nix b/pkgs/desktops/gnome/extensions/timepp/default.nix
new file mode 100644
index 00000000000..cb4234a2513
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/timepp/default.nix
@@ -0,0 +1,28 @@
+{ lib, stdenv, fetchFromGitHub, gnome }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-timepp";
+  version = "unstable-2020-03-15";
+
+  src = fetchFromGitHub {
+    owner = "zagortenay333";
+    repo = "timepp__gnome";
+    rev = "34ae477a51267cc1e85992a80cf85a1a7b7005c1";
+    sha256 = "1v0xbrp0x5dwizscxh7h984pax4n92bj8iyw3qvjk27ynpxq8ag1";
+  };
+
+  uuid = "timepp@zagortenay333";
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/share/gnome-shell/extensions/${uuid}
+    cp -r . $out/share/gnome-shell/extensions/${uuid}
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "A todo.txt manager, time tracker, timer, stopwatch, pomodoro, and alarms gnome-shell extension.";
+    homepage = "https://github.com/zagortenay333/timepp__gnome";
+    license = licenses.gpl3;
+    maintainers = with maintainers; [ svsdep ];
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/topicons-plus/default.nix b/pkgs/desktops/gnome/extensions/topicons-plus/default.nix
new file mode 100644
index 00000000000..084548e1a10
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/topicons-plus/default.nix
@@ -0,0 +1,28 @@
+{ lib, stdenv, fetchFromGitHub, glib, gettext }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-topicons-plus";
+  version = "27";
+
+  src = fetchFromGitHub {
+    owner = "phocean";
+    repo = "TopIcons-plus";
+    rev = version;
+    sha256 = "1p3jlvs4zgnrvy8am7myivv4rnnshjp49kg87rd22qqyvcz51ykr";
+  };
+
+  buildInputs = [ glib ];
+
+  nativeBuildInputs = [ gettext ];
+
+  makeFlags = [ "INSTALL_PATH=$(out)/share/gnome-shell/extensions" ];
+
+  uuid = "TopIcons@phocean.net";
+
+  meta = with lib; {
+    description = "Brings all icons back to the top panel, so that it's easier to keep track of apps running in the backround";
+    license = licenses.gpl2Only;
+    maintainers = with maintainers; [ eperuffo ];
+    homepage = "https://github.com/phocean/TopIcons-plus";
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/unite/default.nix b/pkgs/desktops/gnome/extensions/unite/default.nix
new file mode 100644
index 00000000000..1fbd31ec10a
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/unite/default.nix
@@ -0,0 +1,40 @@
+{ lib, stdenv, gnome, fetchFromGitHub, xprop, glib }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-unite";
+  version = "53";
+
+  src = fetchFromGitHub {
+    owner = "hardpixel";
+    repo = "unite-shell";
+    rev = "v${version}";
+    sha256 = "0fw9wqf362h2yd67fhgbhqx0b2fwcl25wxmb92dqwigxjcj0dnw6";
+  };
+
+  uuid = "unite@hardpixel.eu";
+
+  nativeBuildInputs = [ glib ];
+
+  buildInputs = [ xprop ];
+
+  buildPhase = ''
+    runHook preBuild
+    glib-compile-schemas --strict --targetdir=${uuid}/schemas/ ${uuid}/schemas
+    runHook postBuild
+  '';
+
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/share/gnome-shell/extensions
+    cp -r ${uuid} $out/share/gnome-shell/extensions
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "Unite is a GNOME Shell extension which makes a few layout tweaks to the top panel and removes window decorations to make it look like Ubuntu Unity Shell";
+    license = licenses.gpl3Only;
+    maintainers = with maintainers; [ rhoriguchi ];
+    homepage = "https://github.com/hardpixel/unite-shell";
+    broken = versionOlder gnome.gnome-shell.version "3.32";
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/window-corner-preview/default.nix b/pkgs/desktops/gnome/extensions/window-corner-preview/default.nix
new file mode 100644
index 00000000000..0e71345bb8a
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/window-corner-preview/default.nix
@@ -0,0 +1,31 @@
+{ lib, stdenv, fetchFromGitHub, gnome }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-window-corner-preview";
+  version = "unstable-2019-04-03";
+
+  src = fetchFromGitHub {
+    owner = "medenagan";
+    repo = "window-corner-preview";
+    rev = "a95bb1389d94474efab7509aac592fb58fff6006";
+    sha256 = "03v18j9l0fb64xrg3swf1vcgl0kpgwjlp8ddn068bpvghrsvgfah";
+  };
+
+  dontBuild = true;
+
+  uuid = "window-corner-preview@fabiomereu.it";
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/share/gnome-shell/extensions
+    cp -r ${uuid} $out/share/gnome-shell/extensions
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "GNOME Shell extension showing a video preview on the corner of the screen";
+    license = licenses.mit;
+    maintainers = with maintainers; [ jtojnar ];
+    homepage = "https://github.com/medenagan/window-corner-preview";
+    broken = lib.versionAtLeast gnome.gnome-shell.version "3.32"; # Doesn't support 3.34
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/window-is-ready-remover/default.nix b/pkgs/desktops/gnome/extensions/window-is-ready-remover/default.nix
new file mode 100644
index 00000000000..3f0e9e71b57
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/window-is-ready-remover/default.nix
@@ -0,0 +1,28 @@
+{ lib, stdenv, fetchFromGitHub }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-window-is-ready-remover";
+  version = "1.02";
+
+  src = fetchFromGitHub {
+    owner = "nunofarruca";
+    repo = "WindowIsReady_Remover";
+    rev = "v${version}";
+    sha256 = "1xaf95gn0if44avvkjxyf8fl29y28idn9shnrks0m9k67jcwv8ns";
+  };
+
+  uuid = "windowIsReady_Remover@nunofarruca@gmail.com";
+
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/share/gnome-shell/extensions/
+    cp -r ${uuid} $out/share/gnome-shell/extensions/${uuid}
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "GNOME Shell extension removing window is ready notification";
+    homepage = "https://github.com/nunofarruca/WindowIsReady_Remover";
+    license = licenses.asl20;
+  };
+}
diff --git a/pkgs/desktops/gnome/extensions/workspace-matrix/default.nix b/pkgs/desktops/gnome/extensions/workspace-matrix/default.nix
new file mode 100644
index 00000000000..eb1d6e7e319
--- /dev/null
+++ b/pkgs/desktops/gnome/extensions/workspace-matrix/default.nix
@@ -0,0 +1,36 @@
+{ lib, stdenv, fetchFromGitHub, findutils, glib }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-extension-workspace-matrix";
+  version = "4.0.2";
+
+  src = fetchFromGitHub {
+    owner = "mzur";
+    repo = "gnome-shell-wsmatrix";
+    rev = "v${version}";
+    sha256 = "0dbn6b3fdd7yblk0mhsmaiqs3mwgcf3khkx1dsnlqn5hcs0a3myd";
+  };
+
+  uuid = "wsmatrix@martin.zurowietz.de";
+
+  nativeBuildInputs = [
+    findutils
+    glib
+  ];
+
+  buildFlags = "schemas";
+
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/share/gnome-shell/extensions
+    cp -r ${uuid} $out/share/gnome-shell/extensions
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "Arrange workspaces in a two dimensional grid with workspace thumbnails";
+    license = licenses.gpl3Plus;
+    maintainers = with maintainers; [ chkno ];
+    homepage =  "https://github.com/mzur/gnome-shell-wsmatrix";
+  };
+}
diff --git a/pkgs/desktops/gnome/find-latest-version.py b/pkgs/desktops/gnome/find-latest-version.py
new file mode 100644
index 00000000000..3078999e3e5
--- /dev/null
+++ b/pkgs/desktops/gnome/find-latest-version.py
@@ -0,0 +1,89 @@
+import argparse
+import math
+import json
+import requests
+import sys
+from libversion import Version
+from typing import Optional
+
+
+def version_to_list(version):
+    return list(map(int, version.split(".")))
+
+
+def odd_unstable(version: Version, selected):
+    try:
+        version = version_to_list(version.value)
+    except:
+        # Failing to parse as a list of numbers likely means the version contains a string tag like “beta”, therefore it is not a stable release.
+        return selected != "stable"
+
+    if len(version) < 2:
+        return True
+
+    even = version[1] % 2 == 0
+    prerelease = (version[1] >= 90 and version[1] < 100) or (version[1] >= 900 and version[1] < 1000)
+    stable = even and not prerelease
+    if selected == "stable":
+        return stable
+    else:
+        return True
+
+
+def tagged(version: Version, selected):
+    if selected == "stable":
+        return not ("alpha" in version.value or "beta" in version.value or "rc" in version.value)
+    else:
+        return True
+
+
+def no_policy(version: Version, selected):
+    return True
+
+
+version_policies = {
+    "odd-unstable": odd_unstable,
+    "tagged": tagged,
+    "none": no_policy,
+}
+
+
+def make_version_policy(version_predicate, selected, upper_bound: Optional[Version]):
+    if not upper_bound:
+        return lambda version: version_predicate(version, selected)
+    else:
+        return lambda version: version_predicate(version, selected) and version < upper_bound
+
+
+parser = argparse.ArgumentParser(description="Find latest version for a GNOME package by crawling their release server.")
+parser.add_argument("package-name", help="Name of the directory in https://ftp.gnome.org/pub/GNOME/sources/ containing the package.")
+parser.add_argument("version-policy", help="Policy determining which versions are considered stable. GNOME packages usually denote stability by alpha/beta/rc tag in the version. For older packages, odd minor versions are unstable but there are exceptions.", choices=version_policies.keys(), nargs="?", default="tagged")
+parser.add_argument("requested-release", help="Most of the time, we will want to update to stable version but sometimes it is useful to test.", choices=["stable", "unstable"], nargs="?", default="stable")
+parser.add_argument("--upper-bound", dest="upper-bound", help="Only look for versions older than this one (useful for pinning dependencies).")
+
+
+if __name__ == "__main__":
+    args = parser.parse_args()
+
+    package_name = getattr(args, "package-name")
+    requested_release = getattr(args, "requested-release")
+    upper_bound = getattr(args, "upper-bound")
+    if upper_bound:
+        upper_bound = Version(upper_bound)
+    version_predicate = version_policies[getattr(args, "version-policy")]
+    version_policy = make_version_policy(version_predicate, requested_release, upper_bound)
+
+    # The structure of cache.json: https://gitlab.gnome.org/Infrastructure/sysadmin-bin/blob/master/ftpadmin#L762
+    cache = json.loads(requests.get(f"https://ftp.gnome.org/pub/GNOME/sources/{package_name}/cache.json").text)
+    if type(cache) != list or cache[0] != 4:
+        print("Unknown format of cache.json file.", file=sys.stderr)
+        sys.exit(1)
+
+    versions = map(Version, cache[2][package_name])
+    versions = sorted(filter(version_policy, versions))
+
+    if len(versions) == 0:
+        print("No versions matched.", file=sys.stderr)
+        sys.exit(1)
+
+    print(versions[-1].value)
diff --git a/pkgs/desktops/gnome/games/aisleriot/default.nix b/pkgs/desktops/gnome/games/aisleriot/default.nix
new file mode 100644
index 00000000000..8893846698e
--- /dev/null
+++ b/pkgs/desktops/gnome/games/aisleriot/default.nix
@@ -0,0 +1,77 @@
+{ lib, stdenv
+, fetchFromGitLab
+, pkg-config
+, gnome
+, itstool
+, gtk3
+, wrapGAppsHook
+, meson
+, librsvg
+, libxml2
+, desktop-file-utils
+, pysolfc
+, guile
+, libcanberra-gtk3
+, ninja
+, appstream-glib
+, yelp-tools
+}:
+
+stdenv.mkDerivation rec {
+  pname = "aisleriot";
+  version = "3.22.13";
+
+  src = fetchFromGitLab {
+    domain = "gitlab.gnome.org";
+    owner = "GNOME";
+    repo = pname;
+    rev = version;
+    sha256 = "05k84bbgrrxchxg08l1jjcz384kpjdmxd24g0wnf731aa9zcnp5k";
+  };
+
+  nativeBuildInputs = [
+    wrapGAppsHook
+    meson
+    ninja
+    appstream-glib
+    pkg-config
+    itstool
+    libxml2
+    desktop-file-utils
+    yelp-tools
+  ];
+
+  buildInputs = [
+    gtk3
+    librsvg
+    guile
+    libcanberra-gtk3
+    pysolfc
+  ];
+
+  prePatch = ''
+    patchShebangs cards/meson_svgz.sh
+    patchShebangs data/meson_desktopfile.py
+    patchShebangs data/icons/meson_updateiconcache.py
+    patchShebangs src/lib/meson_compileschemas.py
+  '';
+
+  mesonFlags = [
+    "-Dtheme_kde=false"
+  ];
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Aisleriot";
+    description = "A collection of patience games written in guile scheme";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl3Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/games/atomix/default.nix b/pkgs/desktops/gnome/games/atomix/default.nix
new file mode 100644
index 00000000000..43d9aaa7680
--- /dev/null
+++ b/pkgs/desktops/gnome/games/atomix/default.nix
@@ -0,0 +1,37 @@
+{ lib, stdenv, fetchurl, meson, ninja, pkg-config, wrapGAppsHook, python3
+, gettext, gnome, glib, gtk3, libgnome-games-support, gdk-pixbuf }:
+
+let
+  pname = "atomix";
+  version = "3.34.0";
+in stdenv.mkDerivation rec {
+  name = "${pname}-${version}";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${name}.tar.xz";
+    sha256 = "0h909a4mccf160hi0aimyicqhq2b0gk1dmqp7qwf87qghfrw6m00";
+  };
+
+  nativeBuildInputs = [ meson ninja pkg-config gettext wrapGAppsHook python3 ];
+  buildInputs = [ glib gtk3 gdk-pixbuf libgnome-games-support gnome.adwaita-icon-theme ];
+
+  postPatch = ''
+    chmod +x meson_post_install.py
+    patchShebangs meson_post_install.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    description = "Puzzle game where you move atoms to build a molecule";
+    homepage = "https://wiki.gnome.org/Apps/Atomix";
+    license = licenses.gpl2Plus;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/games/five-or-more/default.nix b/pkgs/desktops/gnome/games/five-or-more/default.nix
new file mode 100644
index 00000000000..f01d137979e
--- /dev/null
+++ b/pkgs/desktops/gnome/games/five-or-more/default.nix
@@ -0,0 +1,40 @@
+{ lib, stdenv, fetchurl, meson, ninja, pkg-config, gnome, gtk3, wrapGAppsHook
+, librsvg, libgnome-games-support, gettext, itstool, libxml2, python3, vala }:
+
+stdenv.mkDerivation rec {
+  pname = "five-or-more";
+  version = "3.32.2";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/five-or-more/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "19pf8wzbf3ciqf2k4bj9sddvyhckfd62x86pnqr6s8h4vn9jc6ii";
+  };
+
+  nativeBuildInputs = [
+    meson ninja pkg-config gettext itstool libxml2 python3 wrapGAppsHook
+    vala
+  ];
+  buildInputs = [
+    gtk3 librsvg libgnome-games-support gnome.adwaita-icon-theme
+  ];
+
+  postPatch = ''
+    chmod +x meson_post_install.py # patchShebangs requires executable file
+    patchShebangs meson_post_install.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "five-or-more";
+      attrPath = "gnome.five-or-more";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Five_or_more";
+    description = "Remove colored balls from the board by forming lines";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/games/four-in-a-row/default.nix b/pkgs/desktops/gnome/games/four-in-a-row/default.nix
new file mode 100644
index 00000000000..2c6899ee1aa
--- /dev/null
+++ b/pkgs/desktops/gnome/games/four-in-a-row/default.nix
@@ -0,0 +1,39 @@
+{ lib, stdenv, fetchurl, pkg-config, gnome, gtk3, wrapGAppsHook
+, gettext, meson, gsound, librsvg, itstool, vala
+, python3, ninja, desktop-file-utils }:
+
+stdenv.mkDerivation rec {
+  pname = "four-in-a-row";
+  version = "3.38.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/four-in-a-row/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "10ji60bdfdzb6wk5dkwjc3yww7hqi3yjcx1k1z7x2521h2dpdli1";
+  };
+
+  nativeBuildInputs = [
+    pkg-config wrapGAppsHook gettext meson itstool vala
+    ninja python3 desktop-file-utils
+  ];
+  buildInputs = [ gtk3 gsound librsvg gnome.adwaita-icon-theme ];
+
+  postPatch = ''
+    chmod +x build-aux/meson_post_install.py
+    patchShebangs build-aux/meson_post_install.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "four-in-a-row";
+      attrPath = "gnome.four-in-a-row";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Four-in-a-row";
+    description = "Make lines of the same color to win";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/games/gnome-chess/default.nix b/pkgs/desktops/gnome/games/gnome-chess/default.nix
new file mode 100644
index 00000000000..c632bce407b
--- /dev/null
+++ b/pkgs/desktops/gnome/games/gnome-chess/default.nix
@@ -0,0 +1,68 @@
+{ lib
+, stdenv
+, fetchurl
+, meson
+, ninja
+, vala
+, pkg-config
+, wrapGAppsHook4
+, gobject-introspection
+, gettext
+, itstool
+, libxml2
+, python3
+, gnome
+, glib
+, gtk4
+, librsvg
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-chess";
+  version = "40.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-chess/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "132nc96z0bryyi9d5gljsbwsa71rl8wm5w57jbhpwiv4fyjhgybk";
+  };
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    vala
+    pkg-config
+    gettext
+    itstool
+    libxml2
+    python3
+    wrapGAppsHook4
+    gobject-introspection
+  ];
+
+  buildInputs = [
+    glib
+    gtk4
+    librsvg
+    gnome.adwaita-icon-theme
+  ];
+
+  postPatch = ''
+    chmod +x meson_post_install.py
+    patchShebangs meson_post_install.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "gnome-chess";
+      attrPath = "gnome.gnome-chess";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Chess";
+    description = "Play the classic two-player boardgame of chess";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl3Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/games/gnome-klotski/default.nix b/pkgs/desktops/gnome/games/gnome-klotski/default.nix
new file mode 100644
index 00000000000..bb4cdae8fa3
--- /dev/null
+++ b/pkgs/desktops/gnome/games/gnome-klotski/default.nix
@@ -0,0 +1,43 @@
+{ lib, stdenv, fetchurl, pkg-config, vala, gnome, gtk3, wrapGAppsHook, appstream-glib, desktop-file-utils
+, glib, librsvg, libxml2, gettext, itstool, libgee, libgnome-games-support
+, meson, ninja, python3
+}:
+
+let
+  pname = "gnome-klotski";
+  version = "3.38.2";
+in stdenv.mkDerivation rec {
+  name = "${pname}-${version}";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${name}.tar.xz";
+    sha256 = "1qm01hdd5yp8chig62bj10912vclbdvywwczs84sfg4zci2phqwi";
+  };
+
+  nativeBuildInputs = [
+    pkg-config vala meson ninja python3 wrapGAppsHook
+    gettext itstool libxml2 appstream-glib desktop-file-utils
+    gnome.adwaita-icon-theme
+  ];
+  buildInputs = [ glib gtk3 librsvg libgee libgnome-games-support ];
+
+  postPatch = ''
+    chmod +x build-aux/meson_post_install.py
+    patchShebangs build-aux/meson_post_install.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Klotski";
+    description = "Slide blocks to solve the puzzle";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/games/gnome-mahjongg/default.nix b/pkgs/desktops/gnome/games/gnome-mahjongg/default.nix
new file mode 100644
index 00000000000..7ef68e470e1
--- /dev/null
+++ b/pkgs/desktops/gnome/games/gnome-mahjongg/default.nix
@@ -0,0 +1,41 @@
+{ lib, stdenv, fetchurl, pkg-config, gnome, gtk3, wrapGAppsHook
+, librsvg, gettext, itstool, libxml2
+, meson, ninja, glib, vala, desktop-file-utils
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-mahjongg";
+  version = "3.38.3";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-mahjongg/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "144ia3zn9rhwa1xbdkvsz6m0dsysl6mxvqw9bnrlh845hmyy9cfj";
+  };
+
+  nativeBuildInputs = [
+    meson ninja vala desktop-file-utils
+    pkg-config gnome.adwaita-icon-theme
+    libxml2 itstool gettext wrapGAppsHook
+    glib # for glib-compile-schemas
+  ];
+  buildInputs = [
+    glib
+    gtk3
+    librsvg
+  ];
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Mahjongg";
+    description = "Disassemble a pile of tiles by removing matching pairs";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl3Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/games/gnome-mines/default.nix b/pkgs/desktops/gnome/games/gnome-mines/default.nix
new file mode 100644
index 00000000000..6a7168badbf
--- /dev/null
+++ b/pkgs/desktops/gnome/games/gnome-mines/default.nix
@@ -0,0 +1,39 @@
+{ lib, stdenv, fetchurl, meson, ninja, vala, gobject-introspection, pkg-config, gnome, gtk3, wrapGAppsHook
+, librsvg, gettext, itstool, python3, libxml2, libgnome-games-support, libgee, desktop-file-utils }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-mines";
+  version = "40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "0sf6kdvhr4pr3hddnj6ql9larz2wy108sri31id6x9g459nbly8z";
+  };
+
+  # gobject-introspection for finding vapi files
+  nativeBuildInputs = [
+    meson ninja vala gobject-introspection pkg-config gettext itstool python3
+    libxml2 wrapGAppsHook desktop-file-utils
+  ];
+  buildInputs = [ gtk3 librsvg gnome.adwaita-icon-theme libgnome-games-support libgee ];
+
+  postPatch = ''
+    chmod +x build-aux/meson_post_install.py
+    patchShebangs build-aux/meson_post_install.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "gnome-mines";
+      attrPath = "gnome.gnome-mines";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Mines";
+    description = "Clear hidden mines from a minefield";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl3;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/games/gnome-nibbles/default.nix b/pkgs/desktops/gnome/games/gnome-nibbles/default.nix
new file mode 100644
index 00000000000..34b50f2244f
--- /dev/null
+++ b/pkgs/desktops/gnome/games/gnome-nibbles/default.nix
@@ -0,0 +1,84 @@
+{ lib
+, stdenv
+, fetchurl
+, fetchpatch
+, pkg-config
+, gnome
+, gtk3
+, wrapGAppsHook
+, librsvg
+, gsound
+, clutter-gtk
+, gettext
+, itstool
+, vala
+, python3
+, libxml2
+, libgee
+, libgnome-games-support
+, meson
+, ninja
+, desktop-file-utils
+, hicolor-icon-theme
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-nibbles";
+  version = "3.38.2";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-nibbles/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "1naknfbciydbym79a0jq039xf0033z8gyln48c0qsbcfr2qn8yj5";
+  };
+
+  patches = [
+    # Fix build with recent Vala.
+    (fetchpatch {
+      url = "https://gitlab.gnome.org/GNOME/gnome-nibbles/-/commit/62964e9256fcac616109af874dbb2bd8342a9853.patch";
+      sha256 = "4VijELRxycS8rwi1HU9U3h9K/VtdQjJntfdtMN9Uz34=";
+    })
+    (fetchpatch {
+      url = "https://gitlab.gnome.org/GNOME/gnome-nibbles/-/commit/1b48446068608aff9b5edf1fdbd4b8c0d9f0be94.patch";
+      sha256 = "X0+Go5ae4F06WTPDYc2HIIax8X4RDgUGO6A6Qp8UifQ=";
+    })
+  ];
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    vala
+    python3
+    pkg-config
+    wrapGAppsHook
+    gettext
+    itstool
+    libxml2
+    desktop-file-utils
+    hicolor-icon-theme
+  ];
+
+  buildInputs = [
+    gtk3
+    librsvg
+    gsound
+    clutter-gtk
+    gnome.adwaita-icon-theme
+    libgee
+    libgnome-games-support
+  ];
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "gnome-nibbles";
+      attrPath = "gnome.gnome-nibbles";
+    };
+  };
+
+  meta = with lib; {
+    description = "Guide a worm around a maze";
+    homepage = "https://wiki.gnome.org/Apps/Nibbles";
+    license = licenses.gpl2;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/games/gnome-robots/default.nix b/pkgs/desktops/gnome/games/gnome-robots/default.nix
new file mode 100644
index 00000000000..c9f7cbfc213
--- /dev/null
+++ b/pkgs/desktops/gnome/games/gnome-robots/default.nix
@@ -0,0 +1,73 @@
+{ lib
+, stdenv
+, fetchurl
+, pkg-config
+, gnome
+, gtk3
+, wrapGAppsHook
+, librsvg
+, gsound
+, gettext
+, itstool
+, libxml2
+, libgnome-games-support
+, libgee
+, meson
+, ninja
+, vala
+, python3
+, desktop-file-utils
+, adwaita-icon-theme
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-robots";
+  version = "40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-robots/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "04fbykj576dq1h6cycgfhh8wd6yxmlsqykvj188sbwahay42zgvg";
+  };
+
+  nativeBuildInputs = [
+    pkg-config
+    meson
+    ninja
+    vala
+    python3
+    libxml2
+    wrapGAppsHook
+    gettext
+    itstool
+    desktop-file-utils
+  ];
+
+  buildInputs = [
+    gtk3
+    librsvg
+    gsound
+    libgnome-games-support
+    libgee
+    adwaita-icon-theme
+  ];
+
+  postPatch = ''
+    chmod +x build-aux/meson_post_install.py
+    patchShebangs build-aux/meson_post_install.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "gnome-robots";
+      attrPath = "gnome.gnome-robots";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Robots";
+    description = "Avoid the robots and make them crash into each other";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl3Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/games/gnome-sudoku/default.nix b/pkgs/desktops/gnome/games/gnome-sudoku/default.nix
new file mode 100644
index 00000000000..3bd0ec3b3cd
--- /dev/null
+++ b/pkgs/desktops/gnome/games/gnome-sudoku/default.nix
@@ -0,0 +1,35 @@
+{ lib, stdenv, fetchurl, meson, ninja, vala, pkg-config, gobject-introspection, gettext, gtk3, gnome, wrapGAppsHook
+, libgee, json-glib, qqwing, itstool, libxml2, python3, desktop-file-utils }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-sudoku";
+  version = "40.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-sudoku/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "1nr1g4q1gxqbzmaz15y3zgssnj7w01cq9l422ja4rglyg0fwjhbm";
+  };
+
+  nativeBuildInputs = [ meson ninja vala pkg-config gobject-introspection gettext itstool libxml2 python3 desktop-file-utils wrapGAppsHook ];
+  buildInputs = [ gtk3 libgee json-glib qqwing ];
+
+  postPatch = ''
+    chmod +x build-aux/post_install.py
+    patchShebangs build-aux/post_install.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "gnome-sudoku";
+      attrPath = "gnome.gnome-sudoku";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Sudoku";
+    description = "Test your logic skills in this number grid puzzle";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/games/gnome-taquin/default.nix b/pkgs/desktops/gnome/games/gnome-taquin/default.nix
new file mode 100644
index 00000000000..c3e78ff2014
--- /dev/null
+++ b/pkgs/desktops/gnome/games/gnome-taquin/default.nix
@@ -0,0 +1,75 @@
+{ lib
+, stdenv
+, fetchurl
+, fetchpatch
+, pkg-config
+, gnome
+, gtk3
+, wrapGAppsHook
+, librsvg
+, gsound
+, gettext
+, itstool
+, libxml2
+, meson
+, ninja
+, vala
+, python3
+, desktop-file-utils
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-taquin";
+  version = "3.38.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-taquin/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "0kw131q0ad0rbsp6qifjc8fjlhvjxyihil8a76kj8ya9mn7kvnwn";
+  };
+
+  patches = [
+    # Fix build with recent Vala.
+    (fetchpatch {
+      url = "https://gitlab.gnome.org/GNOME/gnome-taquin/-/commit/99dea5e7863e112f33f16e59898c56a4f1a547b3.patch";
+      sha256 = "U7djuMhb1XJaKAPyogQjaunOkbBK24r25YD7BgH05P4=";
+    })
+    (fetchpatch {
+      url = "https://gitlab.gnome.org/GNOME/gnome-taquin/-/commit/66be44dc20d114e449fc33156e3939fd05dfbb16.patch";
+      sha256 = "RN41RCLHlJyXTARSH9qjsmpYi1UFeMRssoYxRsbngDQ=";
+    })
+  ];
+
+  nativeBuildInputs = [
+    pkg-config
+    wrapGAppsHook
+    meson
+    ninja
+    python3
+    gettext
+    itstool
+    libxml2
+    vala
+    desktop-file-utils
+  ];
+  buildInputs = [
+    gtk3
+    librsvg
+    gsound
+    gnome.adwaita-icon-theme
+  ];
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "gnome-taquin";
+      attrPath = "gnome.gnome-taquin";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Taquin";
+    description = "Move tiles so that they reach their places";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl3Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/games/gnome-tetravex/default.nix b/pkgs/desktops/gnome/games/gnome-tetravex/default.nix
new file mode 100644
index 00000000000..a1cdf98d9a1
--- /dev/null
+++ b/pkgs/desktops/gnome/games/gnome-tetravex/default.nix
@@ -0,0 +1,39 @@
+{ lib, stdenv, fetchurl, pkg-config, gnome, gtk3, wrapGAppsHook
+, libxml2, gettext, itstool, meson, ninja, python3
+, vala, desktop-file-utils
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-tetravex";
+  version = "3.38.2";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-tetravex/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "06wihvqp2p52zd2dnknsc3rii69qib4a30yp15h558xrg44z3k8z";
+  };
+
+  passthru = {
+    updateScript = gnome.updateScript { packageName = "gnome-tetravex"; attrPath = "gnome.gnome-tetravex"; };
+  };
+
+  nativeBuildInputs = [
+    wrapGAppsHook itstool libxml2 gnome.adwaita-icon-theme
+    pkg-config gettext meson ninja python3 vala desktop-file-utils
+  ];
+  buildInputs = [
+    gtk3
+  ];
+
+  postPatch = ''
+    chmod +x build-aux/meson_post_install.py
+    patchShebangs build-aux/meson_post_install.py
+  '';
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Tetravex";
+    description = "Complete the puzzle by matching numbered tiles";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/games/hitori/default.nix b/pkgs/desktops/gnome/games/hitori/default.nix
new file mode 100644
index 00000000000..1dc07bae26b
--- /dev/null
+++ b/pkgs/desktops/gnome/games/hitori/default.nix
@@ -0,0 +1,66 @@
+{ lib, stdenv
+, fetchurl
+, meson
+, ninja
+, pkg-config
+, gnome
+, glib
+, gtk3
+, cairo
+, wrapGAppsHook
+, libxml2
+, python3
+, gettext
+, itstool
+, desktop-file-utils
+, adwaita-icon-theme
+}:
+
+stdenv.mkDerivation rec {
+  pname = "hitori";
+  version = "3.38.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/hitori/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "Ar0sQh1OIYAmVxToVL0S79PG0Vbd8h95599gAR1OQYQ=";
+  };
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    pkg-config
+    gettext
+    itstool
+    desktop-file-utils
+    libxml2
+    python3
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    glib
+    gtk3
+    cairo
+    adwaita-icon-theme
+  ];
+
+  postPatch = ''
+    chmod +x build-aux/meson_post_install.py
+    patchShebangs build-aux/meson_post_install.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Hitori";
+    description = "GTK application to generate and let you play games of Hitori";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/games/iagno/default.nix b/pkgs/desktops/gnome/games/iagno/default.nix
new file mode 100644
index 00000000000..d7e3930eae1
--- /dev/null
+++ b/pkgs/desktops/gnome/games/iagno/default.nix
@@ -0,0 +1,77 @@
+{ lib, stdenv
+, fetchurl
+, fetchpatch
+, pkg-config
+, gtk3
+, gnome
+, gdk-pixbuf
+, librsvg
+, wrapGAppsHook
+, itstool
+, gsound
+, libxml2
+, meson
+, ninja
+, python3
+, vala
+, desktop-file-utils
+}:
+
+stdenv.mkDerivation rec {
+  pname = "iagno";
+  version = "3.38.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/iagno/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "097dw1l92l73xah9l56ka5mi3dvx48ffpiv33ni5i5rqw0ng7fc4";
+  };
+
+  patches = [
+    # Fix build with recent Vala.
+    # https://gitlab.gnome.org/GNOME/dconf-editor/-/merge_requests/15
+    (fetchpatch {
+      url = "https://gitlab.gnome.org/GNOME/iagno/-/commit/e8a0aeec350ea80349582142c0e8e3cd3f1bce38.patch";
+      sha256 = "OO1x0Yx56UFzHTBsPAMYAjnJHlnTjdO1Vk7q6XU8wKQ=";
+    })
+    # https://gitlab.gnome.org/GNOME/dconf-editor/-/merge_requests/13
+    (fetchpatch {
+      url = "https://gitlab.gnome.org/GNOME/iagno/-/commit/508c0f94e5f182e50ff61be6e04f72574dee97cb.patch";
+      sha256 = "U7djuMhb1XJaKAPyogQjaunOkbBK24r25YD7BgH05P4=";
+    })
+  ];
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    python3
+    vala
+    desktop-file-utils
+    pkg-config
+    wrapGAppsHook
+    itstool
+    libxml2
+  ];
+
+  buildInputs = [
+    gtk3
+    gnome.adwaita-icon-theme
+    gdk-pixbuf
+    librsvg
+    gsound
+  ];
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "iagno";
+      attrPath = "gnome.iagno";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Iagno";
+    description = "Computer version of the game Reversi, more popularly called Othello";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl3Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/games/lightsoff/default.nix b/pkgs/desktops/gnome/games/lightsoff/default.nix
new file mode 100644
index 00000000000..94b71f0e856
--- /dev/null
+++ b/pkgs/desktops/gnome/games/lightsoff/default.nix
@@ -0,0 +1,39 @@
+{ lib, stdenv, fetchurl, vala, pkg-config, gtk3, gnome, gdk-pixbuf, librsvg, wrapGAppsHook
+, gettext, itstool, clutter, clutter-gtk, libxml2, appstream-glib
+, meson, ninja, python3 }:
+
+stdenv.mkDerivation rec {
+  pname = "lightsoff";
+  version = "40.0.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/lightsoff/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "1aziy64g15bm83zfn3ifs20z9yvscdvsxbx132xnq77i0r3qvlxc";
+  };
+
+  nativeBuildInputs = [
+    vala pkg-config wrapGAppsHook itstool gettext appstream-glib libxml2
+    meson ninja python3
+  ];
+  buildInputs = [ gtk3 gnome.adwaita-icon-theme gdk-pixbuf librsvg clutter clutter-gtk ];
+
+  postPatch = ''
+    chmod +x build-aux/meson_post_install.py
+    patchShebangs build-aux/meson_post_install.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "lightsoff";
+      attrPath = "gnome.lightsoff";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Lightsoff";
+    description = "Puzzle game, where the objective is to turn off all of the tiles on the board";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/games/quadrapassel/default.nix b/pkgs/desktops/gnome/games/quadrapassel/default.nix
new file mode 100644
index 00000000000..d54c49eafee
--- /dev/null
+++ b/pkgs/desktops/gnome/games/quadrapassel/default.nix
@@ -0,0 +1,40 @@
+{ lib, stdenv, fetchurl, pkg-config, gtk3, gnome, gdk-pixbuf
+, librsvg, gsound, libmanette
+, gettext, itstool, libxml2, clutter, clutter-gtk, wrapGAppsHook
+, meson, ninja, python3, vala, desktop-file-utils
+}:
+
+stdenv.mkDerivation rec {
+  pname = "quadrapassel";
+  version = "3.38.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "033plabc6q3sk6qjr5nml8z6p07vcw57gxddxjk9b65wgg0rzzhr";
+  };
+
+  nativeBuildInputs = [
+    meson ninja python3 vala desktop-file-utils
+    pkg-config gnome.adwaita-icon-theme
+    libxml2 itstool gettext wrapGAppsHook
+  ];
+  buildInputs = [
+    gtk3 gdk-pixbuf librsvg libmanette
+    gsound clutter libxml2 clutter-gtk
+  ];
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    description = "Classic falling-block game, Tetris";
+    homepage = "https://wiki.gnome.org/Apps/Quadrapassel";
+    license = licenses.gpl2;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/games/swell-foop/default.nix b/pkgs/desktops/gnome/games/swell-foop/default.nix
new file mode 100644
index 00000000000..50fab598153
--- /dev/null
+++ b/pkgs/desktops/gnome/games/swell-foop/default.nix
@@ -0,0 +1,72 @@
+{ lib
+, stdenv
+, fetchurl
+, meson
+, ninja
+, pkg-config
+, vala
+, glib
+, gtk3
+, libgnome-games-support
+, gnome
+, desktop-file-utils
+, clutter
+, clutter-gtk
+, gettext
+, itstool
+, libxml2
+, wrapGAppsHook
+, python3
+}:
+
+stdenv.mkDerivation rec {
+  pname = "swell-foop";
+  version = "40.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "17r4b0g8s7z872wdd7ngk248z7fqx43vm2sym1bdqhzsi250s1y1";
+  };
+
+  nativeBuildInputs = [
+    meson
+    ninja
+    vala
+    pkg-config
+    wrapGAppsHook
+    python3
+    itstool
+    gettext
+    libxml2
+    desktop-file-utils
+  ];
+
+  buildInputs = [
+    glib
+    gtk3
+    libgnome-games-support
+    gnome.adwaita-icon-theme
+    clutter
+    clutter-gtk
+  ];
+
+  postPatch = ''
+    chmod +x meson_post_install.py # patchShebangs requires executable file
+    patchShebangs meson_post_install.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Swell%20Foop";
+    description = "Puzzle game, previously known as Same GNOME";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/games/tali/default.nix b/pkgs/desktops/gnome/games/tali/default.nix
new file mode 100644
index 00000000000..3e2abc87304
--- /dev/null
+++ b/pkgs/desktops/gnome/games/tali/default.nix
@@ -0,0 +1,38 @@
+{ lib, stdenv, fetchurl, pkg-config, gtk3, gnome, gdk-pixbuf
+, librsvg, libgnome-games-support, gettext, itstool, libxml2, wrapGAppsHook
+, meson, ninja, python3, desktop-file-utils
+}:
+
+stdenv.mkDerivation rec {
+  pname = "tali";
+  version = "40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/tali/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "19gic6yjg3bg6jf87zvhm7ihsz1y58dz86p4x3a16xdhjyrk40q2";
+  };
+
+  passthru = {
+    updateScript = gnome.updateScript { packageName = "tali"; attrPath = "gnome.tali"; };
+  };
+
+  nativeBuildInputs = [
+    meson ninja python3 desktop-file-utils
+    pkg-config gnome.adwaita-icon-theme
+    libxml2 itstool gettext wrapGAppsHook
+  ];
+  buildInputs = [ gtk3 gdk-pixbuf librsvg libgnome-games-support ];
+
+  postPatch = ''
+    chmod +x build-aux/meson_post_install.py
+    patchShebangs build-aux/meson_post_install.py
+  '';
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Tali";
+    description = "Sort of poker with dice and less money";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/installer.nix b/pkgs/desktops/gnome/installer.nix
new file mode 100644
index 00000000000..4999e1f3343
--- /dev/null
+++ b/pkgs/desktops/gnome/installer.nix
@@ -0,0 +1,15 @@
+{ isoBaseName ? "nixos-graphical-gnome", system ? builtins.currentSystem
+, extraModules ? [] }:
+
+let
+
+  module = ../../../../nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix;
+
+  config = (import ../../../../nixos/lib/eval-config.nix {
+    inherit system;
+    modules = [ module { isoImage.isoBaseName = isoBaseName; } ] ++ extraModules;
+  }).config;
+
+in
+  config.system.build.isoImage
+
diff --git a/pkgs/desktops/gnome/misc/geary/default.nix b/pkgs/desktops/gnome/misc/geary/default.nix
new file mode 100644
index 00000000000..a40cd30eb8d
--- /dev/null
+++ b/pkgs/desktops/gnome/misc/geary/default.nix
@@ -0,0 +1,160 @@
+{ lib
+, stdenv
+, fetchurl
+, pkg-config
+, gtk3
+, vala
+, enchant2
+, wrapGAppsHook
+, meson
+, ninja
+, desktop-file-utils
+, gnome-online-accounts
+, gsettings-desktop-schemas
+, adwaita-icon-theme
+, libpeas
+, libsecret
+, gmime3
+, isocodes
+, icu
+, libxml2
+, gettext
+, sqlite
+, gcr
+, json-glib
+, itstool
+, libgee
+, gnome
+, webkitgtk
+, python3
+, gnutls
+, cacert
+, xvfb_run
+, glibcLocales
+, dbus
+, shared-mime-info
+, libunwind
+, folks
+, glib-networking
+, gobject-introspection
+, gspell
+, appstream-glib
+, libstemmer
+, libytnef
+, libhandy
+, gsound
+}:
+
+stdenv.mkDerivation rec {
+  pname = "geary";
+  version = "40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "1c2nd35500ng28223y5pszc7fh8g16njj34f6p5xc9594lvj0mik";
+  };
+
+  nativeBuildInputs = [
+    appstream-glib
+    desktop-file-utils
+    gettext
+    gobject-introspection
+    itstool
+    libxml2
+    meson
+    ninja
+    pkg-config
+    python3
+    vala
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    adwaita-icon-theme
+    enchant2
+    folks
+    gcr
+    glib-networking
+    gmime3
+    gnome-online-accounts
+    gsettings-desktop-schemas
+    gsound
+    gspell
+    gtk3
+    isocodes
+    icu
+    json-glib
+    libgee
+    libhandy
+    libpeas
+    libsecret
+    libunwind
+    libstemmer
+    libytnef
+    sqlite
+    webkitgtk
+  ];
+
+  checkInputs = [
+    dbus
+    gnutls # for certtool
+    cacert # trust store for glib-networking
+    xvfb_run
+    glibcLocales # required by Geary.ImapDb.DatabaseTest/utf8_case_insensitive_collation
+  ];
+
+  mesonFlags = [
+    "-Dprofile=release"
+    "-Dcontractor=enabled" # install the contractor file (Pantheon specific)
+  ];
+
+  # NOTE: Remove `build-auxyaml_to_json.py` when no longer needed, see:
+  # https://gitlab.gnome.org/GNOME/geary/commit/f7f72143e0f00ca5e0e6a798691805c53976ae31#0cc1139e3347f573ae1feee5b73dbc8a8a21fcfa
+  postPatch = ''
+    chmod +x build-aux/post_install.py build-aux/git_version.py
+
+    patchShebangs build-aux/post_install.py build-aux/git_version.py
+
+    chmod +x build-aux/yaml_to_json.py
+    patchShebangs build-aux/yaml_to_json.py
+
+    chmod +x desktop/geary-attach
+  '';
+
+  # Some tests time out.
+  doCheck = false;
+
+  checkPhase = ''
+    runHook preCheck
+
+    NO_AT_BRIDGE=1 \
+    GIO_EXTRA_MODULES=$GIO_EXTRA_MODULES:${glib-networking}/lib/gio/modules \
+    HOME=$TMPDIR \
+    XDG_DATA_DIRS=$XDG_DATA_DIRS:${gsettings-desktop-schemas}/share/gsettings-schemas/${gsettings-desktop-schemas.name}:${shared-mime-info}/share:${folks}/share/gsettings-schemas/${folks.name} \
+    xvfb-run -s '-screen 0 800x600x24' dbus-run-session \
+      --config-file=${dbus.daemon}/share/dbus-1/session.conf \
+      meson test -v --no-stdsplit
+
+    runHook postCheck
+  '';
+
+  preFixup = ''
+    # Add geary to path for geary-attach
+    gappsWrapperArgs+=(--prefix PATH : "$out/bin")
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Geary";
+    description = "Mail client for GNOME 3";
+    maintainers = teams.gnome.members;
+    license = licenses.lgpl21Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/misc/gitg/default.nix b/pkgs/desktops/gnome/misc/gitg/default.nix
new file mode 100644
index 00000000000..8f73bdaeb7d
--- /dev/null
+++ b/pkgs/desktops/gnome/misc/gitg/default.nix
@@ -0,0 +1,95 @@
+{ lib
+, stdenv
+, fetchurl
+, vala
+, gettext
+, pkg-config
+, gtk3
+, glib
+, json-glib
+, wrapGAppsHook
+, libpeas
+, bash
+, gobject-introspection
+, libsoup
+, gtksourceview
+, gsettings-desktop-schemas
+, adwaita-icon-theme
+, gnome
+, gtkspell3
+, shared-mime-info
+, libgee
+, libgit2-glib
+, libsecret
+, meson
+, ninja
+, python3
+, libdazzle
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gitg";
+  version = "3.32.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "0npg4kqpwl992fgjd2cn3fh84aiwpdp9kd8z7rw2xaj2iazsm914";
+  };
+
+  nativeBuildInputs = [
+    gobject-introspection
+    gettext
+    meson
+    ninja
+    pkg-config
+    python3
+    vala
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    adwaita-icon-theme
+    glib
+    gsettings-desktop-schemas
+    gtk3
+    gtksourceview
+    gtkspell3
+    json-glib
+    libdazzle
+    libgee
+    libgit2-glib
+    libpeas
+    libsecret
+    libsoup
+  ];
+
+  doCheck = false; # FAIL: tests-gitg gtk_style_context_add_provider_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed
+
+  postPatch = ''
+    chmod +x meson_post_install.py
+    patchShebangs meson_post_install.py
+
+    substituteInPlace tests/libgitg/test-commit.vala --replace "/bin/bash" "${bash}/bin/bash"
+  '';
+
+  preFixup = ''
+    gappsWrapperArgs+=(
+      # Thumbnailers
+      --prefix XDG_DATA_DIRS : "${shared-mime-info}/share"
+    )
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Gitg";
+    description = "GNOME GUI client to view git repositories";
+    maintainers = with maintainers; [ domenkozar ];
+    license = licenses.gpl2Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/misc/gnome-applets/default.nix b/pkgs/desktops/gnome/misc/gnome-applets/default.nix
new file mode 100644
index 00000000000..d414266a9d9
--- /dev/null
+++ b/pkgs/desktops/gnome/misc/gnome-applets/default.nix
@@ -0,0 +1,80 @@
+{ lib, stdenv
+, fetchurl
+, gettext
+, itstool
+, libxml2
+, pkg-config
+, gnome-panel
+, gtk3
+, glib
+, libwnck3
+, libgtop
+, libnotify
+, upower
+, wirelesstools
+, linuxPackages
+, adwaita-icon-theme
+, libgweather
+, gucharmap
+, tracker
+, polkit
+, gnome
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-applets";
+  version = "3.40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "1k6mdkg16ia29fyg8ikf4dfs51gnrmg0f8xwpvd3192lhfsbsh19";
+  };
+
+  nativeBuildInputs = [
+    gettext
+    itstool
+    pkg-config
+    libxml2
+  ];
+
+  buildInputs = [
+    gnome-panel
+    gtk3
+    glib
+    libxml2
+    libwnck3
+    libgtop
+    libnotify
+    upower
+    adwaita-icon-theme
+    libgweather
+    gucharmap
+    tracker
+    polkit
+    wirelesstools
+    linuxPackages.cpupower
+  ];
+
+  enableParallelBuilding = true;
+
+  doCheck = true;
+
+  # Don't try to install modules to gnome panel's directory, as it's read only
+  PKG_CONFIG_LIBGNOME_PANEL_MODULESDIR = "${placeholder "out"}/lib/gnome-panel/modules";
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+      versionPolicy = "odd-unstable";
+    };
+  };
+
+  meta = with lib; {
+    description = "Applets for use with the GNOME panel";
+    homepage = "https://wiki.gnome.org/Projects/GnomeApplets";
+    license = licenses.gpl2Plus;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/misc/gnome-autoar/default.nix b/pkgs/desktops/gnome/misc/gnome-autoar/default.nix
new file mode 100644
index 00000000000..8a74c05dfea
--- /dev/null
+++ b/pkgs/desktops/gnome/misc/gnome-autoar/default.nix
@@ -0,0 +1,48 @@
+{ lib, stdenv
+, fetchurl
+, pkg-config
+, gnome
+, gtk3
+, glib
+, gobject-introspection
+, libarchive
+, vala
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-autoar";
+  version = "0.3.2";
+
+  outputs = [ "out" "dev" ];
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-autoar/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "0wkwix44yg126xn1v4f2j60bv9yiyadfpzf8ifx0bvd9x5f4v354";
+  };
+
+  passthru = {
+    updateScript = gnome.updateScript { packageName = "gnome-autoar"; attrPath = "gnome.gnome-autoar"; };
+  };
+
+  nativeBuildInputs = [
+    gobject-introspection
+    pkg-config
+    vala
+  ];
+
+  buildInputs = [
+    gtk3
+  ];
+
+  propagatedBuildInputs = [
+    libarchive
+    glib
+  ];
+
+  meta = with lib; {
+    platforms = platforms.linux;
+    maintainers = teams.gnome.members;
+    license = licenses.lgpl21Plus;
+    description = "Library to integrate compressed files management with GNOME";
+  };
+}
diff --git a/pkgs/desktops/gnome/misc/gnome-flashback/default.nix b/pkgs/desktops/gnome/misc/gnome-flashback/default.nix
new file mode 100644
index 00000000000..7e578f27cd2
--- /dev/null
+++ b/pkgs/desktops/gnome/misc/gnome-flashback/default.nix
@@ -0,0 +1,203 @@
+{ lib, stdenv
+, autoreconfHook
+, fetchurl
+, gettext
+, glib
+, gnome-bluetooth
+, gnome-desktop
+, gnome-panel
+, gnome-session
+, gnome
+, gsettings-desktop-schemas
+, gtk3
+, ibus
+, libcanberra-gtk3
+, libpulseaudio
+, libxkbfile
+, libxml2
+, pkg-config
+, polkit
+, gdm
+, systemd
+, upower
+, pam
+, wrapGAppsHook
+, writeTextFile
+, writeShellScriptBin
+, xkeyboard_config
+, xorg
+, runCommand
+}:
+let
+  pname = "gnome-flashback";
+  version = "3.40.0";
+
+  # From data/sessions/Makefile.am
+  requiredComponentsCommon = [
+    "gnome-flashback"
+    "gnome-panel"
+  ];
+  requiredComponentsGsd = [
+    "org.gnome.SettingsDaemon.A11ySettings"
+    "org.gnome.SettingsDaemon.Color"
+    "org.gnome.SettingsDaemon.Datetime"
+    "org.gnome.SettingsDaemon.Housekeeping"
+    "org.gnome.SettingsDaemon.Keyboard"
+    "org.gnome.SettingsDaemon.MediaKeys"
+    "org.gnome.SettingsDaemon.Power"
+    "org.gnome.SettingsDaemon.PrintNotifications"
+    "org.gnome.SettingsDaemon.Rfkill"
+    "org.gnome.SettingsDaemon.ScreensaverProxy"
+    "org.gnome.SettingsDaemon.Sharing"
+    "org.gnome.SettingsDaemon.Smartcard"
+    "org.gnome.SettingsDaemon.Sound"
+    "org.gnome.SettingsDaemon.UsbProtection"
+    "org.gnome.SettingsDaemon.Wacom"
+    "org.gnome.SettingsDaemon.XSettings"
+  ];
+  requiredComponents = wmName: "RequiredComponents=${lib.concatStringsSep ";" ([ wmName ] ++ requiredComponentsCommon ++ requiredComponentsGsd)};";
+  gnome-flashback = stdenv.mkDerivation rec {
+    name = "${pname}-${version}";
+
+    src = fetchurl {
+      url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${name}.tar.xz";
+      sha256 = "0fxv13m2q9z1q3i9jbggl35cb7jlckbdrfsr5sf030hr1w836gz0";
+    };
+
+    # make .desktop Execs absolute
+    postPatch = ''
+      patch -p0 <<END_PATCH
+      +++ data/applications/gnome-flashback.desktop.in.in
+      @@ -4 +4 @@
+      -Exec=gnome-flashback
+      +Exec=$out/bin/gnome-flashback
+      END_PATCH
+    '';
+
+    postInstall = ''
+      # Check that our expected RequiredComponents match the stock session files, but then don't install them.
+      # They can be installed using mkSessionForWm.
+      grep '${requiredComponents "metacity"}' $out/share/gnome-session/sessions/gnome-flashback-metacity.session || (echo "RequiredComponents have changed, please update gnome-flashback/default.nix."; false)
+
+      rm -r $out/share/gnome-session
+      rm -r $out/share/xsessions
+      rm -r $out/libexec
+    '';
+
+    nativeBuildInputs = [
+      autoreconfHook
+      gettext
+      libxml2
+      pkg-config
+      wrapGAppsHook
+    ];
+
+    buildInputs = [
+      glib
+      gnome-bluetooth
+      gnome-desktop
+      gsettings-desktop-schemas
+      gtk3
+      ibus
+      libcanberra-gtk3
+      libpulseaudio
+      libxkbfile
+      xorg.libXxf86vm
+      polkit
+      gdm
+      gnome-panel
+      systemd
+      upower
+      pam
+      xkeyboard_config
+    ];
+
+    doCheck = true;
+
+    enableParallelBuilding = true;
+
+    PKG_CONFIG_LIBGNOME_PANEL_LAYOUTSDIR = "${placeholder "out"}/share/gnome-panel/layouts";
+    PKG_CONFIG_LIBGNOME_PANEL_MODULESDIR = "${placeholder "out"}/lib/gnome-panel/modules";
+
+    passthru = {
+      updateScript = gnome.updateScript {
+        packageName = pname;
+        attrPath = "gnome.${pname}";
+        versionPolicy = "odd-unstable";
+      };
+
+      mkSessionForWm = { wmName, wmLabel, wmCommand }:
+        let
+          wmApplication = writeTextFile {
+            name = "gnome-flashback-${wmName}-wm";
+            destination = "/share/applications/${wmName}.desktop";
+            text = ''
+              [Desktop Entry]
+              Type=Application
+              Encoding=UTF-8
+              Name=${wmLabel}
+              Exec=${wmCommand}
+              NoDisplay=true
+              X-GNOME-WMName=${wmLabel}
+              X-GNOME-Autostart-Phase=WindowManager
+              X-GNOME-Provides=windowmanager
+              X-GNOME-Autostart-Notify=false
+            '';
+          };
+
+          gnomeSession = writeTextFile {
+            name = "gnome-flashback-${wmName}-gnome-session";
+            destination = "/share/gnome-session/sessions/gnome-flashback-${wmName}.session";
+            text = ''
+              [GNOME Session]
+              Name=GNOME Flashback (${wmLabel})
+              ${requiredComponents wmName}
+            '';
+          };
+
+          executable = writeShellScriptBin "gnome-flashback-${wmName}" ''
+            if [ -z $XDG_CURRENT_DESKTOP ]; then
+              export XDG_CURRENT_DESKTOP="GNOME-Flashback:GNOME"
+            fi
+
+            export XDG_DATA_DIRS=${wmApplication}/share:${gnomeSession}/share:${gnome-flashback}/share:${gnome-panel}/share:$XDG_DATA_DIRS
+
+            exec ${gnome-session}/bin/gnome-session --session=gnome-flashback-${wmName} "$@"
+          '';
+
+        in
+        writeTextFile
+          {
+            name = "gnome-flashback-${wmName}-xsession";
+            destination = "/share/xsessions/gnome-flashback-${wmName}.desktop";
+            text = ''
+              [Desktop Entry]
+              Name=GNOME Flashback (${wmLabel})
+              Comment=This session logs you into GNOME Flashback with ${wmLabel}
+              Exec=${executable}/bin/gnome-flashback-${wmName}
+              TryExec=${wmCommand}
+              Type=Application
+              DesktopNames=GNOME-Flashback;GNOME;
+            '';
+          } // {
+          providedSessions = [ "gnome-flashback-${wmName}" ];
+        };
+
+      mkSystemdTargetForWm = { wmName }:
+        runCommand "gnome-flashback-${wmName}.target" { } ''
+          mkdir -p $out/lib/systemd/user
+          cp "${gnome-flashback}/lib/systemd/user/gnome-session-x11@gnome-flashback-metacity.target" \
+            "$out/lib/systemd/user/gnome-session-x11@gnome-flashback-${wmName}.target"
+        '';
+    };
+
+    meta = with lib; {
+      description = "GNOME 2.x-like session for GNOME 3";
+      homepage = "https://wiki.gnome.org/Projects/GnomeFlashback";
+      license = licenses.gpl2;
+      maintainers = teams.gnome.members;
+      platforms = platforms.linux;
+    };
+  };
+in
+gnome-flashback
diff --git a/pkgs/desktops/gnome/misc/gnome-packagekit/default.nix b/pkgs/desktops/gnome/misc/gnome-packagekit/default.nix
new file mode 100644
index 00000000000..6e0aa78e6fd
--- /dev/null
+++ b/pkgs/desktops/gnome/misc/gnome-packagekit/default.nix
@@ -0,0 +1,37 @@
+{ lib, stdenv, fetchurl, pkg-config, meson, ninja, gettext, gnome, packagekit, polkit
+, gtk3, systemd, wrapGAppsHook, desktop-file-utils }:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-packagekit";
+  version = "3.32.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gnome-packagekit/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "08rhsisdvx7pnx3rrg5v7c09jbw4grglkdj979gwl4a31j24zjsd";
+  };
+
+  nativeBuildInputs = [
+    pkg-config meson ninja gettext wrapGAppsHook desktop-file-utils
+  ];
+
+  buildInputs = [ gtk3 packagekit systemd polkit ];
+
+  postPatch = ''
+    patchShebangs meson_post_install.sh
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = "gnome-packagekit";
+      attrPath = "gnome.gnome-packagekit";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://www.freedesktop.org/software/PackageKit/";
+    platforms = platforms.linux;
+    maintainers = teams.gnome.members;
+    license = licenses.gpl2;
+    description = "Tools for installing software on the GNOME desktop using PackageKit";
+  };
+}
diff --git a/pkgs/desktops/gnome/misc/gnome-panel/default.nix b/pkgs/desktops/gnome/misc/gnome-panel/default.nix
new file mode 100644
index 00000000000..4e42f91e1e3
--- /dev/null
+++ b/pkgs/desktops/gnome/misc/gnome-panel/default.nix
@@ -0,0 +1,99 @@
+{ lib, stdenv
+, fetchurl
+, autoreconfHook
+, dconf
+, evolution-data-server
+, gdm
+, gettext
+, glib
+, gnome-desktop
+, gnome-menus
+, gnome
+, gtk3
+, itstool
+, libgweather
+, libsoup
+, libwnck3
+, libxml2
+, pkg-config
+, polkit
+, systemd
+, wrapGAppsHook
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-panel";
+  version = "3.40.0";
+
+  outputs = [ "out" "dev" "man" ];
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    hash = "sha256-nxNQde3GZs8rnKkd41xnA+KxdxwQp3B0FPtlbCilmzs=";
+  };
+
+  # make .desktop Exec absolute
+  postPatch = ''
+    patch -p0 <<END_PATCH
+    +++ gnome-panel/gnome-panel.desktop.in
+    @@ -7 +7 @@
+    -Exec=gnome-panel
+    +Exec=$out/bin/gnome-panel
+    END_PATCH
+  '';
+
+  preFixup = ''
+    gappsWrapperArgs+=(
+      --prefix XDG_DATA_DIRS : "${gnome-menus}/share"
+      --prefix XDG_CONFIG_DIRS : "${gnome-menus}/etc/xdg"
+    )
+  '';
+
+  nativeBuildInputs = [
+    autoreconfHook
+    gettext
+    itstool
+    libxml2
+    pkg-config
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    dconf
+    evolution-data-server
+    gdm
+    glib
+    gnome-desktop
+    gnome-menus
+    gtk3
+    libgweather
+    libsoup
+    libwnck3
+    polkit
+    systemd
+  ];
+
+  configureFlags = [
+    "--enable-eds"
+  ];
+
+  enableParallelBuilding = true;
+
+  doCheck = true;
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+      versionPolicy = "odd-unstable";
+    };
+  };
+
+  meta = with lib; {
+    description = "Component of Gnome Flashback that provides panels and default applets for the desktop";
+    homepage = "https://wiki.gnome.org/Projects/GnomePanel";
+    license = licenses.gpl2Plus;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/misc/gnome-screensaver/fix-dbus-service-dir.patch b/pkgs/desktops/gnome/misc/gnome-screensaver/fix-dbus-service-dir.patch
new file mode 100644
index 00000000000..81e037ee690
--- /dev/null
+++ b/pkgs/desktops/gnome/misc/gnome-screensaver/fix-dbus-service-dir.patch
@@ -0,0 +1,11 @@
+--- a/configure.ac  2019-01-20 20:28:01.309231507 +0100
++++ b/configure.ac  2019-01-20 20:31:54.927978927 +0100
+@@ -137,7 +137,7 @@
+ 
+ # Find out where the session service file goes
+ # The sad sed hack is recomended by section 27.10 of the automake manual.
+-DBUS_SESSION_SERVICE_DIR=`pkg-config --variable session_bus_services_dir dbus-1 | sed -e 's,/usr/share,${datarootdir},g'`
++DBUS_SESSION_SERVICE_DIR=`pkg-config --variable session_bus_services_dir dbus-1 --define-variable 'datadir=${datadir}'`
+ AC_SUBST(DBUS_SESSION_SERVICE_DIR)
+ 
+ dnl ---------------------------------------------------------------------------
\ No newline at end of file
diff --git a/pkgs/desktops/gnome/misc/gnome-tweaks/default.nix b/pkgs/desktops/gnome/misc/gnome-tweaks/default.nix
new file mode 100644
index 00000000000..460ab47733c
--- /dev/null
+++ b/pkgs/desktops/gnome/misc/gnome-tweaks/default.nix
@@ -0,0 +1,81 @@
+{ lib
+, meson
+, ninja
+, fetchurl
+, gdk-pixbuf
+, gettext
+, glib
+, gnome
+, gobject-introspection
+, gsettings-desktop-schemas
+, gtk3
+, itstool
+, libhandy
+, libnotify
+, libsoup
+, libxml2
+, pkg-config
+, python3Packages
+, wrapGAppsHook }:
+
+python3Packages.buildPythonApplication rec {
+  pname = "gnome-tweaks";
+  version = "40.0";
+  format = "other";
+  strictDeps = false; # https://github.com/NixOS/nixpkgs/issues/56943
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.major version}/${pname}-${version}.tar.xz";
+    sha256 = "+V8/4DGwsBwC95oWWfiJFS03cq4+RN+EA9FGC6Xuw2o=";
+  };
+
+  nativeBuildInputs = [
+    gettext
+    gobject-introspection
+    itstool
+    libxml2
+    meson
+    ninja
+    pkg-config
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    gdk-pixbuf
+    glib
+    gnome.gnome-desktop
+    gnome.gnome-settings-daemon
+    gnome.gnome-shell
+    # Makes it possible to select user themes through the `user-theme` extension
+    gnome.gnome-shell-extensions
+    gnome.mutter
+    gsettings-desktop-schemas
+    gtk3
+    libhandy
+    libnotify
+    libsoup
+  ];
+
+  propagatedBuildInputs = with python3Packages; [
+    pygobject3
+  ];
+
+  postPatch = ''
+    patchShebangs meson-postinstall.py
+  '';
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+    };
+  };
+
+  meta = with lib; {
+    homepage = "https://wiki.gnome.org/Apps/Tweaks";
+    description = "A tool to customize advanced GNOME 3 options";
+    maintainers = teams.gnome.members;
+    license = licenses.gpl3Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/misc/gpaste/default.nix b/pkgs/desktops/gnome/misc/gpaste/default.nix
new file mode 100644
index 00000000000..15fcfbfe390
--- /dev/null
+++ b/pkgs/desktops/gnome/misc/gpaste/default.nix
@@ -0,0 +1,81 @@
+{ lib, stdenv
+, fetchFromGitHub
+, fetchpatch
+, appstream-glib
+, clutter
+, gjs
+, glib
+, gobject-introspection
+, gtk3
+, meson
+, mutter
+, ninja
+, pango
+, pkg-config
+, vala
+, wrapGAppsHook
+}:
+
+stdenv.mkDerivation rec {
+  version = "3.40.2";
+  pname = "gpaste";
+
+  src = fetchFromGitHub {
+    owner = "Keruspe";
+    repo = "GPaste";
+    rev = "v${version}";
+    sha256 = "sha256-DUikcnkDBRkCwPLrl8lkNr+SeNpc3bPwPTWRn91nOo4=";
+  };
+
+  patches = [
+    ./fix-paths.patch
+  ];
+
+  # TODO: switch to substituteAll with placeholder
+  # https://github.com/NixOS/nix/issues/1846
+  postPatch = ''
+    substituteInPlace src/gnome-shell/extension.js \
+      --subst-var-by typelibPath "${placeholder "out"}/lib/girepository-1.0"
+    substituteInPlace src/gnome-shell/prefs.js \
+      --subst-var-by typelibPath "${placeholder "out"}/lib/girepository-1.0"
+    substituteInPlace src/libgpaste/settings/gpaste-settings.c \
+      --subst-var-by gschemasCompiled ${glib.makeSchemaPath (placeholder "out") "${pname}-${version}"}
+  '';
+
+  nativeBuildInputs = [
+    appstream-glib
+    gobject-introspection
+    meson
+    ninja
+    pkg-config
+    vala
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    clutter # required by mutter-clutter
+    gjs
+    glib
+    gtk3
+    mutter
+    pango
+  ];
+
+  mesonFlags = [
+    "-Dcontrol-center-keybindings-dir=${placeholder "out"}/share/gnome-control-center/keybindings"
+    "-Ddbus-services-dir=${placeholder "out"}/share/dbus-1/services"
+    "-Dsystemd-user-unit-dir=${placeholder "out"}/etc/systemd/user"
+  ];
+
+  postInstall = ''
+    ${glib.dev}/bin/glib-compile-schemas "$out/share/glib-2.0/schemas"
+  '';
+
+  meta = with lib; {
+    homepage = "https://github.com/Keruspe/GPaste";
+    description = "Clipboard management system with GNOME 3 integration";
+    license = licenses.gpl3;
+    platforms = platforms.linux;
+    maintainers = teams.gnome.members;
+  };
+}
diff --git a/pkgs/desktops/gnome/misc/gpaste/fix-paths.patch b/pkgs/desktops/gnome/misc/gpaste/fix-paths.patch
new file mode 100644
index 00000000000..46e30ce2e2c
--- /dev/null
+++ b/pkgs/desktops/gnome/misc/gpaste/fix-paths.patch
@@ -0,0 +1,37 @@
+--- a/src/gnome-shell/extension.js
++++ b/src/gnome-shell/extension.js
+@@ -6,6 +6,8 @@
+ 
+ const Config = imports.misc.config;
+ 
++imports.gi.GIRepository.Repository.prepend_search_path('@typelibPath@');
++
+ imports.gi.versions.Clutter = Config.LIBMUTTER_API_VERSION;
+ imports.gi.versions.GLib = '2.0';
+ imports.gi.versions.GPaste = '1.0';
+--- a/src/gnome-shell/prefs.js
++++ b/src/gnome-shell/prefs.js
+@@ -6,6 +6,8 @@
+ 
+ const Gettext = imports.gettext;
+ 
++imports.gi.GIRepository.Repository.prepend_search_path('@typelibPath@');
++
+ //const { GPaste } = imports.gi;
+ 
+ const ExtensionUtils = imports.misc.extensionUtils;
+--- a/src/libgpaste/settings/gpaste-settings.c
++++ b/src/libgpaste/settings/gpaste-settings.c
+@@ -1013,7 +1013,11 @@
+     }
+     else
+     {
+-        return g_settings_new (G_PASTE_SETTINGS_NAME);
++        // library used by introspection requires schemas but we cannot set XDG_DATA_DIRS for the library
++        GSettingsSchemaSource *schema_source = g_settings_schema_source_new_from_directory ("@gschemasCompiled@", NULL, FALSE, NULL);
++        g_autoptr (GSettingsSchema) schema = g_settings_schema_source_lookup (schema_source, G_PASTE_SETTINGS_NAME, FALSE);
++        g_settings_schema_source_unref (schema_source);
++        return g_settings_new_full (schema, NULL, NULL);
+     }
+ }
+ 
diff --git a/pkgs/desktops/gnome/misc/gtkhtml/default.nix b/pkgs/desktops/gnome/misc/gtkhtml/default.nix
new file mode 100644
index 00000000000..88fb31c4333
--- /dev/null
+++ b/pkgs/desktops/gnome/misc/gtkhtml/default.nix
@@ -0,0 +1,27 @@
+{ lib, stdenv, fetchurl, pkg-config, gtk3, intltool
+, gnome, enchant, isocodes, gsettings-desktop-schemas }:
+
+stdenv.mkDerivation rec {
+  pname = "gtkhtml";
+  version = "4.10.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/gtkhtml/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "ca3b6424fb2c7ac5d9cb8fdafb69318fa2e825c9cf6ed17d1e38d9b29e5606c3";
+  };
+
+  passthru = {
+    updateScript = gnome.updateScript { packageName = "gtkhtml"; attrPath = "gnome.gtkhtml"; };
+  };
+
+  nativeBuildInputs = [ pkg-config ];
+  buildInputs = [ gtk3 intltool gnome.adwaita-icon-theme
+                  gsettings-desktop-schemas ];
+
+  propagatedBuildInputs = [ enchant isocodes ];
+
+  meta = with lib; {
+    platforms = platforms.linux;
+    maintainers = teams.gnome.members;
+  };
+}
diff --git a/pkgs/desktops/gnome/misc/libgnome-games-support/default.nix b/pkgs/desktops/gnome/misc/libgnome-games-support/default.nix
new file mode 100644
index 00000000000..dd65f858b6d
--- /dev/null
+++ b/pkgs/desktops/gnome/misc/libgnome-games-support/default.nix
@@ -0,0 +1,58 @@
+{ lib, stdenv
+, fetchurl
+, pkg-config
+, glib
+, gtk3
+, libgee
+, gettext
+, vala
+, gnome
+, libintl
+, meson
+, ninja
+}:
+
+stdenv.mkDerivation rec {
+  pname = "libgnome-games-support";
+  version = "1.8.1";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "0gs1k88wwafn5cdyb5yq1cxpi9azachb0ysxgwh15sx77g6plyy3";
+  };
+
+  nativeBuildInputs = [
+    gettext
+    meson
+    ninja
+    pkg-config
+    vala
+  ];
+
+  buildInputs = [
+    libintl
+  ];
+
+  propagatedBuildInputs = [
+    # Required by libgnome-games-support-1.pc
+    glib
+    gtk3
+    libgee
+  ];
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+      versionPolicy = "odd-unstable";
+    };
+  };
+
+  meta = with lib; {
+    description = "Small library intended for internal use by GNOME Games, but it may be used by others";
+    homepage = "https://wiki.gnome.org/Apps/Games";
+    license = licenses.lgpl3;
+    maintainers = teams.gnome.members;
+    platforms = platforms.unix;
+  };
+}
diff --git a/pkgs/desktops/gnome/misc/metacity/default.nix b/pkgs/desktops/gnome/misc/metacity/default.nix
new file mode 100644
index 00000000000..702b7ffb38b
--- /dev/null
+++ b/pkgs/desktops/gnome/misc/metacity/default.nix
@@ -0,0 +1,74 @@
+{ lib, stdenv
+, fetchurl
+, gettext
+, glib
+, gnome
+, gsettings-desktop-schemas
+, gtk3
+, xorg
+, libcanberra-gtk3
+, libgtop
+, libstartup_notification
+, libxml2
+, pkg-config
+, substituteAll
+, wrapGAppsHook
+, zenity
+}:
+
+stdenv.mkDerivation rec {
+  pname = "metacity";
+  version = "3.40.0";
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "1d8mj2nshijshfiaica8dirfws1p6i9631frq7q23b3y91jiyk12";
+  };
+
+  patches = [
+    (substituteAll {
+      src = ./fix-paths.patch;
+      inherit zenity;
+    })
+  ];
+
+  nativeBuildInputs = [
+    gettext
+    libxml2
+    pkg-config
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    xorg.libXres
+    xorg.libXpresent
+    xorg.libXdamage
+    glib
+    gsettings-desktop-schemas
+    gtk3
+    libcanberra-gtk3
+    libgtop
+    libstartup_notification
+    zenity
+  ];
+
+  enableParallelBuilding = true;
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+      versionPolicy = "odd-unstable";
+    };
+  };
+
+  doCheck = true;
+
+  meta = with lib; {
+    description = "Window manager used in Gnome Flashback";
+    homepage = "https://wiki.gnome.org/Projects/Metacity";
+    license = licenses.gpl2;
+    maintainers = teams.gnome.members;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/misc/metacity/fix-paths.patch b/pkgs/desktops/gnome/misc/metacity/fix-paths.patch
new file mode 100644
index 00000000000..ff3a244e67d
--- /dev/null
+++ b/pkgs/desktops/gnome/misc/metacity/fix-paths.patch
@@ -0,0 +1,11 @@
+--- a/src/core/util.c
++++ b/src/core/util.c
+@@ -424,7 +424,7 @@
+                                  g_slist_length (columns)*2 +
+                                  g_slist_length (entries)));
+ 
+-  argvl[i++] = "zenity";
++  argvl[i++] = "@zenity@/bin/zenity";
+   argvl[i++] = type;
+   argvl[i++] = "--display";
+   argvl[i++] = display;
diff --git a/pkgs/desktops/gnome/misc/nautilus-python/default.nix b/pkgs/desktops/gnome/misc/nautilus-python/default.nix
new file mode 100644
index 00000000000..40c1d4c767a
--- /dev/null
+++ b/pkgs/desktops/gnome/misc/nautilus-python/default.nix
@@ -0,0 +1,63 @@
+{ lib, stdenv
+, fetchurl
+, pkg-config
+, which
+, gtk-doc
+, docbook_xsl
+, docbook_xml_dtd_412
+, python3
+, ncurses
+, nautilus
+, gtk3
+, gnome
+}:
+
+stdenv.mkDerivation rec {
+  pname = "nautilus-python";
+  version = "1.2.3";
+
+  outputs = [ "out" "dev" "doc" ];
+
+  src = fetchurl {
+    url = "mirror://gnome/sources/${pname}/${lib.versions.majorMinor version}/${pname}-${version}.tar.xz";
+    sha256 = "161050sx3sdxqcpjkjcpf6wl4kx0jydihga7mcvrj9c2f8ly0g07";
+  };
+
+  nativeBuildInputs = [
+    pkg-config
+    which
+    gtk-doc
+    docbook_xsl
+    docbook_xml_dtd_412
+  ];
+
+  buildInputs = [
+    python3
+    ncurses # required by python3
+    python3.pkgs.pygobject3
+    nautilus
+    gtk3 # required by libnautilus-extension
+  ];
+
+  makeFlags = [
+    "PYTHON_LIB_LOC=${python3}/lib"
+  ];
+
+  PKG_CONFIG_LIBNAUTILUS_EXTENSION_EXTENSIONDIR = "${placeholder "out"}/lib/nautilus/extensions-3.0";
+
+  passthru = {
+    updateScript = gnome.updateScript {
+      packageName = pname;
+      attrPath = "gnome.${pname}";
+      versionPolicy = "odd-unstable";
+    };
+  };
+
+  meta = with lib; {
+    description = "Python bindings for the Nautilus Extension API";
+    homepage = "https://wiki.gnome.org/Projects/NautilusPython";
+    license = licenses.gpl2Plus;
+    maintainers = teams.gnome.members;
+    platforms = platforms.unix;
+  };
+}
diff --git a/pkgs/desktops/gnome/misc/pomodoro/default.nix b/pkgs/desktops/gnome/misc/pomodoro/default.nix
new file mode 100644
index 00000000000..ae52c41787b
--- /dev/null
+++ b/pkgs/desktops/gnome/misc/pomodoro/default.nix
@@ -0,0 +1,73 @@
+{ lib, stdenv
+, fetchFromGitHub
+, autoconf-archive
+, appstream-glib
+, pkg-config
+, wrapGAppsHook
+, libcanberra
+, gst_all_1
+, vala
+, gtk3
+, gom
+, sqlite
+, libxml2
+, autoreconfHook
+, glib
+, gobject-introspection
+, libpeas
+, gnome-shell
+, gsettings-desktop-schemas
+, adwaita-icon-theme
+, gettext
+}:
+
+stdenv.mkDerivation rec {
+  pname = "gnome-shell-pomodoro";
+  version = "0.18.0";
+
+  src = fetchFromGitHub {
+    owner = "codito";
+    repo = "gnome-pomodoro";
+    rev = version;
+    sha256 = "0990m8ydryd77kv25nfqli1n209i0h5dkjg9gkyww8bfrjhw47mc";
+  };
+
+  nativeBuildInputs = [
+    appstream-glib
+    autoconf-archive
+    autoreconfHook
+    gettext
+    gobject-introspection
+    libxml2
+    pkg-config
+    vala
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    adwaita-icon-theme
+    glib
+    gnome-shell
+    gom
+    gsettings-desktop-schemas
+    gst_all_1.gst-plugins-base
+    gst_all_1.gst-plugins-good
+    gst_all_1.gstreamer
+    gtk3
+    libcanberra
+    libpeas
+    sqlite
+  ];
+
+  meta = with lib; {
+    homepage = "https://gnomepomodoro.org/";
+    description = "Time management utility for GNOME based on the pomodoro technique";
+    longDescription = ''
+      This GNOME utility helps to manage time according to Pomodoro Technique.
+      It intends to improve productivity and focus by taking short breaks.
+    '';
+    maintainers = with maintainers; [ worldofpeace ];
+    license = licenses.gpl3Plus;
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/desktops/gnome/update.nix b/pkgs/desktops/gnome/update.nix
new file mode 100644
index 00000000000..928eac45160
--- /dev/null
+++ b/pkgs/desktops/gnome/update.nix
@@ -0,0 +1,26 @@
+{ stdenv, pkgs, lib, writeScript, python3, common-updater-scripts }:
+{ packageName, attrPath ? packageName, versionPolicy ? "tagged", freeze ? false }:
+
+let
+  python = python3.withPackages (p: [ p.requests p.libversion ]);
+  upperBoundFlag =
+    let
+      package = lib.attrByPath (lib.splitString "." attrPath) (throw "Cannot find attribute ‘${attrPath}’.") pkgs;
+      packageVersion = lib.getVersion package;
+      versionComponents = lib.versions.splitVersion packageVersion;
+      minorVersion = lib.versions.minor packageVersion;
+      minorAvailable = builtins.length versionComponents > 1 && builtins.match "[0-9]+" minorVersion != null;
+      nextMinor = builtins.fromJSON minorVersion + 1;
+      upperBound = "${lib.versions.major packageVersion}.${builtins.toString nextMinor}";
+    in lib.optionalString (freeze && minorAvailable) ''--upper-bound="${upperBound}"'';
+  updateScript = writeScript "gnome-update-script" ''
+    #!${stdenv.shell}
+    set -o errexit
+    package_name="$1"
+    attr_path="$2"
+    version_policy="$3"
+    PATH=${lib.makeBinPath [ common-updater-scripts python ]}
+    latest_tag=$(python "${./find-latest-version.py}" "$package_name" "$version_policy" "stable" ${upperBoundFlag})
+    update-source-version "$attr_path" "$latest_tag"
+  '';
+in [ updateScript packageName attrPath versionPolicy ]