diff --git a/backends/platform/sdl/module.mk b/backends/platform/sdl/module.mk
index 230ea04b35157..4169cfc9a537f 100644
--- a/backends/platform/sdl/module.mk
+++ b/backends/platform/sdl/module.mk
@@ -79,6 +79,13 @@ MODULE_OBJS += \
psp2/psp2.o
endif
+ifdef SAILFISH
+MODULE_OBJS += \
+ sailfish/sailfish-main.o \
+ sailfish/sailfish-window.o \
+ sailfish/sailfish.o
+endif
+
ifdef SWITCH
MODULE_OBJS += \
switch/switch-main.o \
diff --git a/backends/platform/sdl/posix/posix-main.cpp b/backends/platform/sdl/posix/posix-main.cpp
index a24bd0c3776f0..ed1c2e7e89b9c 100644
--- a/backends/platform/sdl/posix/posix-main.cpp
+++ b/backends/platform/sdl/posix/posix-main.cpp
@@ -21,7 +21,7 @@
#include "common/scummsys.h"
-#if defined(POSIX) && !defined(MACOSX) && !defined(SAMSUNGTV) && !defined(MAEMO) && !defined(DINGUX) && !defined(OPENPANDORA) && !defined(PLAYSTATION3) && !defined(PSP2) && !defined(NINTENDO_SWITCH) && !defined(__EMSCRIPTEN__) && !defined(MIYOO) && !defined(MIYOOMINI)
+#if defined(POSIX) && !defined(MACOSX) && !defined(SAMSUNGTV) && !defined(MAEMO) && !defined(DINGUX) && !defined(OPENPANDORA) && !defined(PLAYSTATION3) && !defined(PSP2) && !defined(NINTENDO_SWITCH) && !defined(__EMSCRIPTEN__) && !defined(MIYOO) && !defined(MIYOOMINI) && !defined(SAILFISH)
#include "backends/platform/sdl/posix/posix.h"
#include "backends/plugins/sdl/sdl-provider.h"
diff --git a/backends/platform/sdl/sailfish/README.md b/backends/platform/sdl/sailfish/README.md
new file mode 100644
index 0000000000000..b85c10fed6ffa
--- /dev/null
+++ b/backends/platform/sdl/sailfish/README.md
@@ -0,0 +1,48 @@
+Welcome to Sailfish port of ScummVM.
+
+# Building
+
+First you need to download dependencies as we link statically with them:
+
+``` shell
+./sailfish-download.sh
+```
+
+You have to do this only once
+
+Suppose that your SDK is in `$SDK_ROOT`
+
+First you need to figure out your target config
+
+``` shell
+$SDK_ROOT/bin/sfdk engine exec sb2-config -l
+```
+
+``` text
+
+SailfishOS-armv7hl
+SailfishOS-i486-x86
+```
+
+Then run:
+
+``` shell
+$SDK_ROOT/bin/sfdk config --push target $TARGET
+$SDK_ROOT/bin/sfdk build
+```
+
+And finally you need to sign them with your developper key:
+
+``` shell
+$SDK_ROOT/bin/sfdk engine exec -tt sb2 -t $TARGET rpmsign-external sign -k $KEY_PATH/regular_key.pem -c $KEY_PATH/regular_cert.pem RPMS/*.rpm
+```
+
+
+# Known issues
+
+* Screen dimming and sleep aren't inhibited in game
+* If you close ScummVM window on the panel ScummVM isn't closed and you
+can't open it again
+* When switching From Surface SDL to OpenGL renderer touchscreen coordinates
+are garbled until restart
+* make install doesn't install Sailfish-specific file. It's done in RPM spec
diff --git a/backends/platform/sdl/sailfish/rpm/org.scummvm.scummvm.spec b/backends/platform/sdl/sailfish/rpm/org.scummvm.scummvm.spec
new file mode 100644
index 0000000000000..41355945f2cbc
--- /dev/null
+++ b/backends/platform/sdl/sailfish/rpm/org.scummvm.scummvm.spec
@@ -0,0 +1,276 @@
+%if %{undefined outdir}
+%define outdir out-sailfish.%{_arch}
+%endif
+
+%if %{undefined real_src_path}
+%define real_src_path OFF
+%endif
+
+%define freetype_version 2.13.3
+%define flac_version 1.4.3
+%define theora_version 1.1.1
+%define jpeg_turbo_version 3.0.4
+%define libmad_version 0.15.1b
+%define libmpeg2_version 0.5.1
+%define libfaad_version 2.8.8
+%define giflib_version 5.2.2
+%define fribidi_version 1.0.16
+%define sdl2_version 2.30.7
+
+%define minimal_build 1
+
+%if %{minimal_build}
+%define engine_config --disable-all-engines --enable-engines=scumm
+%else
+%define engine_config %{nil}
+%endif
+
+%define _rpmfilename %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm
+
+Name: org.scummvm.scummvm
+Summary: ScummVM: Multi-game engine
+Version: 0
+Release: 1
+Group: Qt/Qt
+License: GPLv3
+URL: https://scummvm.org
+Source0: %{name}-%{version}.tar.bz2
+BuildRequires: pkgconfig(sdl2)
+BuildRequires: SDL2_net-devel
+BuildRequires: pkgconfig(ogg)
+BuildRequires: pkgconfig(vorbis)
+BuildRequires: pkgconfig(libpng)
+BuildRequires: pkgconfig(vpx)
+BuildRequires: pkgconfig(egl)
+BuildRequires: pkgconfig(glesv2)
+BuildRequires: cmake
+
+%description
+ScummVM: Multi-game engine
+
+%build
+mkdir -p %{outdir}
+mkdir -p %{outdir}/scummvm
+mkdir -p %{outdir}/pkgconfig
+if ! [ -d %{outdir}/freetype-install ]; then
+ cd %{outdir}
+ tar xvf ../rpmdeps/freetype-%{freetype_version}.tar.xz
+ cd freetype-%{freetype_version}
+ ./configure --prefix=$PWD/../freetype-install --disable-shared --enable-static
+ make %{?_smp_mflags}
+ make install
+ cd ../..
+fi
+if ! [ -d %{outdir}/flac-install ]; then
+ cd %{outdir}
+ tar xvf ../rpmdeps/flac-%{flac_version}.tar.xz
+ cd flac-%{flac_version}
+ ./configure --disable-shared --enable-static --disable-examples --disable-programs
+ make %{?_smp_mflags}
+ make DESTDIR=$PWD/../flac-install INSTALL_ROOT=$PWD/../flac-install install
+ cd ../..
+fi
+if ! [ -d %{outdir}/theora-install ]; then
+ cd %{outdir}
+ tar xvf ../rpmdeps/libtheora-%{theora_version}.tar.xz
+ cd libtheora-%{theora_version}
+ ./configure --disable-shared --enable-static --disable-examples --disable-programs
+ make %{?_smp_mflags}
+ make DESTDIR=$PWD/../theora-install INSTALL_ROOT=$PWD/../theora-install install
+ cd ../..
+fi
+if ! [ -d %{outdir}/jpeg-install ]; then
+ cd %{outdir}
+ tar xvf ../rpmdeps/libjpeg-turbo-%{jpeg_turbo_version}.tar.gz
+ cd libjpeg-turbo-%{jpeg_turbo_version}
+ %cmake -DENABLE_SHARED=FALSE
+ make %{?_smp_mflags}
+ make DESTDIR=$PWD/../jpeg-install INSTALL_ROOT=$PWD/../jpeg-install install
+ cd ../..
+fi
+if ! [ -d %{outdir}/libmad-install ]; then
+ cd %{outdir}
+ tar xvf ../rpmdeps/libmad-%{libmad_version}.tar.gz
+ cd libmad-%{libmad_version}
+ ASFLAGS=-marm CFLAGS="-O2 -marm" ./configure --disable-shared --enable-static --disable-examples --disable-programs CFLAGS="-O2 -marm" ASFLAGS=-marm
+ make CFLAGS="-O2 -marm" ASFLAGS=-marm %{?_smp_mflags}
+ make DESTDIR=$PWD/../libmad-install INSTALL_ROOT=$PWD/../libmad-install install
+ cd ../..
+fi
+if ! [ -d %{outdir}/mpeg2-install ]; then
+ cd %{outdir}
+ tar xvf ../rpmdeps/libmpeg2-%{libmpeg2_version}.tar.gz
+ cd libmpeg2-%{libmpeg2_version}
+ ./configure --disable-shared --enable-static --disable-examples --disable-programs
+ make %{?_smp_mflags}
+ make DESTDIR=$PWD/../mpeg2-install INSTALL_ROOT=$PWD/../mpeg2-install install
+ cd ../..
+fi
+if ! [ -d %{outdir}/faad-install ]; then
+ cd %{outdir}
+ tar xvf ../rpmdeps/faad2-%{libfaad_version}.tar.gz
+ cd faad2-%{libfaad_version}
+ ./configure --disable-shared --enable-static --disable-examples --disable-programs
+ make %{?_smp_mflags}
+ make DESTDIR=$PWD/../faad-install INSTALL_ROOT=$PWD/../faad-install install
+ cd ../..
+fi
+if ! [ -d %{outdir}/giflib-install ]; then
+ cd %{outdir}
+ tar xvf ../rpmdeps/giflib-%{giflib_version}.tar.gz
+ cd giflib-%{giflib_version}
+ make %{?_smp_mflags} libgif.a
+ make DESTDIR=$PWD/../giflib-install INSTALL_ROOT=$PWD/../giflib-install install-include
+ install -d "$PWD/../giflib-install/usr/local/lib"
+ install -m 644 libgif.a "$PWD/../giflib-install/usr/local/lib/libgif.a"
+ cd ../..
+fi
+if ! [ -d %{outdir}/fribidi-install ]; then
+ cd %{outdir}
+ tar xvf ../rpmdeps/fribidi-%{fribidi_version}.tar.xz
+ cd fribidi-%{fribidi_version}
+ ./configure --disable-shared --enable-static --prefix=$PWD/../fribidi-install
+ make %{?_smp_mflags}
+ make install
+ cd ../..
+fi
+if ! [ -d %{outdir}/sdl-install ]; then
+ cd %{outdir}
+ tar xvf ../rpmdeps/SDL2-%{sdl2_version}.tar.gz
+ cd SDL2-%{sdl2_version}
+ for x in ../../sdl-patches/*.patch; do
+ echo "Applying patch $x"
+ patch -p1 -i "$x"
+ done
+ cd ..
+ cmake \
+ -Bsdl-build \
+ -DSDL_PULSEAUDIO=ON \
+ -DSDL_RPATH=OFF \
+ -DSDL_STATIC=ON \
+ -DSDL_SHARED=OFF \
+ -DSDL_WAYLAND=ON \
+ -DSDL_X11=OFF \
+ -DSDL_DBUS=ON \
+ -DSDL_WAYLAND_LIBDECOR=OFF \
+ -DSDL_WAYLAND_QT_TOUCH=OFF \
+ SDL2-%{sdl2_version}
+ make -C sdl-build %{?_smp_mflags}
+ make -C sdl-build install DESTDIR=$PWD/sdl-install INSTALL_ROOT=$PWD/sdl-install
+ cd ..
+fi
+sed "s@Libs: .*@Libs: $PWD/%{outdir}/freetype-install/lib/libfreetype.a@g" < %{outdir}/freetype-install/lib/pkgconfig/freetype2.pc > %{outdir}/pkgconfig/freetype2.pc
+sed "s@Libs: .*@Libs: $PWD/%{outdir}/fribidi-install/lib/libfribidi.a@g" < %{outdir}/fribidi-install/lib/pkgconfig/fribidi.pc > %{outdir}/pkgconfig/fribidi.pc
+export PKG_CONFIG_PATH=$PWD/%{outdir}/pkgconfig:$PKG_CONFIG_PATH
+cd %{outdir}/scummvm;
+../../../../../../configure --host=sailfish \
+ --with-jpeg-prefix=../jpeg-install/usr \
+ --with-mad-prefix=../libmad-install/usr/local \
+ --with-flac-prefix=../flac-install/usr/local \
+ --with-theoradec-prefix=../theora-install/usr/local \
+ --with-mpeg2-prefix=../mpeg2-install/usr/local \
+ --with-faad-prefix=../faad-install/usr/local \
+ --with-gif-prefix=../giflib-install/usr/local \
+ --enable-fribidi --with-fribidi-prefix=../fribidi-install/usr/local/org.scummvm.scummvm \
+ --with-sdl-prefix=../sdl-install/usr/local --enable-static \
+ %{engine_config} --disable-tinygl
+cd ../..
+%{__make} -C %{outdir}/scummvm %{_make_output_sync} %{?_smp_mflags}
+
+%install
+rm -rf %{buildroot}/*
+%{__make} -C %{outdir}/scummvm DESTDIR=%{buildroot} INSTALL_ROOT=%{buildroot} install
+# TODO: Move this stuff into make
+mkdir -p %{buildroot}/usr/share/applications
+mkdir -p %{buildroot}/usr/share/icons/hicolor/86x86/apps
+mkdir -p %{buildroot}/usr/share/icons/hicolor/108x108/apps
+mkdir -p %{buildroot}/usr/share/icons/hicolor/128x128/apps
+mkdir -p %{buildroot}/usr/share/icons/hicolor/172x172/apps
+cp ../../../../dists/sailfish/org.scummvm.scummvm.desktop %{buildroot}/usr/share/applications/org.scummvm.scummvm.desktop
+cp ../../../../dists/sailfish/86x86.png %{buildroot}/usr/share/icons/hicolor/86x86/apps/org.scummvm.scummvm.png
+cp ../../../../dists/sailfish/108x108.png %{buildroot}/usr/share/icons/hicolor/108x108/apps/org.scummvm.scummvm.png
+cp ../../../../dists/sailfish/128x128.png %{buildroot}/usr/share/icons/hicolor/128x128/apps/org.scummvm.scummvm.png
+cp ../../../../dists/sailfish/172x172.png %{buildroot}/usr/share/icons/hicolor/172x172/apps/org.scummvm.scummvm.png
+
+%files
+%defattr(755,root,root,-)
+%{_bindir}/org.scummvm.scummvm
+
+%defattr(644,root,root,-)
+
+%{_datadir}/org.scummvm.scummvm/applications/%{name}.desktop
+%{_datadir}/org.scummvm.scummvm/doc/scummvm/AUTHORS
+%{_datadir}/org.scummvm.scummvm/doc/scummvm/CONTRIBUTING.md
+%{_datadir}/org.scummvm.scummvm/doc/scummvm/COPYING
+%{_datadir}/org.scummvm.scummvm/doc/scummvm/COPYING.Apache
+%{_datadir}/org.scummvm.scummvm/doc/scummvm/COPYING.BSD
+%{_datadir}/org.scummvm.scummvm/doc/scummvm/COPYING.BSL
+%{_datadir}/org.scummvm.scummvm/doc/scummvm/COPYING.FREEFONT
+%{_datadir}/org.scummvm.scummvm/doc/scummvm/COPYING.GLAD
+%{_datadir}/org.scummvm.scummvm/doc/scummvm/COPYING.ISC
+%{_datadir}/org.scummvm.scummvm/doc/scummvm/COPYING.LGPL
+%{_datadir}/org.scummvm.scummvm/doc/scummvm/COPYING.LUA
+%{_datadir}/org.scummvm.scummvm/doc/scummvm/COPYING.MIT
+%{_datadir}/org.scummvm.scummvm/doc/scummvm/COPYING.MKV
+%{_datadir}/org.scummvm.scummvm/doc/scummvm/COPYING.MPL
+%{_datadir}/org.scummvm.scummvm/doc/scummvm/COPYING.OFL
+%{_datadir}/org.scummvm.scummvm/doc/scummvm/COPYING.TINYGL
+%{_datadir}/org.scummvm.scummvm/doc/scummvm/COPYRIGHT
+%{_datadir}/org.scummvm.scummvm/doc/scummvm/CatharonLicense.txt
+%{_datadir}/org.scummvm.scummvm/doc/scummvm/NEWS.md
+%{_datadir}/org.scummvm.scummvm/doc/scummvm/README.md
+%{_datadir}/org.scummvm.scummvm/icons/hicolor/scalable/apps/org.scummvm.scummvm.svg
+%{_datadir}/org.scummvm.scummvm/man/man6/scummvm.6
+%{_datadir}/org.scummvm.scummvm/metainfo/org.scummvm.scummvm.metainfo.xml
+%{_datadir}/org.scummvm.scummvm/pixmaps/org.scummvm.scummvm.xpm
+%{_datadir}/org.scummvm.scummvm/scummvm/achievements.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/classicmacfonts.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/encoding.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/fonts-cjk.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/fonts.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/vkeybd_default.zip
+%{_datadir}/org.scummvm.scummvm/scummvm/vkeybd_small.zip
+%{_datadir}/org.scummvm.scummvm/scummvm/gui-icons.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/helpdialog.zip
+%{_datadir}/org.scummvm.scummvm/scummvm/macgui.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/residualvm.zip
+%{_datadir}/org.scummvm.scummvm/scummvm/scummclassic.zip
+%{_datadir}/org.scummvm.scummvm/scummvm/scummmodern.zip
+%{_datadir}/org.scummvm.scummvm/scummvm/scummremastered.zip
+%{_datadir}/org.scummvm.scummvm/scummvm/shaders.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/translations.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/wwwroot.zip
+%if !%{minimal_build}
+%{_datadir}/org.scummvm.scummvm/scummvm/access.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/bagel.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/cryomni3d.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/drascula.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/freescape.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/grim-patch.lab
+%{_datadir}/org.scummvm.scummvm/scummvm/hadesch_translations.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/hugo.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/kyra.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/lure.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/mm.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/mort.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/myst3.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/nancy.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/neverhood.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/pred.dic
+%{_datadir}/org.scummvm.scummvm/scummvm/prince_translation.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/queen.tbl
+%{_datadir}/org.scummvm.scummvm/scummvm/sky.cpt
+%{_datadir}/org.scummvm.scummvm/scummvm/supernova.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/teenagent.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/titanic.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/tony.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/toon.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/ultima.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/ultima8.dat
+%{_datadir}/org.scummvm.scummvm/scummvm/wintermute.zip
+%endif
+%{_datadir}/applications/org.scummvm.scummvm.desktop
+%{_datadir}/icons/hicolor/108x108/apps/org.scummvm.scummvm.png
+%{_datadir}/icons/hicolor/128x128/apps/org.scummvm.scummvm.png
+%{_datadir}/icons/hicolor/172x172/apps/org.scummvm.scummvm.png
+%{_datadir}/icons/hicolor/86x86/apps/org.scummvm.scummvm.png
diff --git a/backends/platform/sdl/sailfish/sailfish-download.sh b/backends/platform/sdl/sailfish/sailfish-download.sh
new file mode 100644
index 0000000000000..bd2ae974442c2
--- /dev/null
+++ b/backends/platform/sdl/sailfish/sailfish-download.sh
@@ -0,0 +1,10 @@
+wget -O rpmdeps/freetype-2.13.3.tar.xz https://download.savannah.gnu.org/releases/freetype/freetype-2.13.3.tar.xz
+wget -O rpmdeps/flac-1.4.3.tar.xz https://ftp.osuosl.org/pub/xiph/releases/flac/flac-1.4.3.tar.xz
+wget -O rpmdeps/libjpeg-turbo-3.0.4.tar.gz https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/3.0.4/libjpeg-turbo-3.0.4.tar.gz
+wget -O rpmdeps/libmad-0.15.1b.tar.gz https://downloads.sourceforge.net/mad/libmad-0.15.1b.tar.gz
+wget -O rpmdeps/libmpeg2-0.5.1.tar.gz https://libmpeg2.sourceforge.net/files/libmpeg2-0.5.1.tar.gz
+wget -O rpmdeps/faad2-2.8.8.tar.gz https://sourceforge.net/projects/faac/files/faad2-src/faad2-2.8.0/faad2-2.8.8.tar.gz
+wget -O rpmdeps/giflib-5.2.2.tar.gz https://sourceforge.net/projects/giflib/files/giflib-5.2.2.tar.gz
+wget -O rpmdeps/fribidi-1.0.16.tar.xz https://github.com/fribidi/fribidi/releases/download/v1.0.16/fribidi-1.0.16.tar.xz
+wget -O rpmdeps/libtheora-1.1.1.tar.xz https://ftp.osuosl.org/pub/xiph/releases/theora/libtheora-1.1.1.tar.xz
+wget -O rpmdeps/SDL2-2.30.7.tar.gz https://github.com/libsdl-org/SDL/releases/download/release-2.30.7/SDL2-2.30.7.tar.gz
diff --git a/backends/platform/sdl/sailfish/sailfish-main.cpp b/backends/platform/sdl/sailfish/sailfish-main.cpp
new file mode 100644
index 0000000000000..8e348cc374542
--- /dev/null
+++ b/backends/platform/sdl/sailfish/sailfish-main.cpp
@@ -0,0 +1,45 @@
+
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#include "backends/platform/sdl/sailfish/sailfish.h"
+#include "backends/plugins/sdl/sdl-provider.h"
+#include "base/main.h"
+
+int main(int argc, char* argv[]) {
+
+ g_system = new OSystem_SDL_Sailfish();
+ assert(g_system);
+
+ g_system->init();
+
+#ifdef DYNAMIC_MODULES
+ PluginManager::instance().addPluginProvider(new SDLPluginProvider());
+#endif
+
+ // Invoke the actual ScummVM main entry point:
+ int res = scummvm_main(argc, argv);
+
+ // Free OSystem
+ g_system->destroy();
+
+ return res;
+}
diff --git a/backends/platform/sdl/sailfish/sailfish-window.cpp b/backends/platform/sdl/sailfish/sailfish-window.cpp
new file mode 100644
index 0000000000000..e0ec87dac82a4
--- /dev/null
+++ b/backends/platform/sdl/sailfish/sailfish-window.cpp
@@ -0,0 +1,38 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#include "backends/graphics/sdl/sdl-graphics.h"
+#include "backends/platform/sdl/sailfish/sailfish-window.h"
+
+bool SdlWindow_Sailfish::createOrUpdateWindow(int, int, uint32 flags) {
+ SDL_DisplayMode dm;
+ SDL_GetCurrentDisplayMode(0,&dm);
+ int width, height;
+
+ if (dm.w < dm.h) {
+ width = dm.w;
+ height = dm.h;
+ } else {
+ width = dm.h;
+ height = dm.w;
+ }
+ return SdlWindow::createOrUpdateWindow(width, height, flags);
+}
diff --git a/backends/platform/sdl/sailfish/sailfish-window.h b/backends/platform/sdl/sailfish/sailfish-window.h
new file mode 100644
index 0000000000000..b30a7c3385783
--- /dev/null
+++ b/backends/platform/sdl/sailfish/sailfish-window.h
@@ -0,0 +1,32 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#ifndef BACKENDS_PLATFORM_SDL_MACOSX_MACOSX_WINDOW_H
+#define BACKENDS_PLATFORM_SDL_MACOSX_MACOSX_WINDOW_H
+
+#include "backends/platform/sdl/sdl-window.h"
+
+class SdlWindow_Sailfish final : public SdlWindow {
+public:
+ bool createOrUpdateWindow(int, int, uint32 flags) override;
+};
+
+#endif
diff --git a/backends/platform/sdl/sailfish/sailfish.cpp b/backends/platform/sdl/sailfish/sailfish.cpp
new file mode 100644
index 0000000000000..f8c8466b6d406
--- /dev/null
+++ b/backends/platform/sdl/sailfish/sailfish.cpp
@@ -0,0 +1,144 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
+#include "common/scummsys.h"
+#include "common/config-manager.h"
+#include "common/translation.h"
+
+#include "backends/platform/sdl/sailfish/sailfish.h"
+#include "backends/platform/sdl/sailfish/sailfish-window.h"
+
+#include "backends/fs/posix/posix-fs-factory.h"
+#include "backends/fs/posix/posix-fs.h"
+#include "backends/saves/default/default-saves.h"
+
+#include "backends/keymapper/action.h"
+#include "backends/keymapper/keymapper-defaults.h"
+#include "backends/keymapper/hardware-input.h"
+#include "backends/keymapper/keymap.h"
+#include "backends/keymapper/keymapper.h"
+
+#define ORG_NAME "org.scummvm"
+#define APP_NAME "scummvm"
+
+void OSystem_SDL_Sailfish::init() {
+ // Initialze File System Factory
+ _fsFactory = new POSIXFilesystemFactory();
+
+ _window = new SdlWindow_Sailfish();
+
+ // Invoke parent implementation of this method
+ OSystem_SDL::init();
+}
+
+void OSystem_SDL_Sailfish::initBackend() {
+ if (!ConfMan.hasKey("rotation_mode")) {
+ ConfMan.setPath("rotation_mode", "90");
+ }
+
+ if (!ConfMan.hasKey("savepath")) {
+ ConfMan.setPath("savepath", getDefaultSavePath());
+ }
+
+ // Create the savefile manager
+ if (_savefileManager == nullptr) {
+ _savefileManager = new DefaultSaveFileManager(getDefaultSavePath());
+ }
+
+ OSystem_SDL::initBackend();
+}
+
+Common::Path OSystem_SDL_Sailfish::getDefaultSavePath() {
+ Common::String saveRelPath;
+
+ const char *prefix = getenv("HOME");
+ if (prefix == nullptr) {
+ return Common::Path();
+ }
+
+ saveRelPath = ".local/share/" ORG_NAME "/" APP_NAME "/saves";
+
+ if (!Posix::assureDirectoryExists(saveRelPath, prefix)) {
+ return Common::Path();
+ }
+
+ Common::Path savePath(prefix);
+ savePath.joinInPlace(saveRelPath);
+
+ return savePath;
+}
+
+Common::Path OSystem_SDL_Sailfish::getDefaultConfigFileName() {
+ Common::String configPath;
+
+ const char *prefix = getenv("HOME");
+ if (prefix == nullptr) {
+ return Common::Path();
+ }
+
+ configPath = ".local/share/" ORG_NAME "/" APP_NAME ;
+
+ if (!Posix::assureDirectoryExists(configPath, prefix)) {
+ return Common::Path();
+ }
+
+ Common::Path configFile(prefix);
+ configFile.joinInPlace(configPath);
+ configFile.joinInPlace("scummvm.ini");
+
+ return configFile;
+}
+
+Common::Path OSystem_SDL_Sailfish::getDefaultLogFileName() {
+ Common::String logFile;
+
+ const char *prefix = getenv("HOME");
+ if (prefix == nullptr) {
+ return Common::Path();
+ }
+
+ logFile = ".cache/" ORG_NAME "/" APP_NAME "/logs";
+
+ if (!Posix::assureDirectoryExists(logFile, prefix)) {
+ return Common::Path();
+ }
+
+ Common::Path logPath(prefix);
+ logPath.joinInPlace(logFile);
+ logPath.joinInPlace("scummvm.log");
+
+ return logPath;
+}
+
+
+bool OSystem_SDL_Sailfish::hasFeature(Feature f) {
+ switch (f) {
+ case kFeatureFullscreenMode:
+ case kFeatureAspectRatioCorrection:
+ return false;
+ case kFeatureTouchpadMode:
+ return true;
+ default:
+ return OSystem_SDL::hasFeature(f);
+ }
+}
diff --git a/backends/platform/sdl/sailfish/sailfish.h b/backends/platform/sdl/sailfish/sailfish.h
new file mode 100644
index 0000000000000..4f47101fecb82
--- /dev/null
+++ b/backends/platform/sdl/sailfish/sailfish.h
@@ -0,0 +1,41 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+#ifndef PLATFORM_SDL_SAILFISH_H
+#define PLATFORM_SDL_SAILFISH_H
+
+#include "backends/platform/sdl/sdl.h"
+
+class OSystem_SDL_Sailfish : public OSystem_SDL {
+public:
+ void init() override;
+ void initBackend() override;
+ bool hasFeature(Feature f) override;
+
+protected:
+ Common::Path getDefaultConfigFileName() override;
+ Common::Path getDefaultLogFileName() override;
+
+private:
+ Common::Path getDefaultSavePath();
+};
+
+#endif
diff --git a/backends/platform/sdl/sailfish/sdl-patches/0001-wayland-Bring-back-wl_shell-support.patch b/backends/platform/sdl/sailfish/sdl-patches/0001-wayland-Bring-back-wl_shell-support.patch
new file mode 100644
index 0000000000000..1819fec76b5d2
--- /dev/null
+++ b/backends/platform/sdl/sailfish/sdl-patches/0001-wayland-Bring-back-wl_shell-support.patch
@@ -0,0 +1,288 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Matti=20Lehtim=C3=A4ki?=
+Date: Wed, 20 Apr 2022 18:03:42 +0300
+Subject: [PATCH] wayland: Bring back wl_shell support
+
+---
+ include/SDL_syswm.h | 2 +-
+ src/video/wayland/SDL_waylanddyn.h | 2 +
+ src/video/wayland/SDL_waylandevents.c | 8 +++
+ src/video/wayland/SDL_waylandsym.h | 2 +
+ src/video/wayland/SDL_waylandvideo.c | 7 ++
+ src/video/wayland/SDL_waylandvideo.h | 1 +
+ src/video/wayland/SDL_waylandwindow.c | 95 +++++++++++++++++++++++++++
+ src/video/wayland/SDL_waylandwindow.h | 1 +
+ 8 files changed, 117 insertions(+), 1 deletion(-)
+
+diff --git a/include/SDL_syswm.h b/include/SDL_syswm.h
+index 7b8bd6ef996571bbba2e5f1e139a0c9292c88146..671a26ee945bdac99de9f07b57aef9cc893f4cec 100644
+--- a/include/SDL_syswm.h
++++ b/include/SDL_syswm.h
+@@ -294,7 +294,7 @@ struct SDL_SysWMinfo
+ {
+ struct wl_display *display; /**< Wayland display */
+ struct wl_surface *surface; /**< Wayland surface */
+- void *shell_surface; /**< DEPRECATED Wayland shell_surface (window manager handle) */
++ struct wl_shell_surface *shell_surface; /**< DEPRECATED Wayland shell_surface (window manager handle) */
+ struct wl_egl_window *egl_window; /**< Wayland EGL window (native window) */
+ struct xdg_surface *xdg_surface; /**< Wayland xdg surface (window manager handle) */
+ struct xdg_toplevel *xdg_toplevel; /**< Wayland xdg toplevel role */
+diff --git a/src/video/wayland/SDL_waylanddyn.h b/src/video/wayland/SDL_waylanddyn.h
+index 6feb343912b15a6a9360a11b66a08c0c4e36f882..2c93149cd2dcbff5a69c20606c028aa13905dced 100644
+--- a/src/video/wayland/SDL_waylanddyn.h
++++ b/src/video/wayland/SDL_waylanddyn.h
+@@ -111,11 +111,13 @@ void SDL_WAYLAND_UnloadSymbols(void);
+ #define wl_shm_pool_interface (*WAYLAND_wl_shm_pool_interface)
+ #define wl_buffer_interface (*WAYLAND_wl_buffer_interface)
+ #define wl_registry_interface (*WAYLAND_wl_registry_interface)
++#define wl_shell_surface_interface (*WAYLAND_wl_shell_surface_interface)
+ #define wl_region_interface (*WAYLAND_wl_region_interface)
+ #define wl_pointer_interface (*WAYLAND_wl_pointer_interface)
+ #define wl_keyboard_interface (*WAYLAND_wl_keyboard_interface)
+ #define wl_compositor_interface (*WAYLAND_wl_compositor_interface)
+ #define wl_output_interface (*WAYLAND_wl_output_interface)
++#define wl_shell_interface (*WAYLAND_wl_shell_interface)
+ #define wl_shm_interface (*WAYLAND_wl_shm_interface)
+ #define wl_data_device_interface (*WAYLAND_wl_data_device_interface)
+ #define wl_data_offer_interface (*WAYLAND_wl_data_offer_interface)
+diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c
+index a8382812ab149c4377441d46a693f736f5430cad..45d679abdafb94708e478745d4f1db57922c37b7 100644
+--- a/src/video/wayland/SDL_waylandevents.c
++++ b/src/video/wayland/SDL_waylandevents.c
+@@ -518,6 +518,10 @@ static SDL_bool ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial)
+ input->seat,
+ serial);
+ }
++ } else {
++ if (window_data->shell_surface.wl) {
++ wl_shell_surface_move(window_data->shell_surface.wl, input->seat, serial);
++ }
+ }
+ return SDL_TRUE;
+
+@@ -543,6 +547,10 @@ static SDL_bool ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial)
+ serial,
+ directions[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
+ }
++ } else {
++ if (window_data->shell_surface.wl) {
++ wl_shell_surface_resize(window_data->shell_surface.wl, input->seat, serial, directions[rc - SDL_HITTEST_RESIZE_TOPLEFT]);
++ }
+ }
+ return SDL_TRUE;
+
+diff --git a/src/video/wayland/SDL_waylandsym.h b/src/video/wayland/SDL_waylandsym.h
+index 1b02b01c6691bd2df30508ab88bbd990586594d0..27ff34a31a77c970300790697204594d24e11a1f 100644
+--- a/src/video/wayland/SDL_waylandsym.h
++++ b/src/video/wayland/SDL_waylandsym.h
+@@ -101,11 +101,13 @@ SDL_WAYLAND_INTERFACE(wl_surface_interface)
+ SDL_WAYLAND_INTERFACE(wl_shm_pool_interface)
+ SDL_WAYLAND_INTERFACE(wl_buffer_interface)
+ SDL_WAYLAND_INTERFACE(wl_registry_interface)
++SDL_WAYLAND_INTERFACE(wl_shell_surface_interface)
+ SDL_WAYLAND_INTERFACE(wl_region_interface)
+ SDL_WAYLAND_INTERFACE(wl_pointer_interface)
+ SDL_WAYLAND_INTERFACE(wl_keyboard_interface)
+ SDL_WAYLAND_INTERFACE(wl_compositor_interface)
+ SDL_WAYLAND_INTERFACE(wl_output_interface)
++SDL_WAYLAND_INTERFACE(wl_shell_interface)
+ SDL_WAYLAND_INTERFACE(wl_shm_interface)
+ SDL_WAYLAND_INTERFACE(wl_data_device_interface)
+ SDL_WAYLAND_INTERFACE(wl_data_source_interface)
+diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c
+index 2cae471792cd692129f193fac2100d7d98ab6705..70e9d7306a8fcc60a4b8b1a9289c18f88a8de990 100644
+--- a/src/video/wayland/SDL_waylandvideo.c
++++ b/src/video/wayland/SDL_waylandvideo.c
+@@ -846,6 +846,8 @@ static void display_handle_global(void *data, struct wl_registry *registry, uint
+ } else if (SDL_strcmp(interface, "xdg_wm_base") == 0) {
+ d->shell.xdg = wl_registry_bind(d->registry, id, &xdg_wm_base_interface, SDL_min(version, 3));
+ xdg_wm_base_add_listener(d->shell.xdg, &shell_listener_xdg, NULL);
++ } else if (SDL_strcmp(interface, "wl_shell") == 0) {
++ d->shell.wl = wl_registry_bind(d->registry, id, &wl_shell_interface, 1);
+ } else if (SDL_strcmp(interface, "wl_shm") == 0) {
+ d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
+ } else if (SDL_strcmp(interface, "zwp_relative_pointer_manager_v1") == 0) {
+@@ -1097,6 +1099,11 @@ static void Wayland_VideoCleanup(_THIS)
+ data->shm = NULL;
+ }
+
++ if (data->shell.wl) {
++ wl_shell_destroy(data->shell.wl);
++ data->shell.wl = NULL;
++ }
++
+ if (data->shell.xdg) {
+ xdg_wm_base_destroy(data->shell.xdg);
+ data->shell.xdg = NULL;
+diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h
+index b7b3348c6d4d9285971d5a2416f7d123f303c7f8..e57ab2bd21a3064c257d704b4912c22d5c49074e 100644
+--- a/src/video/wayland/SDL_waylandvideo.h
++++ b/src/video/wayland/SDL_waylandvideo.h
+@@ -64,6 +64,7 @@ typedef struct
+ struct
+ {
+ struct xdg_wm_base *xdg;
++ struct wl_shell *wl;
+ #ifdef HAVE_LIBDECOR_H
+ struct libdecor *libdecor;
+ #endif
+diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c
+index 08df3638c2e795ecdf4cd5f4972bd5d4f866653d..4cb20afbda9aef1edad59b3cf2bd73a7f6e3d289 100644
+--- a/src/video/wayland/SDL_waylandwindow.c
++++ b/src/video/wayland/SDL_waylandwindow.c
+@@ -446,6 +446,20 @@ static void SetFullscreen(SDL_Window *window, struct wl_output *output)
+ } else {
+ xdg_toplevel_unset_fullscreen(wind->shell_surface.xdg.roleobj.toplevel);
+ }
++ } else {
++ if (wind->shell_surface.wl == NULL) {
++ return; /* Can't do anything yet, wait for ShowWindow */
++ }
++
++ wl_surface_commit(wind->surface);
++
++ if (output) {
++ wl_shell_surface_set_fullscreen(wind->shell_surface.wl,
++ WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
++ 0, output);
++ } else {
++ wl_shell_surface_set_toplevel(wind->shell_surface.wl);
++ }
+ }
+ }
+
+@@ -541,6 +555,62 @@ static const struct wl_callback_listener gles_swap_frame_listener = {
+
+ static void Wayland_HandleResize(SDL_Window *window, int width, int height, float scale);
+
++/* On modern desktops, we probably will use the xdg-shell protocol instead
++ of wl_shell, but wl_shell might be useful on older Wayland installs that
++ don't have the newer protocol, or embedded things that don't have a full
++ window manager. */
++
++static void
++handle_ping_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface,
++ uint32_t serial)
++{
++ wl_shell_surface_pong(shell_surface, serial);
++}
++
++static void
++handle_configure_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface,
++ uint32_t edges, int32_t width, int32_t height)
++{
++ SDL_WindowData *wind = (SDL_WindowData *)data;
++ SDL_Window *window = wind->sdlwindow;
++
++ /* wl_shell_surface spec states that this is a suggestion.
++ Ignore if less than or greater than max/min size. */
++
++ if (width == 0 || height == 0) {
++ return;
++ }
++
++ if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
++ if ((window->flags & SDL_WINDOW_RESIZABLE)) {
++ if (window->max_w > 0) {
++ width = SDL_min(width, window->max_w);
++ }
++ width = SDL_max(width, window->min_w);
++
++ if (window->max_h > 0) {
++ height = SDL_min(height, window->max_h);
++ }
++ height = SDL_max(height, window->min_h);
++ } else {
++ return;
++ }
++ }
++
++ Wayland_HandleResize(window, width, height, wind->scale_factor);
++}
++
++static void
++handle_popup_done_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface)
++{
++}
++
++static const struct wl_shell_surface_listener shell_surface_listener_wl = {
++ handle_ping_wl_shell_surface,
++ handle_configure_wl_shell_surface,
++ handle_popup_done_wl_shell_surface
++};
++
+ static void handle_configure_xdg_shell_surface(void *data, struct xdg_surface *xdg, uint32_t serial)
+ {
+ SDL_WindowData *wind = (SDL_WindowData *)data;
+@@ -1374,6 +1444,11 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window)
+ xdg_toplevel_set_app_id(data->shell_surface.xdg.roleobj.toplevel, c->classname);
+ xdg_toplevel_add_listener(data->shell_surface.xdg.roleobj.toplevel, &toplevel_listener_xdg, data);
+ }
++ } else {
++ data->shell_surface.wl = wl_shell_get_shell_surface(c->shell.wl, data->surface);
++ wl_shell_surface_set_class(data->shell_surface.wl, c->classname);
++ wl_shell_surface_set_user_data(data->shell_surface.wl, data);
++ wl_shell_surface_add_listener(data->shell_surface.wl, &shell_surface_listener_wl, data);
+ }
+
+ /* Restore state that was set prior to this call */
+@@ -1549,6 +1624,11 @@ void Wayland_HideWindow(_THIS, SDL_Window *window)
+ xdg_surface_destroy(wind->shell_surface.xdg.surface);
+ wind->shell_surface.xdg.surface = NULL;
+ }
++ } else {
++ if (wind->shell_surface.wl) {
++ wl_shell_surface_destroy(wind->shell_surface.wl);
++ wind->shell_surface.wl = NULL;
++ }
+ }
+
+ /*
+@@ -1829,6 +1909,11 @@ void Wayland_RestoreWindow(_THIS, SDL_Window *window)
+ return; /* Can't do anything yet, wait for ShowWindow */
+ }
+ xdg_toplevel_unset_maximized(wind->shell_surface.xdg.roleobj.toplevel);
++ } else {
++ if (wind->shell_surface.wl == NULL) {
++ return; /* Can't do anything yet, wait for ShowWindow */
++ }
++ wl_shell_surface_set_toplevel(wind->shell_surface.wl);
+ }
+
+ WAYLAND_wl_display_roundtrip(viddata->display);
+@@ -1908,6 +1993,11 @@ void Wayland_MaximizeWindow(_THIS, SDL_Window *window)
+ return; /* Can't do anything yet, wait for ShowWindow */
+ }
+ xdg_toplevel_set_maximized(wind->shell_surface.xdg.roleobj.toplevel);
++ } else {
++ if (wind->shell_surface.wl == NULL) {
++ return; /* Can't do anything yet, wait for ShowWindow */
++ }
++ wl_shell_surface_set_maximized(wind->shell_surface.wl, NULL);
+ }
+
+ WAYLAND_wl_display_roundtrip(viddata->display);
+@@ -2209,6 +2299,11 @@ void Wayland_SetWindowTitle(_THIS, SDL_Window *window)
+ return; /* Can't do anything yet, wait for ShowWindow */
+ }
+ xdg_toplevel_set_title(wind->shell_surface.xdg.roleobj.toplevel, title);
++ } else {
++ if (wind->shell_surface.wl == NULL) {
++ return; /* Can'd do anything yet, wait for ShowWindow */
++ }
++ wl_shell_surface_set_title(wind->shell_surface.wl, title);
+ }
+
+ WAYLAND_wl_display_flush(viddata->display);
+diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h
+index 36600a4d2783e5205d0e1d2faf8422b54e1f7848..0951126949879d863cde175684a3605367428824 100644
+--- a/src/video/wayland/SDL_waylandwindow.h
++++ b/src/video/wayland/SDL_waylandwindow.h
+@@ -67,6 +67,7 @@ typedef struct
+ } roleobj;
+ SDL_bool initial_configure_seen;
+ } xdg;
++ struct wl_shell_surface *wl;
+ } shell_surface;
+ enum
+ {
diff --git a/backends/platform/sdl/sailfish/sdl-patches/0002-wlcancel.patch b/backends/platform/sdl/sailfish/sdl-patches/0002-wlcancel.patch
new file mode 100644
index 0000000000000..9b5cea65170c6
--- /dev/null
+++ b/backends/platform/sdl/sailfish/sdl-patches/0002-wlcancel.patch
@@ -0,0 +1,49 @@
+commit 7dd1cdd4656e0bdbf0f851392f644b2a05c32d64
+Author: Vladimir Serbinenko
+Date: Thu Sep 26 17:19:14 2024 +0300
+
+ Handle wayland touch cancel message
+
+ Suppose host has some three-finger gesture. Then we get the following sequence
+ of events:
+ DOWN-DOWN-DOWN-MOTION-CANCEL
+
+ Note that there is no UP in this sequence. So if we don't handle CANCEL then
+ we end up thinking that fingers are still touching the screen. Ideally we
+ should inform the application that cancel has happened as not to trigger
+ spurious taps but still this is way better than being stuck with phantom
+ finger touch.
+
+diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c
+index 65838f480..236dc3232 100644
+--- a/src/video/wayland/SDL_waylandevents.c
++++ b/src/video/wayland/SDL_waylandevents.c
+@@ -932,6 +932,28 @@ static void touch_handler_frame(void *data, struct wl_touch *touch)
+
+ static void touch_handler_cancel(void *data, struct wl_touch *touch)
+ {
++ struct SDL_WaylandTouchPoint *tp;
++ while ((tp = touch_points.head)) {
++ wl_fixed_t fx = 0, fy = 0;
++ struct wl_surface *surface = NULL;
++ int id = tp->id;
++
++ touch_del(id, &fx, &fy, &surface);
++
++ if (surface) {
++ SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(surface);
++
++ if (window_data) {
++ const double dblx = wl_fixed_to_double(fx) * window_data->pointer_scale_x;
++ const double dbly = wl_fixed_to_double(fy) * window_data->pointer_scale_y;
++ const float x = dblx / window_data->sdlwindow->w;
++ const float y = dbly / window_data->sdlwindow->h;
++
++ SDL_SendTouch((SDL_TouchID)(intptr_t)touch, (SDL_FingerID)id,
++ window_data->sdlwindow, SDL_FALSE, x, y, 1.0f);
++ }
++ }
++ }
+ }
+
+ static const struct wl_touch_listener touch_listener = {
diff --git a/backends/platform/sdl/sdl-window.h b/backends/platform/sdl/sdl-window.h
index 4a48d62df5630..b3e4933874c0d 100644
--- a/backends/platform/sdl/sdl-window.h
+++ b/backends/platform/sdl/sdl-window.h
@@ -153,7 +153,7 @@ class SdlWindow {
* @param flags SDL flags passed to SDL_CreateWindow
* @return true on success, false otherwise
*/
- bool createOrUpdateWindow(int width, int height, uint32 flags);
+ virtual bool createOrUpdateWindow(int width, int height, uint32 flags);
/**
* Destroys the current SDL window.
diff --git a/configure b/configure
index ab53209f3b7f8..4227ab4832042 100755
--- a/configure
+++ b/configure
@@ -906,6 +906,7 @@ Special configuration feature:
ps3 for PlayStation 3
psp2 for PlayStation Vita
psp for PlayStation Portable
+ sailfish for SailfishOS
samsungtv for Samsung TV
switch for Nintendo Switch
tvos for Apple TV (tvOS 9.0+)
@@ -1158,6 +1159,9 @@ Saved environment variables:
AR="$SAVED_AR" AS="$SAVED_AS" ASFLAGS="$SAVED_ASFLAGS" CPPFLAGS="$SAVED_CPPFLAGS" CXX="$SAVED_CXX" CXXFLAGS="$SAVED_CXXFLAGS" DWP="$SAVED_DWP" LD="$SAVED_LD" LDFLAGS="$SAVED_LDFLAGS" PKG_CONFIG_LIBDIR="$SAVED_PKG_CONFIG_LIBDIR" RANLIB="$SAVED_RANLIB" SDL_CONFIG="$SAVED_SDL_CONFIG" STRIP="$SAVED_STRIP" WINDRES="$SAVED_WINDRES" WINDRESFLAGS="$SAVED_WINDRESFLAGS"
EOF
+JPEG_LIBS=-ljpeg
+FLAC_LIBS=-lFLAC
+THEORADEC_LIBS=-ltheoradec
for ac_option in $@; do
case "$ac_option" in
@@ -1393,7 +1397,8 @@ for ac_option in $@; do
--with-flac-prefix=*)
arg=`echo $ac_option | cut -d '=' -f 2`
FLAC_CFLAGS="-I$arg/include"
- FLAC_LIBS="-L$arg/lib"
+ FLAC_LIBS="-L$arg/lib -lFLAC"
+ FLAC_PREFIX="$arg"
;;
--with-mad-prefix=*)
arg=`echo $ac_option | cut -d '=' -f 2`
@@ -1408,7 +1413,8 @@ for ac_option in $@; do
--with-jpeg-prefix=*)
arg=`echo $ac_option | cut -d '=' -f 2`
JPEG_CFLAGS="-I$arg/include"
- JPEG_LIBS="-L$arg/lib"
+ JPEG_LIBS="-L$arg/lib -ljpeg"
+ JPEG_PREFIX="$arg"
;;
--with-png-prefix=*)
arg=`echo $ac_option | cut -d '=' -f 2`
@@ -1423,7 +1429,8 @@ for ac_option in $@; do
--with-theoradec-prefix=*)
arg=`echo $ac_option | cut -d '=' -f 2`
THEORADEC_CFLAGS="-I$arg/include"
- THEORADEC_LIBS="-L$arg/lib"
+ THEORADEC_LIBS="-L$arg/lib -ltheoradec"
+ THEORADEC_PREFIX="$arg"
;;
--with-vpx-prefix=*)
arg=`echo $ac_option | cut -d '=' -f 2`
@@ -1836,6 +1843,23 @@ samsungtv)
_host_os=linux
_host_cpu=arm
_host_alias=arm-linux-gnueabi
+ ;;
+sailfish)
+ _host_os=linux
+ test "x$prefix" = xNONE && prefix=/usr
+ datarootdir='/usr/share/org.scummvm.scummvm'
+ datadir='${datarootdir}/scummvm'
+ docdir='/usr/share/org.scummvm.scummvm/doc/scummvm'
+ if [ -n "$JPEG_PREFIX" ]; then
+ JPEG_LIBS="$JPEG_PREFIX/lib/libjpeg.a"
+ fi
+ if [ -n "$FLAC_PREFIX" ]; then
+ FLAC_LIBS="$FLAC_PREFIX/lib/libFLAC.a"
+ fi
+ if [ -n "$THEORADEC_PREFIX" ]; then
+ THEORADEC_LIBS="$THEORADEC_PREFIX/lib/libtheoradec.a"
+ fi
+
;;
switch)
_host_os=switch
@@ -2169,7 +2193,7 @@ if test -n "$CXX" && test_compiler "$CXX"; then
# Use the compiler specified in CXX
echo $CXX
else
- if test -n "$_host"; then
+ if test -n "$_host" && test "$_host" != sailfish ; then
compilers="$_host_alias-g++ $_host_alias-c++ $_host_alias-clang++ $_host-g++ $_host-c++ $_host-clang++"
else
compilers="g++ c++ clang++"
@@ -3907,6 +3931,14 @@ if test -n "$_host"; then
_seq_midi=no
_timidity=no
;;
+ sailfish)
+ append_var DEFINES "-DSAILFISH"
+ append_var LDFLAGS "-Wl,-rpath,/usr/share/org.scummvm.scummvm/lib"
+ _vkeybd=yes
+ HOSTEXEPRE=org.scummvm.
+ _backend="sailfish"
+ add_line_to_config_mk 'SAILFISH = 1'
+ ;;
samsungtv)
append_var DEFINES "-DSAMSUNGTV"
append_var DEFINES "-DDISABLE_COMMAND_LINE"
@@ -4050,7 +4082,7 @@ case $_backend in
append_var DEFINES "-DUSE_NULL_DRIVER"
_text_console=yes
;;
- opendingux | miyoo | miyoomini)
+ opendingux | miyoo | miyoomini | sailfish)
_sdlconfig=sdl-config
_sdl=auto
append_var MODULES "backends/platform/sdl"
@@ -4089,7 +4121,7 @@ case $_backend in
append_var LDFLAGS "-fpic"
_sdl=auto
;;
- sdl)
+ sdl | sailfish)
_sdl=auto
;;
switch)
@@ -4461,7 +4493,7 @@ fi
# Enable 16bit support only for backends which support it
#
case $_backend in
- 3ds | android | dingux | dc | ds | ios7 | kolibrios | maemo | null | opendingux | miyoomini | miyoo | openpandora | psp | psp2 | samsungtv | sdl | switch | wii)
+ 3ds | android | dingux | dc | ds | ios7 | kolibrios | maemo | null | opendingux | miyoomini | miyoo | openpandora | psp | psp2 | sailfish | samsungtv | sdl | switch | wii)
if test "$_16bit" = auto ; then
_16bit=yes
else
@@ -5208,14 +5240,14 @@ int main(void) {
EOF
if test "$_ogg" = yes ; then
cc_check $FLAC_CFLAGS $FLAC_LIBS $OGG_CFLAGS $OGG_LIBS \
- -lFLAC -logg && _flac=yes
+ -logg && _flac=yes
else
cc_check $FLAC_CFLAGS $FLAC_LIBS \
- -lFLAC && _flac=yes
+ && _flac=yes
fi
fi
if test "$_flac" = yes ; then
- append_var LIBS "$FLAC_LIBS -lFLAC"
+ append_var LIBS "$FLAC_LIBS"
append_var INCLUDES "$FLAC_CFLAGS"
fi
define_in_config_if_yes "$_flac" 'USE_FLAC'
@@ -5282,10 +5314,10 @@ int main(void) {
return 0;
}
EOF
- cc_check $JPEG_CFLAGS $JPEG_LIBS -ljpeg && _jpeg=yes
+ cc_check $JPEG_CFLAGS $JPEG_LIBS && _jpeg=yes
fi
if test "$_jpeg" = yes ; then
- append_var LIBS "$JPEG_LIBS -ljpeg"
+ append_var LIBS "$JPEG_LIBS"
append_var INCLUDES "$JPEG_CFLAGS"
fi
define_in_config_if_yes "$_jpeg" 'USE_JPEG'
@@ -5367,10 +5399,10 @@ if test "$_theoradec" = auto ; then
#include
int main(void) { th_ycbcr_buffer yuv; th_decode_ycbcr_out(NULL, yuv); }
EOF
- cc_check $THEORADEC_CFLAGS $THEORADEC_LIBS -ltheoradec && _theoradec=yes
+ cc_check $THEORADEC_CFLAGS $THEORADEC_LIBS && _theoradec=yes
fi
if test "$_theoradec" = yes ; then
- append_var LIBS "$THEORADEC_LIBS -ltheoradec"
+ append_var LIBS "$THEORADEC_LIBS"
append_var INCLUDES "$THEORADEC_CFLAGS"
fi
define_in_config_if_yes "$_theoradec" 'USE_THEORADEC'
@@ -6337,6 +6369,12 @@ if test "$_opengl_mode" != none ; then
;;
esac
;;
+ sailfish)
+ _opengl_mode=gles2
+ _opengl_glad=yes
+ OPENGL_CFLAGS=`$_pkgconfig --cflags glesv2 egl`
+ OPENGL_LIBS=`$_pkgconfig --libs glesv2 egl`
+ ;;
switch)
_opengl_mode=gles2
_opengl_glad=yes
@@ -6728,7 +6766,7 @@ echocheck "ImGui"
if test "$_imgui" != no ; then
if test "$_freetype2" = yes ; then
case $_backend in
- sdl)
+ sdl | sailfish)
if test "$_sdlMajorVersionNumber" -ge 2 ; then
cat > $TMPC << EOF
#include "SDL.h"
diff --git a/dists/sailfish/108x108.png b/dists/sailfish/108x108.png
new file mode 100644
index 0000000000000..8627119b8df91
Binary files /dev/null and b/dists/sailfish/108x108.png differ
diff --git a/dists/sailfish/128x128.png b/dists/sailfish/128x128.png
new file mode 100644
index 0000000000000..7ccd61efd1a23
Binary files /dev/null and b/dists/sailfish/128x128.png differ
diff --git a/dists/sailfish/172x172.png b/dists/sailfish/172x172.png
new file mode 100644
index 0000000000000..a3ea780df1b10
Binary files /dev/null and b/dists/sailfish/172x172.png differ
diff --git a/dists/sailfish/86x86.png b/dists/sailfish/86x86.png
new file mode 100644
index 0000000000000..b7dd7e0390315
Binary files /dev/null and b/dists/sailfish/86x86.png differ
diff --git a/dists/sailfish/org.scummvm.scummvm.desktop b/dists/sailfish/org.scummvm.scummvm.desktop
new file mode 100644
index 0000000000000..9d4f4f03c5259
--- /dev/null
+++ b/dists/sailfish/org.scummvm.scummvm.desktop
@@ -0,0 +1,24 @@
+[Desktop Entry]
+Name=ScummVM
+Comment=Interpreter for numerous adventure games and RPGs
+Comment[pl]=Interpreter graficznych gier przygodowych
+Comment[sv]=Tolk för flertalet äventyrsspel
+Comment[he]=פרשן למספר משחקי הרפתקאות
+Comment[de]=Interpreter für zahlreiche Abenteuerspiele und RPGs
+Comment[es]=Intérprete para varias aventuras gráficas
+Comment[ca]=Intèrpret per diverses aventures gràfiques
+Exec=/usr/bin/org.scummvm.scummvm
+Icon=org.scummvm.scummvm
+Type=Application
+Categories=Game;AdventureGame;
+X-Nemo-Application-Type=no-invoker
+X-Desktop-File-Install-Version=0.26
+
+[X-Application]
+Permissions=UserDirs;RemovableMedia;Internet;Audio
+OrganizationName=org.scummvm
+ApplicationName=scummvm
+
+[X-Aurora-Application]
+Orientation=Landscape;Portrait
+IconMode=Crop