diff --git a/app/build.gradle b/app/build.gradle index 1b6f5ac..a7bee20 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,14 +2,13 @@ apply plugin: 'com.android.application' android { compileSdk 30 - buildToolsVersion '30.0.3' defaultConfig { applicationId 'com.winlator' minSdkVersion 26 targetSdkVersion 28 - versionCode 13 - versionName "6.1" + versionCode 16 + versionName "7.1" } buildTypes { diff --git a/app/src/main/assets/box86_64/box64-0.2.6.tzst b/app/src/main/assets/box86_64/box64-0.2.6.tzst deleted file mode 100644 index 1dcfb3a..0000000 Binary files a/app/src/main/assets/box86_64/box64-0.2.6.tzst and /dev/null differ diff --git a/app/src/main/assets/box86_64/box64-0.2.7.tzst b/app/src/main/assets/box86_64/box64-0.2.7.tzst deleted file mode 100644 index ca9e475..0000000 Binary files a/app/src/main/assets/box86_64/box64-0.2.7.tzst and /dev/null differ diff --git a/app/src/main/assets/box86_64/box64-0.2.8.tzst b/app/src/main/assets/box86_64/box64-0.2.8.tzst new file mode 100644 index 0000000..19447a9 Binary files /dev/null and b/app/src/main/assets/box86_64/box64-0.2.8.tzst differ diff --git a/app/src/main/assets/box86_64/box64-0.2.9.tzst b/app/src/main/assets/box86_64/box64-0.2.9.tzst new file mode 100644 index 0000000..fc2074f Binary files /dev/null and b/app/src/main/assets/box86_64/box64-0.2.9.tzst differ diff --git a/app/src/main/assets/box86_64/box86-0.3.0.tzst b/app/src/main/assets/box86_64/box86-0.3.0.tzst deleted file mode 100644 index 10e42a3..0000000 Binary files a/app/src/main/assets/box86_64/box86-0.3.0.tzst and /dev/null differ diff --git a/app/src/main/assets/box86_64/box86-0.3.2.tzst b/app/src/main/assets/box86_64/box86-0.3.2.tzst new file mode 100644 index 0000000..66b45ce Binary files /dev/null and b/app/src/main/assets/box86_64/box86-0.3.2.tzst differ diff --git a/app/src/main/assets/box86_64/box86-0.3.5.tzst b/app/src/main/assets/box86_64/box86-0.3.5.tzst deleted file mode 100644 index 241263f..0000000 Binary files a/app/src/main/assets/box86_64/box86-0.3.5.tzst and /dev/null differ diff --git a/app/src/main/assets/box86_64/box86-0.3.7.tzst b/app/src/main/assets/box86_64/box86-0.3.7.tzst new file mode 100644 index 0000000..66c4ee3 Binary files /dev/null and b/app/src/main/assets/box86_64/box86-0.3.7.tzst differ diff --git a/app/src/main/assets/box86_env_vars.json b/app/src/main/assets/box86_env_vars.json index 1c988e1..315104b 100644 --- a/app/src/main/assets/box86_env_vars.json +++ b/app/src/main/assets/box86_env_vars.json @@ -3,8 +3,9 @@ {"name" : "BOX86_DYNAREC_FASTNAN", "values" : ["0", "1"], "toggleSwitch" : true, "defaultValue" : "1"}, {"name" : "BOX86_DYNAREC_FASTROUND", "values" : ["0", "1"], "toggleSwitch" : true, "defaultValue" : "1"}, {"name" : "BOX86_DYNAREC_X87DOUBLE", "values" : ["0", "1"], "toggleSwitch" : true, "defaultValue" : "0"}, - {"name" : "BOX86_DYNAREC_BIGBLOCK", "values" : ["0", "1", "2"], "defaultValue" : "1"}, + {"name" : "BOX86_DYNAREC_BIGBLOCK", "values" : ["0", "1", "2", "3"], "defaultValue" : "1"}, {"name" : "BOX86_DYNAREC_STRONGMEM", "values" : ["0", "1", "2", "3"], "defaultValue" : "0"}, {"name" : "BOX86_DYNAREC_FORWARD", "values" : ["0", "128", "256", "512", "1024"], "defaultValue" : "128"}, + {"name" : "BOX86_DYNAREC_CALLRET", "values" : ["0", "1"], "toggleSwitch" : true, "defaultValue" : "1"}, {"name" : "BOX86_DYNAREC_WAIT", "values" : ["0", "1"], "toggleSwitch" : true, "defaultValue" : "1"} ] \ No newline at end of file diff --git a/app/src/main/assets/common_dlls.json b/app/src/main/assets/common_dlls.json index 2fc89ad..0634184 100644 --- a/app/src/main/assets/common_dlls.json +++ b/app/src/main/assets/common_dlls.json @@ -1 +1 @@ -{"system32":["winedevice.exe","explorer.exe","iexplore.exe","notepad.exe","msxml.dll","msxml2.dll","msxml3.dll","msxml4.dll","msxml6.dll","shdocvw.dll","acledit.dll","aclui.dll","activeds.dll","activeds.tlb","actxprxy.dll","adsldp.dll","adsldpc.dll","advapi32.dll","advpack.dll","amsi.dll","amstream.dll","apisetschema.dll","apphelp.dll","appwiz.cpl","arp.exe","atl.dll","atl100.dll","atl110.dll","atl80.dll","atl90.dll","atlthunk.dll","atmlib.dll","attrib.exe","authz.dll","avicap32.dll","avifil32.dll","avrt.dll","bcrypt.dll","bluetoothapis.dll","browseui.dll","bthprops.cpl","cabarc.exe","cabinet.dll","cacls.exe","capi2032.dll","cards.dll","cdosys.dll","certutil.exe","cfgmgr32.dll","chcp.com","clock.exe","clusapi.dll","cmd.exe","combase.dll","comcat.dll","comctl32.dll","comdlg32.dll","compstui.dll","comsvcs.dll","concrt140.dll","conhost.exe","connect.dll","control.exe","credui.dll","crtdll.dll","crypt32.dll","cryptdlg.dll","cryptdll.dll","cryptext.dll","cryptnet.dll","cryptowinrt.dll","cryptsp.dll","cryptui.dll","cscript.exe","ctapi32.dll","ctl3d32.dll","d2d1.dll","d3d10.dll","d3d10core.dll","d3d10_1.dll","d3d11.dll","d3d12.dll","d3d8.dll","d3d8thk.dll","d3d9.dll","d3dcompiler_33.dll","d3dcompiler_34.dll","d3dcompiler_35.dll","d3dcompiler_36.dll","d3dcompiler_37.dll","d3dcompiler_38.dll","d3dcompiler_39.dll","d3dcompiler_40.dll","d3dcompiler_41.dll","d3dcompiler_42.dll","d3dcompiler_43.dll","d3dcompiler_46.dll","d3dcompiler_47.dll","d3dim.dll","d3dim700.dll","d3drm.dll","d3dx10_33.dll","d3dx10_34.dll","d3dx10_35.dll","d3dx10_36.dll","d3dx10_37.dll","d3dx10_38.dll","d3dx10_39.dll","d3dx10_40.dll","d3dx10_41.dll","d3dx10_42.dll","d3dx10_43.dll","d3dx11_42.dll","d3dx11_43.dll","d3dx9_24.dll","d3dx9_25.dll","d3dx9_26.dll","d3dx9_27.dll","d3dx9_28.dll","d3dx9_29.dll","d3dx9_30.dll","d3dx9_31.dll","d3dx9_32.dll","d3dx9_33.dll","d3dx9_34.dll","d3dx9_35.dll","d3dx9_36.dll","d3dx9_37.dll","d3dx9_38.dll","d3dx9_39.dll","d3dx9_40.dll","d3dx9_41.dll","d3dx9_42.dll","d3dx9_43.dll","d3dxof.dll","davclnt.dll","dbgeng.dll","dbghelp.dll","dciman32.dll","dcomp.dll","ddraw.dll","ddrawex.dll","devenum.dll","dhcpcsvc.dll","dhcpcsvc6.dll","dhtmled.ocx","difxapi.dll","dinput.dll","dinput8.dll","directmanipulation.dll","dism.exe","dispex.dll","dllhost.exe","dmband.dll","dmcompos.dll","dmime.dll","dmloader.dll","dmscript.dll","dmstyle.dll","dmsynth.dll","dmusic.dll","dmusic32.dll","dnsapi.dll","dplay.dll","dplaysvr.exe","dplayx.dll","dpnaddr.dll","dpnet.dll","dpnhpast.dll","dpnhupnp.dll","dpnlobby.dll","dpnsvr.exe","dpvoice.dll","dpvsetup.exe","dpwsockx.dll","drmclien.dll","dsdmo.dll","dsound.dll","dsquery.dll","dssenh.dll","dsuiext.dll","dswave.dll","dwmapi.dll","dwrite.dll","dx8vb.dll","dxdiag.exe","dxdiagn.dll","dxgi.dll","esent.dll","expand.exe","fc.exe","glu32.dll","hnetcfg.dll","icmp.dll","ieproxy.dll","initpki.dll","inkobj.dll","joy.cpl","jsproxy.dll","kerberos.dll","lz32.dll","mciavi32.dll","mf.dll","mfmediaengine.dll","mfreadwrite.dll","mgmtapi.dll","mlang.dll","mprapi.dll","msasn1.dll","msctf.dll","msgsm32.acm","msimtf.dll","msinfo32.exe","mspatcha.dll","msrle32.dll","msv1_0.dll","msvcp140.dll","msvcp140_1.dll","msvcr71.dll","msvcrt20.dll","msvcrtd.dll","msvfw32.dll","net.exe","ntdsapi.dll","odbc32.dll","ole32.dll","oleacc.dll","oleview.exe","opengl32.dll","pdh.dll","prntvpt.dll","psapi.dll","qasf.dll","reg.exe","regini.exe","rpcrt4.dll","rpcss.exe","rsaenh.dll","sc.exe","scrobj.dll","scrrun.dll","secur32.dll","sensapi.dll","serialui.dll","sfc_os.dll","slbcsp.dll","srvcli.dll","systeminfo.exe","tbs.dll","tdh.dll","ucrtbase.dll","uianimation.dll","uiribbon.dll","vcomp100.dll","vcomp140.dll","version.dll","wdscore.dll","websocket.dll","wevtapi.dll","win32u.dll","windows.networking.dll","wineboot.exe","winecfg.exe","winedbg.exe","winefile.exe","winemapi.dll","winemenubuilder.exe","winmm.dll","winusb.dll","winver.exe","wlanapi.dll","wlanui.dll","wmasf.dll","wow64.dll","wow64win.dll","wpcap.dll","wsdapi.dll","wshom.ocx","wsnmp32.dll","wuapi.dll","x3daudio1_0.dll","x3daudio1_4.dll","x3daudio1_6.dll","xactengine2_0.dll","xactengine2_4.dll","xactengine2_9.dll","xapofx1_2.dll","dxtrans.dll","dxva2.dll","explorerframe.dll","extrac32.exe","findstr.exe","fwpuclnt.dll","gamingtcui.dll","gpkcsp.dll","hhctrl.ocx","hlink.dll","ieframe.dll","imaadp32.acm","imagehlp.dll","ipconfig.exe","iphlpapi.dll","iprop.dll","irprops.cpl","kernel32.dll","localspl.dll","mapistub.dll","mcicda.dll","mciqtz32.dll","mciseq.dll","mferror.dll","mpr.dll","msctfmonitor.dll","msdelta.dll","msg711.acm","msident.dll","msisip.dll","msports.dll","msscript.ocx","mssip32.dll","msvcm80.dll","msvcp140_2.dll","msvcp140_atomic_wait.dll","msvcp60.dll","msvcp90.dll","msvcp_win.dll","msvcr100.dll","msvcr80.dll","msvcr90.dll","msvidc32.dll","mswsock.dll","ncrypt.dll","netprofm.dll","netstat.exe","normaliz.dll","ntprint.dll","odbcbcp.dll","odbccp32.dll","oleaut32.dll","olesvr32.dll","pidgen.dll","ping.exe","printui.dll","qcap.dll","qmgrprxy.dll","qwave.dll","rasapi32.dll","regapi.dll","riched20.dll","robocopy.exe","rsabase.dll","rtworkq.dll","sas.dll","scarddlg.dll","sdbinst.exe","secedit.exe","shdoclc.dll","shell32.dll","shlwapi.dll","shutdown.exe","start.exe","strmdll.dll","tapi32.dll","taskmgr.exe","taskschd.dll","twain_32.dll","unicows.dll","urlmon.dll","usp10.dll","utildll.dll","vbscript.dll","vcomp110.dll","vcomp120.dll","vcruntime140.dll","virtdisk.dll","wiaservc.dll","windows.globalization.dll","windows.media.devices.dll","windowscodecsext.dll","wined3d.dll","winepath.exe","xactengine3_1.dll","xactengine3_4.dll","xactengine3_6.dll","xapofx1_3.dll","xaudio2_5.dll","xcopy.exe","xinput1_4.dll","eject.exe","evr.dll","faultrep.dll","find.exe","fntcache.dll","fontsub.dll","hid.dll","hostname.exe","httpapi.dll","icacls.exe","iccvid.dll","icinfo.exe","imm32.dll","loadperf.dll","localui.dll","mapi32.dll","mf3216.dll","midimap.dll","msacm32.dll","mscms.dll","mscoree.dll","msdmo.dll","msdrm.dll","msftedit.dll","mshtml.tlb","msi.dll","msidb.exe","msiexec.exe","msls31.dll","msnet32.dll","msvcm90.dll","msvcp120_app.dll","msvcp70.dll","msvcp71.dll","msvcr110.dll","msvcr120.dll","msvcr120_app.dll","msvcrt40.dll","mtxdm.dll","nddeapi.dll","netapi32.dll","netutils.dll","newdev.dll","ninput.dll","ntdll.dll","ntoskrnl.exe","odbccu32.dll","olecli32.dll","oledlg.dll","olethk32.dll","plugplay.exe","propsys.dll","qedit.dll","rasdlg.dll","regsvr32.exe","rtutils.dll","samlib.dll","schannel.dll","schedsvc.dll","sechost.dll","setupapi.dll","setx.exe","sfc.dll","slc.dll","spoolss.dll","sppc.dll","sspicli.dll","sti.dll","svrapi.dll","sxs.dll","taskkill.exe","tasklist.exe","uninstaller.exe","updspapi.dll","url.dll","user32.dll","userenv.dll","vcomp.dll","vcruntime140_1.dll","vdmdbg.dll","webservices.dll","wevtsvc.dll","wevtutil.exe","wimgapi.dll","windows.gaming.input.dll","windows.media.dll","windowscodecs.dll","winebrowser.exe","wineconsole.exe","winemsibuilder.exe","winepulse.drv","winex11.drv","winhttp.dll","winnls32.dll","wintrust.dll","wmi.dll","wmvcore.dll","wow64cpu.dll","write.exe","wscript.exe","wsock32.dll","x3daudio1_3.dll","xactengine3_0.dll","feclient.dll","fltlib.dll","fsutil.exe","gameux.dll","gdi32.dll","gdiplus.dll","hal.dll","ia2comproxy.dll","inetcomm.dll","inetcpl.cpl","inetmib1.dll","infosoft.dll","inseng.dll","itircl.dll","itss.dll","jscript.dll","kernelbase.dll","ksproxy.ax","ksuser.dll","ktmw32.dll","l3codeca.acm","lodctr.exe","mciwave.dll","mfplat.dll","mfplay.dll","mfsrcsnk.dll","mmcndmgr.dll","mmdevapi.dll","mp3dmod.dll","msacm32.drv","msadp32.acm","mscat32.dll","msctfp.dll","mshta.exe","mshtml.dll","msimg32.dll","msimsg.dll","msisys.ocx","mssign32.dll","mstask.dll","msvcirt.dll","msvcp100.dll","msvcp110.dll","msvcp120.dll","msvcp80.dll","msvcr70.dll","msvcrt.dll","netcfgx.dll","netsh.exe","npptools.dll","nsi.dll","objsel.dll","olepro32.dll","opcservices.dll","opencl.dll","packager.dll","photometadatahandler.dll","powrprof.dll","progman.exe","pstorec.dll","pwrshplugin.dll","qdvd.dll","qmgr.dll","quartz.dll","query.dll","resutils.dll","riched32.dll","rstrtmgr.dll","rundll32.exe","sccbase.dll","schtasks.exe","security.dll","services.exe","shcore.dll","shfolder.dll","snmpapi.dll","softpub.dll","spoolsv.exe","srclient.dll","stdole2.tlb","stdole32.tlb","subst.exe","svchost.exe","t2embed.dll","termsv.exe","threadpoolwinrt.dll","traffic.dll","tzres.dll","uiautomationcore.dll","unlodctr.exe","uxtheme.dll","vcomp90.dll","vga.dll","view.exe","vssapi.dll","vulkan-1.dll","wer.dll","where.exe","whoami.exe","windows.devices.enumeration.dll","winealsa.drv","winspool.drv","wmp.dll","ws2_32.dll","xaudio2_7.dll","wintypes.dll","wofutil.dll","wuauserv.exe","x3daudio1_1.dll","xactengine3_5.dll","xaudio2_3.dll","windows.gaming.ui.gamebar.dll","windows.media.speech.dll","winegstreamer.dll","winemine.exe","winevulkan.dll","wing32.dll","winhlp32.exe","xapofx1_5.dll","xaudio2_1.dll","xaudio2_2.dll","xaudio2_4.dll","xaudio2_9.dll","wnaspi32.dll","x3daudio1_5.dll","xinput1_2.dll","xmllite.dll","wldap32.dll","wmphoto.dll","wpc.dll","x3daudio1_7.dll","xaudio2_0.dll","wuaueng.dll","wusa.exe","x3daudio1_2.dll","xinput9_1_0.dll","xinputuap.dll","xpsprint.dll","xpssvcs.dll","xactengine3_3.dll","wtsapi32.dll","xactengine3_7.dll","xolehlp.dll","xaudio2_6.dll","xaudio2_8.dll","xinput1_1.dll","wininet.dll","winmgmt.exe","winscard.dll","winsta.dll","wintab32.dll","xactengine2_7.dll","xactengine3_2.dll","xapofx1_4.dll","xapofx1_1.dll","xinput1_3.dll"],"syswow64":["start.exe","winhlp32.exe","stdole2.tlb","iexplore.exe","msxml.dll","msxml2.dll","msxml3.dll","msxml4.dll","msxml6.dll","shdocvw.dll","acledit.dll","aclui.dll","activeds.dll","activeds.tlb","actxprxy.dll","adsldp.dll","adsldpc.dll","advapi32.dll","advpack.dll","amsi.dll","amstream.dll","apisetschema.dll","apphelp.dll","appwiz.cpl","arp.exe","atl.dll","atl100.dll","atl110.dll","atl80.dll","atl90.dll","atlthunk.dll","atmlib.dll","attrib.exe","authz.dll","avicap32.dll","avifil32.dll","avrt.dll","bcrypt.dll","bluetoothapis.dll","browseui.dll","bthprops.cpl","cabarc.exe","cabinet.dll","cacls.exe","capi2032.dll","cards.dll","cdosys.dll","certutil.exe","cfgmgr32.dll","chcp.com","clock.exe","clusapi.dll","cmd.exe","combase.dll","comcat.dll","comctl32.dll","comdlg32.dll","compstui.dll","comsvcs.dll","concrt140.dll","connect.dll","control.exe","credui.dll","crtdll.dll","crypt32.dll","cryptdlg.dll","cryptdll.dll","cryptext.dll","cryptnet.dll","cryptowinrt.dll","cryptsp.dll","cryptui.dll","cscript.exe","ctapi32.dll","ctl3d32.dll","d2d1.dll","d3d10.dll","d3d10core.dll","d3d10_1.dll","d3d11.dll","d3d12.dll","d3d8.dll","d3d8thk.dll","d3d9.dll","d3dcompiler_33.dll","d3dcompiler_34.dll","d3dcompiler_35.dll","d3dcompiler_36.dll","d3dcompiler_37.dll","d3dcompiler_38.dll","d3dcompiler_39.dll","d3dcompiler_40.dll","d3dcompiler_41.dll","d3dcompiler_42.dll","d3dcompiler_43.dll","d3dcompiler_46.dll","d3dcompiler_47.dll","d3dim.dll","d3dim700.dll","d3drm.dll","d3dx10_33.dll","d3dx10_34.dll","d3dx10_35.dll","d3dx10_36.dll","d3dx10_37.dll","d3dx10_38.dll","d3dx10_39.dll","d3dx10_40.dll","d3dx10_41.dll","d3dx10_42.dll","d3dx10_43.dll","d3dx11_42.dll","d3dx11_43.dll","d3dx9_24.dll","d3dx9_25.dll","d3dx9_26.dll","d3dx9_27.dll","d3dx9_28.dll","d3dx9_29.dll","d3dx9_30.dll","d3dx9_31.dll","d3dx9_32.dll","d3dx9_33.dll","d3dx9_34.dll","d3dx9_35.dll","d3dx9_36.dll","d3dx9_37.dll","d3dx9_38.dll","d3dx9_39.dll","d3dx9_40.dll","d3dx9_41.dll","d3dx9_42.dll","d3dx9_43.dll","d3dxof.dll","davclnt.dll","dbgeng.dll","dbghelp.dll","dciman32.dll","dcomp.dll","ddraw.dll","ddrawex.dll","devenum.dll","dhcpcsvc.dll","dhcpcsvc6.dll","dhtmled.ocx","difxapi.dll","dinput.dll","dinput8.dll","directmanipulation.dll","dism.exe","dispex.dll","dllhost.exe","dmband.dll","dmcompos.dll","dmime.dll","dmloader.dll","dmscript.dll","dmstyle.dll","dmsynth.dll","dmusic.dll","dmusic32.dll","dnsapi.dll","dplay.dll","dplaysvr.exe","dplayx.dll","dpnaddr.dll","dpnet.dll","dpnhpast.dll","dpnhupnp.dll","dpnlobby.dll","dpnsvr.exe","dpvoice.dll","dpvsetup.exe","dpwsockx.dll","drmclien.dll","dsdmo.dll","dsound.dll","dsquery.dll","dssenh.dll","dsuiext.dll","dswave.dll","dwmapi.dll","dwrite.dll","dx8vb.dll","dxdiag.exe","dxdiagn.dll","dxgi.dll","dxtrans.dll","dxva2.dll","eject.exe","esent.dll","explorerframe.dll","fwpuclnt.dll","gameux.dll","gdi32.dll","gdiplus.dll","gpkcsp.dll","hid.dll","hlink.dll","httpapi.dll","imaadp32.acm","imm32.dll","inetcpl.cpl","inetmib1.dll","inkobj.dll","jsproxy.dll","kernel32.dll","localui.dll","lodctr.exe","lz32.dll","mapistub.dll","mciwave.dll","mferror.dll","mfplay.dll","mmdevapi.dll","mp3dmod.dll","mpr.dll","msacm32.dll","msctfmonitor.dll","msctfp.dll","msdelta.dll","msg711.acm","msi.dll","msident.dll","msimg32.dll","msinfo32.exe","mspatcha.dll","msscript.ocx","msvcp100.dll","msvcp140.dll","msvcp60.dll","msvcp70.dll","msvcp_win.dll","msvcr120.dll","msvcrt.dll","msvcrt20.dll","msvcrtd.dll","netapi32.dll","newdev.dll","ntdsapi.dll","odbc32.dll","oleaut32.dll","opengl32.dll","pidgen.dll","ping.exe","progman.exe","psapi.dll","qdvd.dll","qmgr.dll","regapi.dll","rsabase.dll","rtutils.dll","sc.exe","schedsvc.dll","scrobj.dll","sdbinst.exe","secedit.exe","setupapi.dll","shcore.dll","shdoclc.dll","shutdown.exe","slc.dll","softpub.dll","stdole32.tlb","sti.dll","svrapi.dll","tapi32.dll","taskschd.dll","uianimation.dll","uiautomationcore.dll","unicows.dll","uninstaller.exe","unlodctr.exe","updspapi.dll","userenv.dll","uxtheme.dll","vcomp120.dll","vcomp90.dll","vga.dll","webservices.dll","wevtsvc.dll","where.exe","wiaservc.dll","windows.gaming.ui.gamebar.dll","windows.media.devices.dll","windows.media.speech.dll","winealsa.drv","winebrowser.exe","wineconsole.exe","wined3d.dll","winemapi.dll","winmgmt.exe","winmm.dll","winscard.dll","winspool.drv","wintab32.dll","winver.exe","expand.exe","explorer.exe","extrac32.exe","fc.exe","feclient.dll","fsutil.exe","hal.dll","hhctrl.ocx","icmp.dll","ieframe.dll","ieproxy.dll","inetcomm.dll","inseng.dll","ipconfig.exe","iprop.dll","kernelbase.dll","ktmw32.dll","localspl.dll","mcicda.dll","mlang.dll","mmcndmgr.dll","mscms.dll","msdmo.dll","msftedit.dll","mshtml.tlb","msiexec.exe","msimsg.dll","msisys.ocx","msnet32.dll","msports.dll","mssip32.dll","msvcp110.dll","msvcp140_1.dll","msvcp140_2.dll","msvcp80.dll","msvcr100.dll","msvcr110.dll","msvcr71.dll","msvcr80.dll","net.exe","netprofm.dll","netsh.exe","netutils.dll","ninput.dll","npptools.dll","nsi.dll","ntoskrnl.exe","objsel.dll","odbcbcp.dll","ole32.dll","olesvr32.dll","olethk32.dll","pdh.dll","propsys.dll","pstorec.dll","query.dll","rasapi32.dll","riched32.dll","robocopy.exe","rpcrt4.dll","rpcss.exe","rstrtmgr.dll","scarddlg.dll","sccbase.dll","shfolder.dll","slbcsp.dll","srvcli.dll","sspicli.dll","strmdll.dll","subst.exe","taskmgr.exe","termsv.exe","tzres.dll","utildll.dll","vcomp.dll","vcomp100.dll","vcomp110.dll","vdmdbg.dll","version.dll","virtdisk.dll","vulkan-1.dll","wevtutil.exe","wimgapi.dll","win32u.dll","windows.gaming.input.dll","windows.media.dll","windowscodecs.dll","winedbg.exe","winedevice.exe","winefile.exe","winex11.drv","winhttp.dll","wmasf.dll","wmvcore.dll","write.exe","wscript.exe","wsnmp32.dll","wusa.exe","evr.dll","findstr.exe","fltlib.dll","hnetcfg.dll","hostname.exe","ia2comproxy.dll","icacls.exe","iccvid.dll","icinfo.exe","initpki.dll","itircl.dll","itss.dll","joy.cpl","jscript.dll","ksuser.dll","mapi32.dll","mciavi32.dll","mciqtz32.dll","mgmtapi.dll","midimap.dll","mprapi.dll","msacm32.drv","msadp32.acm","msasn1.dll","mscat32.dll","msdrm.dll","msgsm32.acm","mshta.exe","msimtf.dll","msls31.dll","mstask.dll","msvcirt.dll","msvcm80.dll","msvcm90.dll","msvcp90.dll","msvcr90.dll","msvcrt40.dll","msvfw32.dll","msvidc32.dll","mswsock.dll","nddeapi.dll","netcfgx.dll","netstat.exe","odbccp32.dll","odbccu32.dll","oleacc.dll","olecli32.dll","oledlg.dll","oleview.exe","opcservices.dll","opencl.dll","packager.dll","prntvpt.dll","qedit.dll","qmgrprxy.dll","qwave.dll","reg.exe","regedit.exe","regsvr32.exe","resutils.dll","riched20.dll","rsaenh.dll","rundll32.exe","samlib.dll","sas.dll","schtasks.exe","scrrun.dll","sechost.dll","secur32.dll","security.dll","sensapi.dll","serialui.dll","shlwapi.dll","sppc.dll","srclient.dll","svchost.exe","t2embed.dll","taskkill.exe","threadpoolwinrt.dll","ucrtbase.dll","uiribbon.dll","usp10.dll","vbscript.dll","vcomp140.dll","vcruntime140.dll","view.exe","vssapi.dll","wer.dll","whoami.exe","windows.devices.enumeration.dll","windows.globalization.dll","wineboot.exe","winecfg.exe","winemsibuilder.exe","wing32.dll","wintypes.dll","winusb.dll","faultrep.dll","find.exe","fntcache.dll","fontsub.dll","gamingtcui.dll","glu32.dll","hh.exe","imagehlp.dll","infosoft.dll","iphlpapi.dll","irprops.cpl","kerberos.dll","ksproxy.ax","l3codeca.acm","loadperf.dll","mciseq.dll","mf.dll","mf3216.dll","mfmediaengine.dll","mfplat.dll","mfreadwrite.dll","mfsrcsnk.dll","mscoree.dll","msctf.dll","mshtml.dll","msidb.exe","msisip.dll","msrle32.dll","mssign32.dll","msv1_0.dll","msvcp120.dll","msvcp120_app.dll","msvcp140_atomic_wait.dll","msvcp71.dll","msvcr120_app.dll","msvcr70.dll","mtxdm.dll","ncrypt.dll","normaliz.dll","notepad.exe","ntdll.dll","ntprint.dll","olepro32.dll","photometadatahandler.dll","plugplay.exe","powrprof.dll","printui.dll","pwrshplugin.dll","qasf.dll","qcap.dll","quartz.dll","rasdlg.dll","regini.exe","rtworkq.dll","schannel.dll","setx.exe","sfc.dll","sfc_os.dll","shell32.dll","snmpapi.dll","spoolss.dll","sxs.dll","systeminfo.exe","tasklist.exe","tbs.dll","tdh.dll","traffic.dll","url.dll","urlmon.dll","user32.dll","vcruntime140_1.dll","wdscore.dll","websocket.dll","wevtapi.dll","windows.networking.dll","windowscodecsext.dll","winegstreamer.dll","winemine.exe","winepath.exe","winepulse.drv","winevulkan.dll","wininet.dll","winnls32.dll","winsta.dll","wintrust.dll","wlanui.dll","wmi.dll","wmphoto.dll","wnaspi32.dll","wpc.dll","wpcap.dll","x3daudio1_0.dll","x3daudio1_1.dll","x3daudio1_3.dll","xactengine3_1.dll","xactengine3_3.dll","wlanapi.dll","ws2_32.dll","wshom.ocx","wuauserv.exe","xactengine3_7.dll","xapofx1_2.dll","xaudio2_4.dll","x3daudio1_2.dll","x3daudio1_6.dll","xactengine2_0.dll","x3daudio1_4.dll","x3daudio1_7.dll","xactengine3_0.dll","xaudio2_6.dll","xactengine3_4.dll","xapofx1_3.dll","xaudio2_5.dll","xapofx1_5.dll","xaudio2_1.dll","xinput1_4.dll","xpsprint.dll","xinput1_1.dll","xaudio2_8.dll","wsock32.dll","xactengine3_6.dll","xaudio2_2.dll","xaudio2_0.dll","xaudio2_3.dll","xaudio2_7.dll","xolehlp.dll","xpssvcs.dll","xactengine2_4.dll","xactengine2_7.dll","wldap32.dll","wmp.dll","wuapi.dll","wuaueng.dll","xactengine3_2.dll","xaudio2_9.dll","xinput1_2.dll","wofutil.dll","x3daudio1_5.dll","xactengine2_9.dll","xinput9_1_0.dll","xcopy.exe","xinputuap.dll","xapofx1_4.dll","xinput1_3.dll","wsdapi.dll","wtsapi32.dll","xactengine3_5.dll","xapofx1_1.dll","xmllite.dll"]} \ No newline at end of file +{"system32":["winedevice.exe","explorer.exe","iexplore.exe","notepad.exe","msxml.dll","msxml2.dll","msxml3.dll","msxml4.dll","msxml6.dll","shdocvw.dll","acledit.dll","aclui.dll","activeds.dll","activeds.tlb","actxprxy.dll","adsldp.dll","adsldpc.dll","advapi32.dll","advpack.dll","amsi.dll","amstream.dll","apisetschema.dll","apphelp.dll","appwiz.cpl","appxdeploymentclient.dll","arp.exe","atl.dll","atl100.dll","atl110.dll","atl80.dll","atl90.dll","atlthunk.dll","atmlib.dll","attrib.exe","authz.dll","avicap32.dll","avifil32.dll","avrt.dll","bcrypt.dll","bcryptprimitives.dll","bluetoothapis.dll","browseui.dll","bthprops.cpl","cabarc.exe","cabinet.dll","cacls.exe","capi2032.dll","cards.dll","cdosys.dll","certutil.exe","cfgmgr32.dll","chcp.com","clock.exe","clusapi.dll","cmd.exe","combase.dll","comcat.dll","comctl32.dll","comdlg32.dll","coml2.dll","compstui.dll","comsvcs.dll","concrt140.dll","conhost.exe","connect.dll","control.exe","credui.dll","crtdll.dll","crypt32.dll","cryptdlg.dll","cryptdll.dll","cryptext.dll","cryptnet.dll","cryptowinrt.dll","cryptsp.dll","cryptui.dll","cscript.exe","ctapi32.dll","ctl3d32.dll","d2d1.dll","d3d10.dll","d3d10core.dll","d3d10_1.dll","d3d11.dll","d3d12.dll","d3d12core.dll","d3d8.dll","d3d8thk.dll","d3d9.dll","d3dcompiler_33.dll","d3dcompiler_34.dll","d3dcompiler_35.dll","d3dcompiler_36.dll","d3dcompiler_37.dll","d3dcompiler_38.dll","d3dcompiler_39.dll","d3dcompiler_40.dll","d3dcompiler_41.dll","d3dcompiler_42.dll","d3dcompiler_43.dll","d3dcompiler_46.dll","d3dcompiler_47.dll","d3dim.dll","d3dim700.dll","d3drm.dll","d3dx10_33.dll","d3dx10_34.dll","d3dx10_35.dll","d3dx10_36.dll","d3dx10_37.dll","d3dx10_38.dll","d3dx10_39.dll","d3dx10_40.dll","d3dx10_41.dll","d3dx10_42.dll","d3dx10_43.dll","d3dx11_42.dll","d3dx11_43.dll","d3dx9_24.dll","d3dx9_25.dll","d3dx9_26.dll","d3dx9_27.dll","d3dx9_28.dll","d3dx9_29.dll","d3dx9_30.dll","d3dx9_31.dll","d3dx9_32.dll","d3dx9_33.dll","d3dx9_34.dll","d3dx9_35.dll","d3dx9_36.dll","d3dx9_37.dll","d3dx9_38.dll","d3dx9_39.dll","d3dx9_40.dll","d3dx9_41.dll","d3dx9_42.dll","d3dx9_43.dll","d3dxof.dll","davclnt.dll","dbgeng.dll","dbghelp.dll","dciman32.dll","dcomp.dll","ddraw.dll","ddrawex.dll","devenum.dll","dhcpcsvc.dll","dhcpcsvc6.dll","dhtmled.ocx","difxapi.dll","dinput.dll","dinput8.dll","directmanipulation.dll","dism.exe","dispex.dll","dllhost.exe","dmband.dll","dmcompos.dll","dmime.dll","dmloader.dll","dmscript.dll","dmstyle.dll","dmsynth.dll","dmusic.dll","dmusic32.dll","dnsapi.dll","dplay.dll","dplaysvr.exe","dplayx.dll","dpnaddr.dll","dpnet.dll","dpnhpast.dll","dpnhupnp.dll","dpnlobby.dll","dpnsvr.exe","dpvoice.dll","dpvsetup.exe","dpwsockx.dll","drmclien.dll","dsdmo.dll","dsound.dll","dsquery.dll","dssenh.dll","dsuiext.dll","dswave.dll","dwrite.dll","dxtrans.dll","dxva2.dll","eject.exe","esent.dll","explorerframe.dll","faultrep.dll","fc.exe","gdiplus.dll","geolocation.dll","hal.dll","hnetcfg.dll","hvsimanagementapi.dll","ia2comproxy.dll","icacls.exe","iccvid.dll","icinfo.exe","icmp.dll","imm32.dll","ir50_32.dll","kernel32.dll","localui.dll","mcicda.dll","mfplay.dll","mmcndmgr.dll","msasn1.dll","mscat32.dll","msctfmonitor.dll","msg711.acm","msidb.exe","msident.dll","msiexec.exe","msisip.dll","msrle32.dll","msscript.ocx","mssign32.dll","mssip32.dll","mstask.dll","msvcirt.dll","msvcp71.dll","msvcp90.dll","msvcr100.dll","msvcr120_app.dll","msvcr71.dll","msvcr90.dll","msvcrtd.dll","msvidc32.dll","ncrypt.dll","net.exe","netutils.dll","nsi.dll","ntdsapi.dll","oleaut32.dll","opcservices.dll","progman.exe","psapi.dll","qmgrprxy.dll","rasapi32.dll","regini.exe","riched32.dll","sas.dll","scardsvr.dll","sccbase.dll","schtasks.exe","sdbinst.exe","sechost.dll","sensapi.dll","shfolder.dll","shutdown.exe","spoolss.dll","systeminfo.exe","tbs.dll","tdh.dll","ucrtbase.dll","url.dll","userenv.dll","utildll.dll","uxtheme.dll","vcomp140.dll","wer.dll","wevtsvc.dll","wiaservc.dll","windows.devices.bluetooth.dll","windows.devices.enumeration.dll","windows.devices.usb.dll","windows.media.mediacontrol.dll","windows.media.speech.dll","windows.perception.stub.dll","windows.storage.applicationdata.dll","windows.system.profile.systemmanufacturers.dll","winealsa.drv","winegstreamer.dll","winepulse.drv","winnls32.dll","wintab32.dll","wlanui.dll","wldp.dll","wmasf.dll","wmp.dll","wmvcore.dll","wnaspi32.dll","wow64cpu.dll","x3daudio1_0.dll","x3daudio1_3.dll","dx8vb.dll","dxdiag.exe","dxgi.dll","evr.dll","extrac32.exe","feclient.dll","find.exe","findstr.exe","fntcache.dll","fsutil.exe","hhctrl.ocx","hostname.exe","ieframe.dll","inetcpl.cpl","ipconfig.exe","iphlpapi.dll","iprop.dll","irprops.cpl","itircl.dll","jscript.dll","kernelbase.dll","mapi32.dll","mciseq.dll","mciwave.dll","mf3216.dll","mfplat.dll","mgmtapi.dll","mp3dmod.dll","mpr.dll","msacm32.dll","msauddecmft.dll","msctfp.dll","msdelta.dll","msimsg.dll","msls31.dll","msvcr110.dll","msvcr120.dll","nddeapi.dll","netcfgx.dll","netprofm.dll","newdev.dll","ninput.dll","npptools.dll","ntprint.dll","odbccp32.dll","olepro32.dll","oleview.exe","pidgen.dll","ping.exe","pnputil.exe","propsys.dll","pstorec.dll","qedit.dll","qwave.dll","resutils.dll","rstrtmgr.dll","rtutils.dll","rtworkq.dll","scarddlg.dll","scrrun.dll","secedit.exe","serialui.dll","setupapi.dll","sfc_os.dll","sppc.dll","srclient.dll","sspicli.dll","start.exe","sti.dll","svchost.exe","svrapi.dll","t2embed.dll","taskmgr.exe","tzres.dll","uninstaller.exe","usp10.dll","vcomp100.dll","vcruntime140.dll","view.exe","vulkan-1.dll","websocket.dll","wevtapi.dll","whoami.exe","x3daudio1_5.dll","xactengine3_2.dll","xaudio2_1.dll","xaudio2_9.dll","xolehlp.dll","winepath.exe","dwmapi.dll","dxdiagn.dll","expand.exe","fltlib.dll","fontsub.dll","fwpuclnt.dll","glu32.dll","graphicscapture.dll","imaadp32.acm","inetcomm.dll","initpki.dll","kerberos.dll","klist.exe","ksproxy.ax","ktmw32.dll","loadperf.dll","lodctr.exe","lz32.dll","mf.dll","mfmediaengine.dll","mlang.dll","mmdevapi.dll","mprapi.dll","msadp32.acm","mscms.dll","msgsm32.acm","mshtml.dll","msimg32.dll","msimtf.dll","msinfo32.exe","msmpeg2vdec.dll","msnet32.dll","mspatcha.dll","msports.dll","msv1_0.dll","msvcm90.dll","msvcp100.dll","msvcp120.dll","msvcp120_app.dll","msvcp140.dll","msvcp140_1.dll","msvcp140_codecvt_ids.dll","msvcr70.dll","msvcrt20.dll","msvcrt40.dll","msvfw32.dll","ntdll.dll","odbc32.dll","odbcbcp.dll","oleacc.dll","olecli32.dll","oledlg.dll","packager.dll","pdh.dll","printui.dll","prntvpt.dll","qcap.dll","qdvd.dll","quartz.dll","query.dll","rasdlg.dll","robocopy.exe","rpcrt4.dll","rpcss.exe","rsabase.dll","schannel.dll","secur32.dll","setx.exe","shdoclc.dll","slc.dll","snmpapi.dll","srvsvc.dll","strmdll.dll","tasklist.exe","uiribbon.dll","vbscript.dll","vcomp110.dll","vga.dll","wevtutil.exe","wimgapi.dll","win32u.dll","windows.media.dll","windows.networking.dll","windows.networking.hostname.dll","winecfg.exe","winevulkan.dll","winmm.dll","wmi.dll","wmphoto.dll","wow64win.dll","wuapi.dll","dxcore.dll","gameux.dll","gamingtcui.dll","gdi32.dll","gpkcsp.dll","hid.dll","hlink.dll","hrtfapo.dll","httpapi.dll","ieproxy.dll","imagehlp.dll","inetmib1.dll","infosoft.dll","inkobj.dll","inseng.dll","itss.dll","joy.cpl","jsproxy.dll","ksuser.dll","l3codeca.acm","localspl.dll","magnification.dll","mapistub.dll","mciavi32.dll","mciqtz32.dll","mferror.dll","mfreadwrite.dll","mfsrcsnk.dll","midimap.dll","msacm32.drv","mscoree.dll","msctf.dll","msdmo.dll","msdrm.dll","msftedit.dll","mshta.exe","mshtml.tlb","msi.dll","msisys.ocx","msvcm80.dll","msvcp110.dll","msvcp140_2.dll","msvcp140_atomic_wait.dll","msvcp60.dll","msvcp70.dll","msvcp80.dll","msvcp_win.dll","msvcr80.dll","msvcrt.dll","mswsock.dll","mtxdm.dll","netapi32.dll","netsh.exe","netstat.exe","normaliz.dll","ntoskrnl.exe","objsel.dll","odbccu32.dll","ole32.dll","olesvr32.dll","olethk32.dll","opencl.dll","opengl32.dll","photometadatahandler.dll","plugplay.exe","powrprof.dll","pwrshplugin.dll","qasf.dll","qmgr.dll","reg.exe","regapi.dll","regsvr32.exe","riched20.dll","rsaenh.dll","rundll32.exe","samlib.dll","sc.exe","schedsvc.dll","scrobj.dll","security.dll","services.exe","sfc.dll","shcore.dll","shell32.dll","shlwapi.dll","slbcsp.dll","softpub.dll","spoolsv.exe","srvcli.dll","stdole2.tlb","stdole32.tlb","subst.exe","sxs.dll","tapi32.dll","taskkill.exe","taskschd.dll","termsv.exe","threadpoolwinrt.dll","traffic.dll","twain_32.dll","twinapi.appcore.dll","uianimation.dll","uiautomationcore.dll","unicows.dll","unlodctr.exe","updspapi.dll","urlmon.dll","user32.dll","vcomp.dll","vcomp120.dll","vcomp90.dll","windows.gaming.ui.gamebar.dll","winhttp.dll","wintypes.dll","wlanapi.dll","xapofx1_1.dll","x3daudio1_4.dll","windows.security.credentials.ui.userconsentverifier.dll","wineboot.exe","winedbg.exe","winemapi.dll","wing32.dll","winver.exe","wsnmp32.dll","x3daudio1_2.dll","xactengine3_0.dll","xactengine3_3.dll","xactengine3_7.dll","vcruntime140_1.dll","vdmdbg.dll","version.dll","virtdisk.dll","vssapi.dll","where.exe","windows.applicationmodel.dll","windows.ui.dll","xaudio2_8.dll","windowscodecs.dll","winebrowser.exe","winemenubuilder.exe","winspool.drv","xactengine2_0.dll","xactengine2_7.dll","xinput1_4.dll","x3daudio1_7.dll","xactengine2_4.dll","xapofx1_3.dll","xapofx1_5.dll","xaudio2_4.dll","xaudio2_6.dll","xaudio2_7.dll","xinput1_1.dll","wineconsole.exe","winemine.exe","winemsibuilder.exe","winsta.dll","winusb.dll","wscript.exe","xaudio2_5.dll","xpssvcs.dll","windows.media.devices.dll","wininet.dll","wldap32.dll","wofutil.dll","wsdapi.dll","wusa.exe","xactengine3_4.dll","xactengine3_5.dll","xactengine2_9.dll","xapofx1_2.dll","xinput1_2.dll","xpsprint.dll","windows.globalization.dll","wined3d.dll","winefile.exe","winhlp32.exe","write.exe","wsock32.dll","wuauserv.exe","x3daudio1_1.dll","xapofx1_4.dll","xaudio2_0.dll","xaudio2_3.dll","wdscore.dll","webservices.dll","windows.gaming.input.dll","wintrust.dll","ws2_32.dll","wshom.ocx","x3daudio1_6.dll","xaudio2_2.dll","xinput9_1_0.dll","xmllite.dll","xactengine3_6.dll","windowscodecsext.dll","winex11.drv","winmgmt.exe","wow64.dll","wpc.dll","wtsapi32.dll","wuaueng.dll","xactengine3_1.dll","xcopy.exe","xinput1_3.dll","xinputuap.dll"],"syswow64":["start.exe","winhlp32.exe","stdole2.tlb","iexplore.exe","msxml.dll","msxml2.dll","msxml3.dll","msxml4.dll","msxml6.dll","shdocvw.dll","acledit.dll","aclui.dll","activeds.dll","activeds.tlb","actxprxy.dll","adsldp.dll","adsldpc.dll","advapi32.dll","advpack.dll","amsi.dll","amstream.dll","apisetschema.dll","apphelp.dll","appwiz.cpl","appxdeploymentclient.dll","arp.exe","atl.dll","atl100.dll","atl110.dll","atl80.dll","atl90.dll","atlthunk.dll","atmlib.dll","attrib.exe","authz.dll","avicap32.dll","avifil32.dll","avrt.dll","bcrypt.dll","bcryptprimitives.dll","bluetoothapis.dll","browseui.dll","bthprops.cpl","cabarc.exe","cabinet.dll","cacls.exe","capi2032.dll","cards.dll","cdosys.dll","certutil.exe","cfgmgr32.dll","chcp.com","clock.exe","clusapi.dll","cmd.exe","combase.dll","comcat.dll","comctl32.dll","comdlg32.dll","coml2.dll","compstui.dll","comsvcs.dll","concrt140.dll","connect.dll","control.exe","credui.dll","crtdll.dll","crypt32.dll","cryptdlg.dll","cryptdll.dll","cryptext.dll","cryptnet.dll","cryptowinrt.dll","cryptsp.dll","cryptui.dll","cscript.exe","ctapi32.dll","ctl3d32.dll","d2d1.dll","d3d10.dll","d3d10core.dll","d3d10_1.dll","d3d11.dll","d3d12.dll","d3d12core.dll","d3d8.dll","d3d8thk.dll","d3d9.dll","d3dcompiler_33.dll","d3dcompiler_34.dll","d3dcompiler_35.dll","d3dcompiler_36.dll","d3dcompiler_37.dll","d3dcompiler_38.dll","d3dcompiler_39.dll","d3dcompiler_40.dll","d3dcompiler_41.dll","d3dcompiler_42.dll","d3dcompiler_43.dll","d3dcompiler_46.dll","d3dcompiler_47.dll","d3dim.dll","d3dim700.dll","d3drm.dll","d3dx10_33.dll","d3dx10_34.dll","d3dx10_35.dll","d3dx10_36.dll","d3dx10_37.dll","d3dx10_38.dll","d3dx10_39.dll","d3dx10_40.dll","d3dx10_41.dll","d3dx10_42.dll","d3dx10_43.dll","d3dx11_42.dll","d3dx11_43.dll","d3dx9_24.dll","d3dx9_25.dll","d3dx9_26.dll","d3dx9_27.dll","d3dx9_28.dll","d3dx9_29.dll","d3dx9_30.dll","d3dx9_31.dll","d3dx9_32.dll","d3dx9_33.dll","d3dx9_34.dll","d3dx9_35.dll","d3dx9_36.dll","d3dx9_37.dll","d3dx9_38.dll","d3dx9_39.dll","d3dx9_40.dll","d3dx9_41.dll","d3dx9_42.dll","d3dx9_43.dll","d3dxof.dll","davclnt.dll","dbgeng.dll","dbghelp.dll","dciman32.dll","dcomp.dll","ddraw.dll","ddrawex.dll","devenum.dll","dhcpcsvc.dll","dhcpcsvc6.dll","dhtmled.ocx","difxapi.dll","dinput.dll","dinput8.dll","directmanipulation.dll","dism.exe","dispex.dll","dllhost.exe","dmband.dll","dmcompos.dll","dmime.dll","dmloader.dll","dmscript.dll","dmstyle.dll","dmsynth.dll","dmusic.dll","dmusic32.dll","dnsapi.dll","dplay.dll","dplaysvr.exe","dplayx.dll","dpnaddr.dll","dpnet.dll","dpnhpast.dll","dpnhupnp.dll","dpnlobby.dll","dpnsvr.exe","dpvoice.dll","dpvsetup.exe","dpwsockx.dll","drmclien.dll","dsdmo.dll","dsound.dll","dsquery.dll","dssenh.dll","dsuiext.dll","dswave.dll","dwmapi.dll","dwrite.dll","dx8vb.dll","dxcore.dll","dxgi.dll","dxva2.dll","expand.exe","hid.dll","hlink.dll","httpapi.dll","ia2comproxy.dll","icinfo.exe","initpki.dll","inseng.dll","ipconfig.exe","ir50_32.dll","kernel32.dll","lodctr.exe","mapistub.dll","mciavi32.dll","mciqtz32.dll","mf3216.dll","mfmediaengine.dll","mfplay.dll","mgmtapi.dll","midimap.dll","mmdevapi.dll","mpr.dll","mprapi.dll","mscat32.dll","mscoree.dll","msdelta.dll","msdmo.dll","msimtf.dll","msinfo32.exe","msisip.dll","mspatcha.dll","mssip32.dll","msvcm80.dll","msvcp100.dll","msvcp140_2.dll","msvcp140_codecvt_ids.dll","msvcp60.dll","msvcp70.dll","msvcp71.dll","msvcp80.dll","msvcr120.dll","msvcr70.dll","msvcr80.dll","msvcr90.dll","msvcrt20.dll","msvcrt40.dll","msvfw32.dll","mswsock.dll","net.exe","netapi32.dll","netsh.exe","netutils.dll","ntdsapi.dll","objsel.dll","odbccu32.dll","olepro32.dll","olesvr32.dll","ping.exe","prntvpt.dll","psapi.dll","pstorec.dll","qasf.dll","quartz.dll","query.dll","qwave.dll","regapi.dll","riched32.dll","robocopy.exe","rpcss.exe","rtworkq.dll","sas.dll","sccbase.dll","schannel.dll","schedsvc.dll","schtasks.exe","sdbinst.exe","serialui.dll","sfc_os.dll","shdoclc.dll","snmpapi.dll","srvsvc.dll","subst.exe","sxs.dll","taskschd.dll","traffic.dll","uninstaller.exe","vcomp120.dll","vcruntime140.dll","version.dll","websocket.dll","wevtapi.dll","wevtutil.exe","where.exe","windows.gaming.input.dll","windows.media.dll","windowscodecs.dll","winedbg.exe","winemapi.dll","winegstreamer.dll","dxdiag.exe","dxtrans.dll","eject.exe","explorerframe.dll","findstr.exe","fsutil.exe","fwpuclnt.dll","graphicscapture.dll","hh.exe","hostname.exe","hvsimanagementapi.dll","imaadp32.acm","imagehlp.dll","inetcomm.dll","inetcpl.cpl","inetmib1.dll","infosoft.dll","inkobj.dll","iprop.dll","irprops.cpl","joy.cpl","jsproxy.dll","localui.dll","magnification.dll","mcicda.dll","mciwave.dll","msacm32.dll","msacm32.drv","msasn1.dll","msauddecmft.dll","mscms.dll","msctf.dll","msctfp.dll","mshta.exe","msidb.exe","msimg32.dll","msmpeg2vdec.dll","msscript.ocx","mssign32.dll","msv1_0.dll","msvcp140_atomic_wait.dll","msvcp90.dll","msvcr120_app.dll","msvcrt.dll","msvcrtd.dll","ncrypt.dll","nddeapi.dll","npptools.dll","ntdll.dll","ntoskrnl.exe","odbcbcp.dll","oleacc.dll","oledlg.dll","opcservices.dll","packager.dll","pdh.dll","plugplay.exe","powrprof.dll","printui.dll","progman.exe","pwrshplugin.dll","qcap.dll","qdvd.dll","rasdlg.dll","reg.exe","rpcrt4.dll","samlib.dll","scarddlg.dll","scardsvr.dll","sechost.dll","security.dll","shell32.dll","sppc.dll","srvcli.dll","sspicli.dll","strmdll.dll","svchost.exe","svrapi.dll","threadpoolwinrt.dll","twinapi.appcore.dll","unlodctr.exe","urlmon.dll","userenv.dll","utildll.dll","vbscript.dll","vcomp.dll","virtdisk.dll","vulkan-1.dll","wevtsvc.dll","wiaservc.dll","windows.globalization.dll","windows.media.devices.dll","windows.media.speech.dll","winealsa.drv","winepulse.drv","esent.dll","evr.dll","explorer.exe","fc.exe","feclient.dll","fltlib.dll","gameux.dll","gamingtcui.dll","geolocation.dll","glu32.dll","hnetcfg.dll","hrtfapo.dll","ieframe.dll","imm32.dll","itircl.dll","itss.dll","jscript.dll","kerberos.dll","kernelbase.dll","ksuser.dll","ktmw32.dll","l3codeca.acm","loadperf.dll","localspl.dll","mciseq.dll","mferror.dll","mfsrcsnk.dll","mlang.dll","mmcndmgr.dll","msadp32.acm","msgsm32.acm","mshtml.dll","msi.dll","msiexec.exe","msls31.dll","msvcm90.dll","msvcp110.dll","msvcp120.dll","msvcp140.dll","msvcr71.dll","newdev.dll","ninput.dll","normaliz.dll","nsi.dll","odbccp32.dll","ole32.dll","olecli32.dll","olethk32.dll","oleview.exe","opengl32.dll","photometadatahandler.dll","pidgen.dll","propsys.dll","qmgr.dll","rasapi32.dll","regedit.exe","regini.exe","regsvr32.exe","riched20.dll","rsaenh.dll","rtutils.dll","sc.exe","scrrun.dll","secedit.exe","secur32.dll","sensapi.dll","setupapi.dll","shfolder.dll","shlwapi.dll","slbcsp.dll","softpub.dll","systeminfo.exe","tapi32.dll","tasklist.exe","taskmgr.exe","tbs.dll","tdh.dll","tzres.dll","ucrtbase.dll","uianimation.dll","user32.dll","usp10.dll","uxtheme.dll","vcomp90.dll","vga.dll","vssapi.dll","wdscore.dll","wer.dll","whoami.exe","wimgapi.dll","windows.devices.usb.dll","windows.networking.dll","windows.networking.hostname.dll","windows.ui.dll","wineboot.exe","winecfg.exe","wineconsole.exe","wined3d.dll","winefile.exe","winemsibuilder.exe","dxdiagn.dll","extrac32.exe","faultrep.dll","find.exe","fntcache.dll","fontsub.dll","gdi32.dll","gdiplus.dll","gpkcsp.dll","hal.dll","hhctrl.ocx","icacls.exe","iccvid.dll","icmp.dll","ieproxy.dll","iphlpapi.dll","klist.exe","ksproxy.ax","lz32.dll","mapi32.dll","mf.dll","mfplat.dll","mfreadwrite.dll","mp3dmod.dll","msctfmonitor.dll","msdrm.dll","msftedit.dll","msg711.acm","mshtml.tlb","msident.dll","msimsg.dll","msisys.ocx","msnet32.dll","msports.dll","msrle32.dll","mstask.dll","msvcirt.dll","msvcp120_app.dll","msvcp140_1.dll","msvcp_win.dll","msvcr100.dll","msvcr110.dll","msvidc32.dll","mtxdm.dll","netcfgx.dll","netprofm.dll","netstat.exe","notepad.exe","ntprint.dll","odbc32.dll","oleaut32.dll","opencl.dll","pnputil.exe","qedit.dll","qmgrprxy.dll","resutils.dll","rsabase.dll","rstrtmgr.dll","rundll32.exe","scrobj.dll","setx.exe","sfc.dll","shcore.dll","shutdown.exe","slc.dll","spoolss.dll","srclient.dll","stdole32.tlb","sti.dll","t2embed.dll","taskkill.exe","termsv.exe","uiautomationcore.dll","uiribbon.dll","unicows.dll","updspapi.dll","url.dll","vcomp100.dll","vcomp110.dll","vcomp140.dll","vdmdbg.dll","view.exe","webservices.dll","win32u.dll","windows.applicationmodel.dll","windows.devices.bluetooth.dll","windows.devices.enumeration.dll","windows.gaming.ui.gamebar.dll","windows.media.mediacontrol.dll","windows.perception.stub.dll","windows.security.credentials.ui.userconsentverifier.dll","windows.storage.applicationdata.dll","windowscodecsext.dll","winebrowser.exe","wintrust.dll","wlanui.dll","winmm.dll","x3daudio1_6.dll","xactengine2_7.dll","xactengine2_9.dll","xapofx1_4.dll","xaudio2_1.dll","xaudio2_3.dll","wldp.dll","winnls32.dll","winusb.dll","wuaueng.dll","xactengine3_2.dll","xapofx1_2.dll","xaudio2_8.dll","xinput1_4.dll","xpsprint.dll","winedevice.exe","wininet.dll","write.exe","wsnmp32.dll","wtsapi32.dll","wuapi.dll","xactengine3_3.dll","wshom.ocx","x3daudio1_1.dll","x3daudio1_7.dll","xapofx1_3.dll","xaudio2_4.dll","xinputuap.dll","xmllite.dll","wldap32.dll","xapofx1_1.dll","xapofx1_5.dll","winex11.drv","wpc.dll","xactengine3_6.dll","xaudio2_5.dll","winemine.exe","winhttp.dll","winmgmt.exe","wmi.dll","wscript.exe","wsock32.dll","xactengine2_0.dll","windows.system.profile.systemmanufacturers.dll","winsta.dll","wintypes.dll","wmasf.dll","x3daudio1_2.dll","xactengine3_5.dll","xaudio2_7.dll","xaudio2_9.dll","xolehlp.dll","xpssvcs.dll","winevulkan.dll","winver.exe","wlanapi.dll","wusa.exe","xactengine2_4.dll","xactengine3_7.dll","xinput1_3.dll","xinput9_1_0.dll","xactengine3_0.dll","xinput1_1.dll","wmphoto.dll","wnaspi32.dll","ws2_32.dll","wsdapi.dll","x3daudio1_0.dll","x3daudio1_4.dll","xactengine3_4.dll","xinput1_2.dll","wmvcore.dll","wofutil.dll","x3daudio1_5.dll","xcopy.exe","winepath.exe","wintab32.dll","wmp.dll","wuauserv.exe","xactengine3_1.dll","xaudio2_0.dll","wing32.dll","winspool.drv","x3daudio1_3.dll","xaudio2_2.dll","xaudio2_6.dll"]} \ No newline at end of file diff --git a/app/src/main/assets/container_pattern.tzst b/app/src/main/assets/container_pattern.tzst index 1d63854..c588fd1 100644 Binary files a/app/src/main/assets/container_pattern.tzst and b/app/src/main/assets/container_pattern.tzst differ diff --git a/app/src/main/assets/dxwrapper/cnc-ddraw/Shaders/interpolation/bilinear.glsl b/app/src/main/assets/dxwrapper/cnc-ddraw-6.6/Shaders/interpolation/bilinear.glsl similarity index 100% rename from app/src/main/assets/dxwrapper/cnc-ddraw/Shaders/interpolation/bilinear.glsl rename to app/src/main/assets/dxwrapper/cnc-ddraw-6.6/Shaders/interpolation/bilinear.glsl diff --git a/app/src/main/assets/dxwrapper/cnc-ddraw/Shaders/cubic/catmull-rom-bilinear.glsl b/app/src/main/assets/dxwrapper/cnc-ddraw-6.6/Shaders/interpolation/catmull-rom-bilinear.glsl similarity index 100% rename from app/src/main/assets/dxwrapper/cnc-ddraw/Shaders/cubic/catmull-rom-bilinear.glsl rename to app/src/main/assets/dxwrapper/cnc-ddraw-6.6/Shaders/interpolation/catmull-rom-bilinear.glsl diff --git a/app/src/main/assets/dxwrapper/cnc-ddraw-6.6/Shaders/interpolation/fsr.glsl b/app/src/main/assets/dxwrapper/cnc-ddraw-6.6/Shaders/interpolation/fsr.glsl new file mode 100644 index 0000000..17e574b --- /dev/null +++ b/app/src/main/assets/dxwrapper/cnc-ddraw-6.6/Shaders/interpolation/fsr.glsl @@ -0,0 +1,324 @@ +/* + FSR - [EASU] EDGE ADAPTIVE SPATIAL UPSAMPLING + Ported from https://www.shadertoy.com/view/stXSWB, MIT license +*/ + +#if defined(VERTEX) + +#if __VERSION__ >= 130 +#define COMPAT_VARYING out +#define COMPAT_ATTRIBUTE in +#define COMPAT_TEXTURE texture +#else +#define COMPAT_VARYING varying +#define COMPAT_ATTRIBUTE attribute +#define COMPAT_TEXTURE texture2D +#endif + +#ifdef GL_ES +#define COMPAT_PRECISION mediump +#else +#define COMPAT_PRECISION +#endif + +COMPAT_ATTRIBUTE vec4 VertexCoord; +COMPAT_ATTRIBUTE vec4 COLOR; +COMPAT_ATTRIBUTE vec4 TexCoord; +COMPAT_VARYING vec4 COL0; +COMPAT_VARYING vec4 TEX0; + +uniform mat4 MVPMatrix; +uniform COMPAT_PRECISION int FrameDirection; +uniform COMPAT_PRECISION int FrameCount; +uniform COMPAT_PRECISION vec2 OutputSize; +uniform COMPAT_PRECISION vec2 TextureSize; +uniform COMPAT_PRECISION vec2 InputSize; + +void main() +{ + gl_Position = MVPMatrix * VertexCoord; + COL0 = COLOR; + TEX0.xy = TexCoord.xy; +} + +#elif defined(FRAGMENT) + +#if __VERSION__ >= 130 +#define COMPAT_VARYING in +#define COMPAT_TEXTURE texture +out vec4 FragColor; +#else +#define COMPAT_VARYING varying +#define FragColor gl_FragColor +#define COMPAT_TEXTURE texture2D +#endif + +#ifdef GL_ES +#ifdef GL_FRAGMENT_PRECISION_HIGH +precision highp float; +#else +precision mediump float; +#endif +#define COMPAT_PRECISION mediump +#else +#define COMPAT_PRECISION +#endif + +uniform COMPAT_PRECISION int FrameDirection; +uniform COMPAT_PRECISION int FrameCount; +uniform COMPAT_PRECISION vec2 OutputSize; +uniform COMPAT_PRECISION vec2 TextureSize; +uniform COMPAT_PRECISION vec2 InputSize; +uniform sampler2D Texture; +COMPAT_VARYING vec4 TEX0; + +// compatibility #defines +#define Source Texture +#define vTexCoord TEX0.xy + +#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize +#define outsize vec4(OutputSize, 1.0 / OutputSize) + +vec3 FsrEasuCF(vec2 p) { + return COMPAT_TEXTURE(Source,p).rgb; +} + +/**** EASU ****/ +void FsrEasuCon( + out vec4 con0, + out vec4 con1, + out vec4 con2, + out vec4 con3, + // This the rendered image resolution being upscaled + vec2 inputViewportInPixels, + // This is the resolution of the resource containing the input image (useful for dynamic resolution) + vec2 inputSizeInPixels, + // This is the display resolution which the input image gets upscaled to + vec2 outputSizeInPixels +) +{ + // Output integer position to a pixel position in viewport. + con0 = vec4( + inputViewportInPixels.x/outputSizeInPixels.x, + inputViewportInPixels.y/outputSizeInPixels.y, + .5*inputViewportInPixels.x/outputSizeInPixels.x-.5, + .5*inputViewportInPixels.y/outputSizeInPixels.y-.5 + ); + // Viewport pixel position to normalized image space. + // This is used to get upper-left of 'F' tap. + con1 = vec4(1,1,1,-1)/inputSizeInPixels.xyxy; + // Centers of gather4, first offset from upper-left of 'F'. + // +---+---+ + // | | | + // +--(0)--+ + // | b | c | + // +---F---+---+---+ + // | e | f | g | h | + // +--(1)--+--(2)--+ + // | i | j | k | l | + // +---+---+---+---+ + // | n | o | + // +--(3)--+ + // | | | + // +---+---+ + // These are from (0) instead of 'F'. + con2 = vec4(-1,2,1,2)/inputSizeInPixels.xyxy; + con3 = vec4(0,4,0,0)/inputSizeInPixels.xyxy; +} + +// Filtering for a given tap for the scalar. +void FsrEasuTapF( + inout vec3 aC, // Accumulated color, with negative lobe. + inout float aW, // Accumulated weight. + vec2 off, // Pixel offset from resolve position to tap. + vec2 dir, // Gradient direction. + vec2 len, // Length. + float lob, // Negative lobe strength. + float clp, // Clipping point. + vec3 c +) +{ + // Tap color. + // Rotate offset by direction. + vec2 v = vec2(dot(off, dir), dot(off,vec2(-dir.y,dir.x))); + // Anisotropy. + v *= len; + // Compute distance^2. + float d2 = min(dot(v,v),clp); + // Limit to the window as at corner, 2 taps can easily be outside. + // Approximation of lancos2 without sin() or rcp(), or sqrt() to get x. + // (25/16 * (2/5 * x^2 - 1)^2 - (25/16 - 1)) * (1/4 * x^2 - 1)^2 + // |_______________________________________| |_______________| + // base window + // The general form of the 'base' is, + // (a*(b*x^2-1)^2-(a-1)) + // Where 'a=1/(2*b-b^2)' and 'b' moves around the negative lobe. + float wB = .4 * d2 - 1.; + float wA = lob * d2 -1.; + wB *= wB; + wA *= wA; + wB = 1.5625*wB-.5625; + float w= wB * wA; + // Do weighted average. + aC += c*w; + aW += w; +} + +//------------------------------------------------------------------------------------------------------------------------------ +// Accumulate direction and length. +void FsrEasuSetF( + inout vec2 dir, + inout float len, + float w, + float lA,float lB,float lC,float lD,float lE +) +{ + // Direction is the '+' diff. + // a + // b c d + // e + // Then takes magnitude from abs average of both sides of 'c'. + // Length converts gradient reversal to 0, smoothly to non-reversal at 1, shaped, then adding horz and vert terms. + float lenX = max(abs(lD - lC), abs(lC - lB)); + float dirX = lD - lB; + dir.x += dirX * w; + lenX = clamp(abs(dirX)/lenX,0.,1.); + lenX *= lenX; + len += lenX * w; + // Repeat for the y axis. + float lenY = max(abs(lE - lC), abs(lC - lA)); + float dirY = lE - lA; + dir.y += dirY * w; + lenY = clamp(abs(dirY) / lenY,0.,1.); + lenY *= lenY; + len += lenY * w; +} + +//------------------------------------------------------------------------------------------------------------------------------ +void FsrEasuF( + out vec3 pix, + vec2 ip, // Integer pixel position in output. + // Constants generated by FsrEasuCon(). + vec4 con0, // xy = output to input scale, zw = first pixel offset correction + vec4 con1, + vec4 con2, + vec4 con3 +) +{ + //------------------------------------------------------------------------------------------------------------------------------ + // Get position of 'f'. + vec2 pp = ip * con0.xy + con0.zw; // Corresponding input pixel/subpixel + vec2 fp = floor(pp);// fp = source nearest pixel + pp -= fp; // pp = source subpixel + + //------------------------------------------------------------------------------------------------------------------------------ + // 12-tap kernel. + // b c + // e f g h + // i j k l + // n o + // Gather 4 ordering. + // a b + // r g + vec2 p0 = fp * con1.xy + con1.zw; + + // These are from p0 to avoid pulling two constants on pre-Navi hardware. + vec2 p1 = p0 + con2.xy; + vec2 p2 = p0 + con2.zw; + vec2 p3 = p0 + con3.xy; + + // TextureGather is not available on WebGL2 + vec4 off = vec4(-.5,.5,-.5,.5)*con1.xxyy; + // textureGather to texture offsets + // x=west y=east z=north w=south + vec3 bC = FsrEasuCF(p0 + off.xw); float bL = bC.g + 0.5 *(bC.r + bC.b); + vec3 cC = FsrEasuCF(p0 + off.yw); float cL = cC.g + 0.5 *(cC.r + cC.b); + vec3 iC = FsrEasuCF(p1 + off.xw); float iL = iC.g + 0.5 *(iC.r + iC.b); + vec3 jC = FsrEasuCF(p1 + off.yw); float jL = jC.g + 0.5 *(jC.r + jC.b); + vec3 fC = FsrEasuCF(p1 + off.yz); float fL = fC.g + 0.5 *(fC.r + fC.b); + vec3 eC = FsrEasuCF(p1 + off.xz); float eL = eC.g + 0.5 *(eC.r + eC.b); + vec3 kC = FsrEasuCF(p2 + off.xw); float kL = kC.g + 0.5 *(kC.r + kC.b); + vec3 lC = FsrEasuCF(p2 + off.yw); float lL = lC.g + 0.5 *(lC.r + lC.b); + vec3 hC = FsrEasuCF(p2 + off.yz); float hL = hC.g + 0.5 *(hC.r + hC.b); + vec3 gC = FsrEasuCF(p2 + off.xz); float gL = gC.g + 0.5 *(gC.r + gC.b); + vec3 oC = FsrEasuCF(p3 + off.yz); float oL = oC.g + 0.5 *(oC.r + oC.b); + vec3 nC = FsrEasuCF(p3 + off.xz); float nL = nC.g + 0.5 *(nC.r + nC.b); + + //------------------------------------------------------------------------------------------------------------------------------ + // Simplest multi-channel approximate luma possible (luma times 2, in 2 FMA/MAD). + // Accumulate for bilinear interpolation. + vec2 dir = vec2(0); + float len = 0.; + + FsrEasuSetF(dir, len, (1.-pp.x)*(1.-pp.y), bL, eL, fL, gL, jL); + FsrEasuSetF(dir, len, pp.x *(1.-pp.y), cL, fL, gL, hL, kL); + FsrEasuSetF(dir, len, (1.-pp.x)* pp.y , fL, iL, jL, kL, nL); + FsrEasuSetF(dir, len, pp.x * pp.y , gL, jL, kL, lL, oL); + + //------------------------------------------------------------------------------------------------------------------------------ + // Normalize with approximation, and cleanup close to zero. + vec2 dir2 = dir * dir; + float dirR = dir2.x + dir2.y; + bool zro = dirR < (1.0/32768.0); + dirR = inversesqrt(dirR); + dirR = zro ? 1.0 : dirR; + dir.x = zro ? 1.0 : dir.x; + dir *= vec2(dirR); + // Transform from {0 to 2} to {0 to 1} range, and shape with square. + len = len * 0.5; + len *= len; + // Stretch kernel {1.0 vert|horz, to sqrt(2.0) on diagonal}. + float stretch = dot(dir,dir) / (max(abs(dir.x), abs(dir.y))); + // Anisotropic length after rotation, + // x := 1.0 lerp to 'stretch' on edges + // y := 1.0 lerp to 2x on edges + vec2 len2 = vec2(1. +(stretch-1.0)*len, 1. -.5 * len); + // Based on the amount of 'edge', + // the window shifts from +/-{sqrt(2.0) to slightly beyond 2.0}. + float lob = .5 - .29 * len; + // Set distance^2 clipping point to the end of the adjustable window. + float clp = 1./lob; + + //------------------------------------------------------------------------------------------------------------------------------ + // Accumulation mixed with min/max of 4 nearest. + // b c + // e f g h + // i j k l + // n o + vec3 min4 = min(min(fC,gC),min(jC,kC)); + vec3 max4 = max(max(fC,gC),max(jC,kC)); + // Accumulation. + vec3 aC = vec3(0); + float aW = 0.; + FsrEasuTapF(aC, aW, vec2( 0,-1)-pp, dir, len2, lob, clp, bC); + FsrEasuTapF(aC, aW, vec2( 1,-1)-pp, dir, len2, lob, clp, cC); + FsrEasuTapF(aC, aW, vec2(-1, 1)-pp, dir, len2, lob, clp, iC); + FsrEasuTapF(aC, aW, vec2( 0, 1)-pp, dir, len2, lob, clp, jC); + FsrEasuTapF(aC, aW, vec2( 0, 0)-pp, dir, len2, lob, clp, fC); + FsrEasuTapF(aC, aW, vec2(-1, 0)-pp, dir, len2, lob, clp, eC); + FsrEasuTapF(aC, aW, vec2( 1, 1)-pp, dir, len2, lob, clp, kC); + FsrEasuTapF(aC, aW, vec2( 2, 1)-pp, dir, len2, lob, clp, lC); + FsrEasuTapF(aC, aW, vec2( 2, 0)-pp, dir, len2, lob, clp, hC); + FsrEasuTapF(aC, aW, vec2( 1, 0)-pp, dir, len2, lob, clp, gC); + FsrEasuTapF(aC, aW, vec2( 1, 2)-pp, dir, len2, lob, clp, oC); + FsrEasuTapF(aC, aW, vec2( 0, 2)-pp, dir, len2, lob, clp, nC); + //------------------------------------------------------------------------------------------------------------------------------ + // Normalize and dering. + pix=min(max4,max(min4,aC/aW)); +} + +void main() +{ + vec3 c; + vec4 con0,con1,con2,con3; + + vec2 fragCoord = vTexCoord.xy * OutputSize.xy; + + FsrEasuCon( + con0, con1, con2, con3, SourceSize.xy, SourceSize.xy, OutputSize.xy + ); + FsrEasuF(c, fragCoord, con0, con1, con2, con3); + FragColor = vec4(c.xyz, 1); +} + +#endif diff --git a/app/src/main/assets/dxwrapper/cnc-ddraw-6.6/Shaders/interpolation/fsr.glsl.pass1 b/app/src/main/assets/dxwrapper/cnc-ddraw-6.6/Shaders/interpolation/fsr.glsl.pass1 new file mode 100644 index 0000000..d9ce74f --- /dev/null +++ b/app/src/main/assets/dxwrapper/cnc-ddraw-6.6/Shaders/interpolation/fsr.glsl.pass1 @@ -0,0 +1,178 @@ +/* + FSR - [RCAS] ROBUST CONTRAST ADAPTIVE SHARPENING + Ported from https://www.shadertoy.com/view/stXSWB, MIT license +*/ + +#pragma parameter FSR_SHARPENING "FSR RCAS Sharpening Amount (Lower = Sharper)" 0.6 0.0 2.0 0.1 + +#if defined(VERTEX) + +#if __VERSION__ >= 130 +#define COMPAT_VARYING out +#define COMPAT_ATTRIBUTE in +#define COMPAT_TEXTURE texture +#else +#define COMPAT_VARYING varying +#define COMPAT_ATTRIBUTE attribute +#define COMPAT_TEXTURE texture2D +#endif + +#ifdef GL_ES +#define COMPAT_PRECISION mediump +#else +#define COMPAT_PRECISION +#endif + +COMPAT_ATTRIBUTE vec4 VertexCoord; +COMPAT_ATTRIBUTE vec4 COLOR; +COMPAT_ATTRIBUTE vec4 TexCoord; +COMPAT_VARYING vec4 COL0; +COMPAT_VARYING vec4 TEX0; + +uniform mat4 MVPMatrix; +uniform COMPAT_PRECISION int FrameDirection; +uniform COMPAT_PRECISION int FrameCount; +uniform COMPAT_PRECISION vec2 OutputSize; +uniform COMPAT_PRECISION vec2 TextureSize; +uniform COMPAT_PRECISION vec2 InputSize; + +void main() +{ + gl_Position = MVPMatrix * VertexCoord; + COL0 = COLOR; + TEX0.xy = TexCoord.xy; +} + +#elif defined(FRAGMENT) + +#if __VERSION__ >= 130 +#define COMPAT_VARYING in +#define COMPAT_TEXTURE texture +out vec4 FragColor; +#else +#define COMPAT_VARYING varying +#define FragColor gl_FragColor +#define COMPAT_TEXTURE texture2D +#endif + +#ifdef GL_ES +#ifdef GL_FRAGMENT_PRECISION_HIGH +precision highp float; +#else +precision mediump float; +#endif +#define COMPAT_PRECISION mediump +#else +#define COMPAT_PRECISION +#endif + +uniform COMPAT_PRECISION int FrameDirection; +uniform COMPAT_PRECISION int FrameCount; +uniform COMPAT_PRECISION vec2 OutputSize; +uniform COMPAT_PRECISION vec2 TextureSize; +uniform COMPAT_PRECISION vec2 InputSize; +uniform sampler2D Texture; +COMPAT_VARYING vec4 TEX0; + +// compatibility #defines +#define Source Texture +#define vTexCoord TEX0.xy + +#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize +#define outsize vec4(OutputSize, 1.0 / OutputSize) + +#ifdef PARAMETER_UNIFORM +uniform COMPAT_PRECISION float FSR_SHARPENING; +#else +#define FSR_SHARPENING 0.6 +#endif + +#define FSR_RCAS_LIMIT (0.25-(1.0/16.0)) +//#define FSR_RCAS_DENOISE + +// Input callback prototypes that need to be implemented by calling shader +vec4 FsrRcasLoadF(vec2 p); +//------------------------------------------------------------------------------------------------------------------------------ +void FsrRcasCon( + out float con, + // The scale is {0.0 := maximum, to N>0, where N is the number of stops (halving) of the reduction of sharpness}. + float sharpness +){ + // Transform from stops to linear value. + con = exp2(-sharpness); +} + +vec3 FsrRcasF( + vec2 ip, // Integer pixel position in output. + float con +) +{ + // Constant generated by RcasSetup(). + // Algorithm uses minimal 3x3 pixel neighborhood. + // b + // d e f + // h + vec2 sp = vec2(ip); + vec3 b = FsrRcasLoadF(sp + vec2( 0,-1)).rgb; + vec3 d = FsrRcasLoadF(sp + vec2(-1, 0)).rgb; + vec3 e = FsrRcasLoadF(sp).rgb; + vec3 f = FsrRcasLoadF(sp+vec2( 1, 0)).rgb; + vec3 h = FsrRcasLoadF(sp+vec2( 0, 1)).rgb; + // Luma times 2. + float bL = b.g + .5 * (b.b + b.r); + float dL = d.g + .5 * (d.b + d.r); + float eL = e.g + .5 * (e.b + e.r); + float fL = f.g + .5 * (f.b + f.r); + float hL = h.g + .5 * (h.b + h.r); + // Noise detection. + float nz = .25 * (bL + dL + fL + hL) - eL; + nz=clamp( + abs(nz) + /( + max(max(bL,dL),max(eL,max(fL,hL))) + -min(min(bL,dL),min(eL,min(fL,hL))) + ), + 0., 1. + ); + nz=1.-.5*nz; + // Min and max of ring. + vec3 mn4 = min(b, min(f, h)); + vec3 mx4 = max(b, max(f, h)); + // Immediate constants for peak range. + vec2 peakC = vec2(1., -4.); + // Limiters, these need to be high precision RCPs. + vec3 hitMin = mn4 / (4. * mx4); + vec3 hitMax = (peakC.x - mx4) / (4.* mn4 + peakC.y); + vec3 lobeRGB = max(-hitMin, hitMax); + float lobe = max( + -FSR_RCAS_LIMIT, + min(max(lobeRGB.r, max(lobeRGB.g, lobeRGB.b)), 0.) + )*con; + // Apply noise removal. + #ifdef FSR_RCAS_DENOISE + lobe *= nz; + #endif + // Resolve, which needs the medium precision rcp approximation to avoid visible tonality changes. + return (lobe * (b + d + h + f) + e) / (4. * lobe + 1.); +} + + +vec4 FsrRcasLoadF(vec2 p) { + return COMPAT_TEXTURE(Source,p/OutputSize.xy); +} + +void main() +{ + vec2 fragCoord = vTexCoord.xy * OutputSize.xy; + + // Set up constants + float con; + FsrRcasCon(con, FSR_SHARPENING); + + // Perform RCAS pass + vec3 col = FsrRcasF(fragCoord, con); + + FragColor = vec4(col,1); +} + +#endif diff --git a/app/src/main/assets/dxwrapper/cnc-ddraw-6.6/Shaders/interpolation/jinc2-dedither.glsl b/app/src/main/assets/dxwrapper/cnc-ddraw-6.6/Shaders/interpolation/jinc2-dedither.glsl new file mode 100644 index 0000000..32235e0 --- /dev/null +++ b/app/src/main/assets/dxwrapper/cnc-ddraw-6.6/Shaders/interpolation/jinc2-dedither.glsl @@ -0,0 +1,202 @@ +/* + Hyllian's jinc windowed-jinc 2-lobe sharper with anti-ringing Shader + + Copyright (C) 2011-2016 Hyllian/Jararaca - sergiogdb@gmail.com + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#define JINC2_WINDOW_SINC 0.405 +#define JINC2_SINC 0.79 +#define JINC2_AR_STRENGTH 0.8 + +#define texCoord TEX0 + +#if defined(VERTEX) + +#if __VERSION__ >= 130 +#define OUT out +#define IN in +#define tex2D texture +#else +#define OUT varying +#define IN attribute +#define tex2D texture2D +#endif + +#ifdef GL_ES +#define COMPAT_PRECISION mediump +#else +#define COMPAT_PRECISION +#endif + + +IN vec4 VertexCoord; +IN vec4 Color; +IN vec2 TexCoord; +OUT vec4 color; +OUT vec2 texCoord; + +uniform mat4 MVPMatrix; +uniform COMPAT_PRECISION int FrameDirection; +uniform COMPAT_PRECISION int FrameCount; +uniform COMPAT_PRECISION vec2 OutputSize; +uniform COMPAT_PRECISION vec2 TextureSize; +uniform COMPAT_PRECISION vec2 InputSize; + +void main() +{ + gl_Position = MVPMatrix * VertexCoord; + color = Color; + texCoord = TexCoord * 1.0001; +} + +#elif defined(FRAGMENT) + +#if __VERSION__ >= 130 +#define IN in +#define tex2D texture +out vec4 FragColor; +#else +#define IN varying +#define FragColor gl_FragColor +#define tex2D texture2D +#endif + +#ifdef GL_ES +#ifdef GL_FRAGMENT_PRECISION_HIGH +precision highp float; +#else +precision mediump float; +#endif +#define COMPAT_PRECISION mediump +#else +#define COMPAT_PRECISION +#endif + +uniform COMPAT_PRECISION int FrameDirection; +uniform COMPAT_PRECISION int FrameCount; +uniform COMPAT_PRECISION vec2 OutputSize; +uniform COMPAT_PRECISION vec2 TextureSize; +uniform COMPAT_PRECISION vec2 InputSize; +uniform sampler2D s_p; +IN vec2 texCoord; + +const float halfpi = 1.5707963267948966192313216916398; +const float pi = 3.1415926535897932384626433832795; +const float wa = JINC2_WINDOW_SINC*pi; +const float wb = JINC2_SINC*pi; + +// Calculates the distance between two points +float d(vec2 pt1, vec2 pt2) +{ + vec2 v = pt2 - pt1; + return sqrt(dot(v,v)); +} + +vec3 min4(vec3 a, vec3 b, vec3 c, vec3 d) +{ + return min(a, min(b, min(c, d))); +} + +vec3 max4(vec3 a, vec3 b, vec3 c, vec3 d) +{ + return max(a, max(b, max(c, d))); +} + +vec4 resampler(vec4 x) +{ + vec4 res; + + res = (x==vec4(0.0, 0.0, 0.0, 0.0)) ? vec4(wa*wb) : sin(x*wa)*sin(x*wb)/(x*x); + + return res; +} + +void main() +{ + + vec3 color; + vec4 weights[4]; + + vec2 dx = vec2(1.0, 0.0); + vec2 dy = vec2(0.0, 1.0); + + vec2 pc = texCoord*TextureSize; + + vec2 tc = (floor(pc-vec2(0.5,0.5))+vec2(0.5,0.5)); + + weights[0] = resampler(vec4(d(pc, tc -dx -dy), d(pc, tc -dy), d(pc, tc +dx -dy), d(pc, tc+2.0*dx -dy))); + weights[1] = resampler(vec4(d(pc, tc -dx ), d(pc, tc ), d(pc, tc +dx ), d(pc, tc+2.0*dx ))); + weights[2] = resampler(vec4(d(pc, tc -dx +dy), d(pc, tc +dy), d(pc, tc +dx +dy), d(pc, tc+2.0*dx +dy))); + weights[3] = resampler(vec4(d(pc, tc -dx+2.0*dy), d(pc, tc +2.0*dy), d(pc, tc +dx+2.0*dy), d(pc, tc+2.0*dx+2.0*dy))); + + dx = dx/TextureSize; + dy = dy/TextureSize; + tc = tc/TextureSize; + + vec3 c00 = tex2D(s_p, tc -dx -dy).xyz; + vec3 c10 = tex2D(s_p, tc -dy).xyz; + vec3 c20 = tex2D(s_p, tc +dx -dy).xyz; + vec3 c30 = tex2D(s_p, tc+2.0*dx -dy).xyz; + vec3 c01 = tex2D(s_p, tc -dx ).xyz; + vec3 c11 = tex2D(s_p, tc ).xyz; + vec3 c21 = tex2D(s_p, tc +dx ).xyz; + vec3 c31 = tex2D(s_p, tc+2.0*dx ).xyz; + vec3 c02 = tex2D(s_p, tc -dx +dy).xyz; + vec3 c12 = tex2D(s_p, tc +dy).xyz; + vec3 c22 = tex2D(s_p, tc +dx +dy).xyz; + vec3 c32 = tex2D(s_p, tc+2.0*dx +dy).xyz; + vec3 c03 = tex2D(s_p, tc -dx+2.0*dy).xyz; + vec3 c13 = tex2D(s_p, tc +2.0*dy).xyz; + vec3 c23 = tex2D(s_p, tc +dx+2.0*dy).xyz; + vec3 c33 = tex2D(s_p, tc+2.0*dx+2.0*dy).xyz; + + color = tex2D(s_p, texCoord).xyz; + + // Get min/max samples + vec3 min_sample = min4(c11, c21, c12, c22); + vec3 max_sample = max4(c11, c21, c12, c22); +/* + color = mat4x3(c00, c10, c20, c30) * weights[0]; + color+= mat4x3(c01, c11, c21, c31) * weights[1]; + color+= mat4x3(c02, c12, c22, c32) * weights[2]; + color+= mat4x3(c03, c13, c23, c33) * weights[3]; + mat4 wgts = mat4(weights[0], weights[1], weights[2], weights[3]); + vec4 wsum = wgts * vec4(1.0,1.0,1.0,1.0); + color = color/(dot(wsum, vec4(1.0,1.0,1.0,1.0))); +*/ + + + color = vec3(dot(weights[0], vec4(c00.x, c10.x, c20.x, c30.x)), dot(weights[0], vec4(c00.y, c10.y, c20.y, c30.y)), dot(weights[0], vec4(c00.z, c10.z, c20.z, c30.z))); + color+= vec3(dot(weights[1], vec4(c01.x, c11.x, c21.x, c31.x)), dot(weights[1], vec4(c01.y, c11.y, c21.y, c31.y)), dot(weights[1], vec4(c01.z, c11.z, c21.z, c31.z))); + color+= vec3(dot(weights[2], vec4(c02.x, c12.x, c22.x, c32.x)), dot(weights[2], vec4(c02.y, c12.y, c22.y, c32.y)), dot(weights[2], vec4(c02.z, c12.z, c22.z, c32.z))); + color+= vec3(dot(weights[3], vec4(c03.x, c13.x, c23.x, c33.x)), dot(weights[3], vec4(c03.y, c13.y, c23.y, c33.y)), dot(weights[3], vec4(c03.z, c13.z, c23.z, c33.z))); + color = color/(dot(weights[0], vec4(1,1,1,1)) + dot(weights[1], vec4(1,1,1,1)) + dot(weights[2], vec4(1,1,1,1)) + dot(weights[3], vec4(1,1,1,1))); + + // Anti-ringing + vec3 aux = color; + color = clamp(color, min_sample, max_sample); + color = mix(aux, color, JINC2_AR_STRENGTH); + + // final sum and weight normalization + FragColor.xyz = color; +} +#endif diff --git a/app/src/main/assets/dxwrapper/cnc-ddraw-6.6/Shaders/interpolation/lanczos2-sharp.glsl b/app/src/main/assets/dxwrapper/cnc-ddraw-6.6/Shaders/interpolation/lanczos2-sharp.glsl new file mode 100644 index 0000000..5f83af3 --- /dev/null +++ b/app/src/main/assets/dxwrapper/cnc-ddraw-6.6/Shaders/interpolation/lanczos2-sharp.glsl @@ -0,0 +1,205 @@ +/* + Hyllian's jinc windowed-jinc 2-lobe sharper with anti-ringing Shader + + Copyright (C) 2011-2016 Hyllian/Jararaca - sergiogdb@gmail.com + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#define JINC2_WINDOW_SINC 0.5 +#define JINC2_SINC 1.0 +#define JINC2_AR_STRENGTH 0.8 + +#define texCoord TEX0 + +#if defined(VERTEX) + +#if __VERSION__ >= 130 +#define OUT out +#define IN in +#define tex2D texture +#else +#define OUT varying +#define IN attribute +#define tex2D texture2D +#endif + +#ifdef GL_ES +#define COMPAT_PRECISION mediump +#else +#define COMPAT_PRECISION +#endif + + +IN vec4 VertexCoord; +IN vec4 Color; +IN vec2 TexCoord; +OUT vec4 color; +OUT vec2 texCoord; + +uniform mat4 MVPMatrix; +uniform COMPAT_PRECISION int FrameDirection; +uniform COMPAT_PRECISION int FrameCount; +uniform COMPAT_PRECISION vec2 OutputSize; +uniform COMPAT_PRECISION vec2 TextureSize; +uniform COMPAT_PRECISION vec2 InputSize; + +void main() +{ + gl_Position = MVPMatrix * VertexCoord; + color = Color; + texCoord = TexCoord; +} + +#elif defined(FRAGMENT) + +#if __VERSION__ >= 130 +#define IN in +#define tex2D texture +out vec4 FragColor; +#else +#define IN varying +#define FragColor gl_FragColor +#define tex2D texture2D +#endif + +#ifdef GL_ES +#ifdef GL_FRAGMENT_PRECISION_HIGH +precision highp float; +#else +precision mediump float; +#endif +#define COMPAT_PRECISION mediump +#else +#define COMPAT_PRECISION +#endif + +uniform COMPAT_PRECISION int FrameDirection; +uniform COMPAT_PRECISION int FrameCount; +uniform COMPAT_PRECISION vec2 OutputSize; +uniform COMPAT_PRECISION vec2 TextureSize; +uniform COMPAT_PRECISION vec2 InputSize; +uniform sampler2D s_p; +IN vec2 texCoord; + +const float halfpi = 1.5707963267948966192313216916398; +const float pi = 3.1415926535897932384626433832795; +const float wa = JINC2_WINDOW_SINC*pi; +const float wb = JINC2_SINC*pi; + +// Calculates the distance between two points +float d(vec2 pt1, vec2 pt2) +{ + vec2 v = pt2 - pt1; + return sqrt(dot(v,v)); +} + +vec3 min4(vec3 a, vec3 b, vec3 c, vec3 d) +{ + return min(a, min(b, min(c, d))); +} + +vec3 max4(vec3 a, vec3 b, vec3 c, vec3 d) +{ + return max(a, max(b, max(c, d))); +} + +vec4 resampler(vec4 x) +{ + vec4 res; + + res.x = (x.x==0.0) ? wa*wb : sin(x.x*wa)*sin(x.x*wb)/(x.x*x.x); + res.y = (x.y==0.0) ? wa*wb : sin(x.y*wa)*sin(x.y*wb)/(x.y*x.y); + res.z = (x.z==0.0) ? wa*wb : sin(x.z*wa)*sin(x.z*wb)/(x.z*x.z); + res.w = (x.w==0.0) ? wa*wb : sin(x.w*wa)*sin(x.w*wb)/(x.w*x.w); + + return res; +} + +void main() +{ + + vec3 color; + vec4 weights[4]; + + vec2 dx = vec2(1.0, 0.0); + vec2 dy = vec2(0.0, 1.0); + + vec2 pc = texCoord*TextureSize; + + vec2 tc = (floor(pc-vec2(0.5,0.5))+vec2(0.5,0.5)); + + weights[0] = resampler(vec4(d(pc, tc -dx -dy), d(pc, tc -dy), d(pc, tc +dx -dy), d(pc, tc+2.0*dx -dy))); + weights[1] = resampler(vec4(d(pc, tc -dx ), d(pc, tc ), d(pc, tc +dx ), d(pc, tc+2.0*dx ))); + weights[2] = resampler(vec4(d(pc, tc -dx +dy), d(pc, tc +dy), d(pc, tc +dx +dy), d(pc, tc+2.0*dx +dy))); + weights[3] = resampler(vec4(d(pc, tc -dx+2.0*dy), d(pc, tc +2.0*dy), d(pc, tc +dx+2.0*dy), d(pc, tc+2.0*dx+2.0*dy))); + + dx = dx/TextureSize; + dy = dy/TextureSize; + tc = tc/TextureSize; + + vec3 c00 = tex2D(s_p, tc -dx -dy).xyz; + vec3 c10 = tex2D(s_p, tc -dy).xyz; + vec3 c20 = tex2D(s_p, tc +dx -dy).xyz; + vec3 c30 = tex2D(s_p, tc+2.0*dx -dy).xyz; + vec3 c01 = tex2D(s_p, tc -dx ).xyz; + vec3 c11 = tex2D(s_p, tc ).xyz; + vec3 c21 = tex2D(s_p, tc +dx ).xyz; + vec3 c31 = tex2D(s_p, tc+2.0*dx ).xyz; + vec3 c02 = tex2D(s_p, tc -dx +dy).xyz; + vec3 c12 = tex2D(s_p, tc +dy).xyz; + vec3 c22 = tex2D(s_p, tc +dx +dy).xyz; + vec3 c32 = tex2D(s_p, tc+2.0*dx +dy).xyz; + vec3 c03 = tex2D(s_p, tc -dx+2.0*dy).xyz; + vec3 c13 = tex2D(s_p, tc +2.0*dy).xyz; + vec3 c23 = tex2D(s_p, tc +dx+2.0*dy).xyz; + vec3 c33 = tex2D(s_p, tc+2.0*dx+2.0*dy).xyz; + + color = tex2D(s_p, texCoord).xyz; + + // Get min/max samples + vec3 min_sample = min4(c11, c21, c12, c22); + vec3 max_sample = max4(c11, c21, c12, c22); +/* + color = mat4x3(c00, c10, c20, c30) * weights[0]; + color+= mat4x3(c01, c11, c21, c31) * weights[1]; + color+= mat4x3(c02, c12, c22, c32) * weights[2]; + color+= mat4x3(c03, c13, c23, c33) * weights[3]; + mat4 wgts = mat4(weights[0], weights[1], weights[2], weights[3]); + vec4 wsum = wgts * vec4(1.0,1.0,1.0,1.0); + color = color/(dot(wsum, vec4(1.0,1.0,1.0,1.0))); +*/ + + + color = vec3(dot(weights[0], vec4(c00.x, c10.x, c20.x, c30.x)), dot(weights[0], vec4(c00.y, c10.y, c20.y, c30.y)), dot(weights[0], vec4(c00.z, c10.z, c20.z, c30.z))); + color+= vec3(dot(weights[1], vec4(c01.x, c11.x, c21.x, c31.x)), dot(weights[1], vec4(c01.y, c11.y, c21.y, c31.y)), dot(weights[1], vec4(c01.z, c11.z, c21.z, c31.z))); + color+= vec3(dot(weights[2], vec4(c02.x, c12.x, c22.x, c32.x)), dot(weights[2], vec4(c02.y, c12.y, c22.y, c32.y)), dot(weights[2], vec4(c02.z, c12.z, c22.z, c32.z))); + color+= vec3(dot(weights[3], vec4(c03.x, c13.x, c23.x, c33.x)), dot(weights[3], vec4(c03.y, c13.y, c23.y, c33.y)), dot(weights[3], vec4(c03.z, c13.z, c23.z, c33.z))); + color = color/(dot(weights[0], vec4(1,1,1,1)) + dot(weights[1], vec4(1,1,1,1)) + dot(weights[2], vec4(1,1,1,1)) + dot(weights[3], vec4(1,1,1,1))); + + // Anti-ringing + vec3 aux = color; + color = clamp(color, min_sample, max_sample); + color = mix(aux, color, JINC2_AR_STRENGTH); + + // final sum and weight normalization + FragColor.xyz = color; +} +#endif diff --git a/app/src/main/assets/dxwrapper/cnc-ddraw-6.6/Shaders/nearest-neighbor.glsl b/app/src/main/assets/dxwrapper/cnc-ddraw-6.6/Shaders/nearest-neighbor.glsl new file mode 100644 index 0000000..aa7bee6 --- /dev/null +++ b/app/src/main/assets/dxwrapper/cnc-ddraw-6.6/Shaders/nearest-neighbor.glsl @@ -0,0 +1,73 @@ +#if defined(VERTEX) + +#if __VERSION__ >= 130 +#define COMPAT_VARYING out +#define COMPAT_ATTRIBUTE in +#define COMPAT_TEXTURE texture +#else +#define COMPAT_VARYING varying +#define COMPAT_ATTRIBUTE attribute +#define COMPAT_TEXTURE texture2D +#endif + +#ifdef GL_ES +#define COMPAT_PRECISION mediump +#else +#define COMPAT_PRECISION +#endif + +COMPAT_ATTRIBUTE vec4 VertexCoord; +COMPAT_ATTRIBUTE vec4 COLOR; +COMPAT_ATTRIBUTE vec4 TexCoord; +COMPAT_VARYING vec4 COL0; +COMPAT_VARYING vec4 TEX0; + +uniform mat4 MVPMatrix; +uniform COMPAT_PRECISION int FrameDirection; +uniform COMPAT_PRECISION int FrameCount; +uniform COMPAT_PRECISION vec2 OutputSize; +uniform COMPAT_PRECISION vec2 TextureSize; +uniform COMPAT_PRECISION vec2 InputSize; + +void main() +{ + gl_Position = VertexCoord.x * MVPMatrix[0] + VertexCoord.y * MVPMatrix[1] + VertexCoord.z * MVPMatrix[2] + VertexCoord.w * MVPMatrix[3]; + TEX0.xy = TexCoord.xy; +} + +#elif defined(FRAGMENT) + +#if __VERSION__ >= 130 +#define COMPAT_VARYING in +#define COMPAT_TEXTURE texture +out vec4 FragColor; +#else +#define COMPAT_VARYING varying +#define FragColor gl_FragColor +#define COMPAT_TEXTURE texture2D +#endif + +#ifdef GL_ES +#ifdef GL_FRAGMENT_PRECISION_HIGH +precision highp float; +#else +precision mediump float; +#endif +#define COMPAT_PRECISION mediump +#else +#define COMPAT_PRECISION +#endif + +uniform COMPAT_PRECISION int FrameDirection; +uniform COMPAT_PRECISION int FrameCount; +uniform COMPAT_PRECISION vec2 OutputSize; +uniform COMPAT_PRECISION vec2 TextureSize; +uniform COMPAT_PRECISION vec2 InputSize; +uniform sampler2D Texture; +COMPAT_VARYING vec4 TEX0; + +void main() +{ + FragColor = COMPAT_TEXTURE(Texture, TEX0.xy); +} +#endif \ No newline at end of file diff --git a/app/src/main/assets/dxwrapper/cnc-ddraw/ddraw.ini b/app/src/main/assets/dxwrapper/cnc-ddraw-6.6/ddraw.ini similarity index 72% rename from app/src/main/assets/dxwrapper/cnc-ddraw/ddraw.ini rename to app/src/main/assets/dxwrapper/cnc-ddraw-6.6/ddraw.ini index aa5c3ca..80fc4bc 100644 --- a/app/src/main/assets/dxwrapper/cnc-ddraw/ddraw.ini +++ b/app/src/main/assets/dxwrapper/cnc-ddraw-6.6/ddraw.ini @@ -38,14 +38,14 @@ adjmouse=true ; 2x scaling example: https://imgur.com/a/kxsM1oY - 4x scaling example: https://imgur.com/a/wjrhpFV ; You can specify a full path to a .glsl shader file here or use one of the values listed below ; Possible values: Nearest neighbor, Bilinear, Bicubic, Lanczos, xBR-lv2 -shader=C:\ProgramData\cnc-ddraw\Shaders\cubic\catmull-rom-bilinear.glsl +shader=C:\ProgramData\cnc-ddraw\Shaders\interpolation\catmull-rom-bilinear.glsl ; Window position, -32000 = center to screen posX=-32000 posY=-32000 ; Renderer, possible values: auto, opengl, openglcore, gdi, direct3d9, direct3d9on12 (auto = try direct3d9/opengl, fallback = gdi) -renderer=direct3d9 +renderer=auto ; Developer mode (don't lock the cursor) devmode=false @@ -64,7 +64,7 @@ resizable=true ; Possible values: 0 = nearest-neighbor, 1 = bilinear, 2 = bicubic, 3 = lanczos (bicubic/lanczos only support 16/32bit color depth games) d3d9_filter=2 -; Enable upscale hack for high resolution patches (Supports C&C1, Red Alert 1 and KKND Xtreme) +; Enable upscale hack for high resolution patches (Supports C&C1, Red Alert 1, Worms 2 and KKND Xtreme) vhack=false ; Where should screenshots be saved @@ -90,6 +90,9 @@ noactivateapp=false ; Note: Usually one of the following values will work: 60 / 30 / 25 / 20 / 15 (lower value = slower game speed) maxgameticks=0 +; Method that should be used to limit game ticks (maxgameticks=): 0 = Automatic, 1 = TestCooperativeLevel, 2 = BltFast +limiter_type=0 + ; Force minimum FPS, possible values: 0 = disabled, -1 = use 'maxfps=' value, -2 = same as -1 but force full redraw, 1-1000 = custom FPS ; Note: Set this to a low value such as 5 or 10 if some parts of the game are not being displayed (e.g. menus or loading screens) minfps=0 @@ -123,7 +126,6 @@ fixnotresponding=false hook=4 guard_lines=200 max_resolutions=0 -limit_bltfast=false lock_surfaces=false allow_wmactivate=false flipclear=false @@ -136,6 +138,11 @@ custom_width=0 custom_height=0 min_font_size=0 direct3d_passthrough=false +center_cursor_fix=false +;fake_mode=640x480x32 +wine_allow_resize=false +lock_mouse_top_left=false +no_compat_warning=false @@ -185,7 +192,7 @@ allow_reset=true ; Atrox [Atrox] -fixchilds=0 +nonexclusive=true allow_wmactivate=true ; Atomic Bomberman @@ -220,17 +227,20 @@ resolutions=2 guard_lines=300 minfps=-2 +; American Girls Dress Designer +[Dress Designer] +fake_mode=640x480x32 +nonexclusive=true + ; Age of Wonders 2 [AoW2] resolutions=2 renderer=opengl -singlecpu=false ; Age of Wonders 2 [AoW2Compat] resolutions=2 renderer=opengl -singlecpu=false ; Age of Wonders 2 Config Tool [aow2Setup] @@ -240,13 +250,11 @@ resolutions=2 [AoWSM] resolutions=2 renderer=opengl -singlecpu=false ; Age of Wonders: Shadow Magic [AoWSMCompat] resolutions=2 renderer=opengl -singlecpu=false ; Age of Wonders: Shadow Magic Config Tool [AoWSMSetup] @@ -269,11 +277,16 @@ adjmouse=true [ATLANTIS] renderer=opengl maxgameticks=60 +center_cursor_fix=true ; Airline Tycoon Deluxe [AT] fixchilds=0 +; Arthur's Wilderness Rescue +[Arthur] +renderer=gdi + ; Baldur's Gate II ; Note: 'Use 3D Acceleration' must be disabled and 'Full Screen' must be enabled in BGConfig.exe [BGMain] @@ -293,6 +306,27 @@ fixchilds=3 checkfile=.\SOUND.REZ noactivateapp=true +; Blue's 123 Time Activities +[Blues123Time] +renderer=gdi +hook=3 + +; Blue's Treasure Hunt +[Blue'sTreasureHunt-Disc1] +renderer=gdi + +; Blue's Treasure Hunt +[Blue'sTreasureHunt-Disc2] +renderer=gdi + +; Blue's Reading Time Activities +[Blue's Reading Time] +renderer=gdi + +; Blue's ArtTime Activities +[ArtTime] +renderer=gdi + ; Carmageddon [CARMA95] noactivateapp=true @@ -307,6 +341,17 @@ flipclear=true [Carma2_SW] noactivateapp=true +; Carmen Sandiego's Great Chase - NOT WORKING YET +[TIME32] +allow_wmactivate=true +renderer=gdi +adjmouse=false +width=0 +height=0 +resizable=false +maintas=false +boxing=false + ; Captain Claw [claw] adjmouse=true @@ -480,6 +525,24 @@ nonexclusive=true adjmouse=true nonexclusive=true +; ClueFinders Math Adventures 1.0 +[TCFM32] +adjmouse=false +width=0 +height=0 +resizable=false +maintas=false +boxing=false + +; ClueFinders Math Adventures 1.0 +[cfmath32] +adjmouse=false +width=0 +height=0 +resizable=false +maintas=false +boxing=false + ; Call To Power 2 [ctp2] maintas=false @@ -492,13 +555,12 @@ adjmouse=true ; Divine Divinity [div] resolutions=2 -singlecpu=false ; Dragon Throne: Battle of Red Cliffs [AdSanguo] maxgameticks=60 noactivateapp=true -limit_bltfast=true +limiter_type=2 ; Dark Reign: The Future of War [DKReign] @@ -526,6 +588,7 @@ devmode=true ; Escape Velocity Nova [EV Nova] +nonexclusive=true hook_peekmessage=true rgb555=true keytogglefullscreen=0x46 @@ -549,6 +612,43 @@ guard_lines=0 nonexclusive=true adjmouse=true +; Freddi 1 +[Freddi1] +renderer=gdi + +; Freddi Fish : The Case of the Hogfish Rustlers of Briny Gulch +[Freddihrbg] +renderer=gdi + +; Freddi Water Worries +[Water] +renderer=gdi + +; Freddi Fish +[FreddiSCS] +renderer=gdi + +; Freddi Fish +[FREDDI4] +renderer=gdi +hook=3 + +; Freddi Fish's One-Stop Fun Shop +[FreddisFunShop] +renderer=gdi + +; Freddi Fish: The Case of the Creature of Coral Cove +[freddicove] +renderer=gdi + +; Freddi Fish: The Case of the Haunted Schoolhouse +[FreddiCHSH] +renderer=gdi + +; Freddi Fish: Maze Madness +[Maze] +renderer=gdi + ; G-Police [GPOLICE] maxgameticks=60 @@ -558,34 +658,36 @@ maxgameticks=60 adjmouse=true nonexclusive=true -; Grand Theft Auto -[Grand Theft Auto] -singlecpu=false - -; Grand Theft Auto: London 1969 -[gta_uk] -singlecpu=false - -; Grand Theft Auto: London 1961 -[Gta_61] -singlecpu=false - ; Gruntz [GRUNTZ] adjmouse=true noactivateapp=true nonexclusive=true +; Jazz Jackrabbit 2 plus +[Jazz2] +keytogglefullscreen=0x08 +custom_width=800 +custom_height=450 + +; Jazz Jackrabbit 2 +[Jazz2_NonPlus] +keytogglefullscreen=0x08 +custom_width=800 +custom_height=450 + ; Heroes of Might and Magic II: The Succession Wars [HEROES2W] adjmouse=true ; Heroes of Might and Magic III [Heroes3] +renderer=opengl game_handles_close=true ; Heroes of Might and Magic III HD Mod [Heroes3 HD] +renderer=opengl game_handles_close=true ; Hard Truck: Road to Victory @@ -611,44 +713,44 @@ renderer=opengl [i76] adjmouse=true -; Infantry Online +; Infantry [infantry] -devmode=true +resolutions=2 +infantryhack=true +max_resolutions=90 + +; Infantry Steam +[FreeInfantry] resolutions=2 infantryhack=true max_resolutions=90 ; Jagged Alliance 2 [ja2] -singlecpu=false fixmousehook=true noactivateapp=true releasealt=true ; Jagged Alliance 2: Unfinished Business [JA2UB] -singlecpu=false fixmousehook=true noactivateapp=true releasealt=true ; Jagged Alliance 2: Wildfire [WF6] -singlecpu=false fixmousehook=true noactivateapp=true releasealt=true ; Jagged Alliance 2 - UC mod [JA2_UC] -singlecpu=false fixmousehook=true noactivateapp=true releasealt=true ; Jagged Alliance 2 - Vengeance Reloaded mod [JA2_Vengeance] -singlecpu=false fixmousehook=true noactivateapp=true releasealt=true @@ -677,10 +779,80 @@ vhack=true [KKND2] noactivateapp=true +; Knights and Merchants The Shattered Kingdom +[KaM_800] +limiter_type=2 +maxgameticks=60 + +; Knights and Merchants The Shattered Kingdom +[KaM_1024] +limiter_type=2 +maxgameticks=60 + +; Little Bear Kindergarten/Preschool Thinking Adventures: Parent's Progress Report +[LBPR] +adjmouse=false +width=0 +height=0 +resizable=false +maintas=false +boxing=false + +; Little Bear Kindergarten/Preschool Thinking Adventures +[LBSTART] +adjmouse=false +width=0 +height=0 +resizable=false +maintas=false +boxing=false + +; Little Bear Toddler Discovery Adventures +[LBT] +adjmouse=false +width=0 +height=0 +resizable=false +maintas=false +boxing=false + ; Lionheart [Lionheart] hook_peekmessage=true +; Madeline 1st Grade Math +[madmath1] +nonexclusive=true +no_compat_warning=true +adjmouse=false +width=0 +height=0 +resizable=false +maintas=false +boxing=false + +; Madeline 1st Grade Math: Progress Report +[madpr] +nonexclusive=true +no_compat_warning=true +adjmouse=false +width=0 +height=0 +resizable=false +maintas=false +boxing=false + +; Madeline 2nd Grade Math +[madmath2] +nonexclusive=true +no_compat_warning=true +adjmouse=false +width=0 +height=0 +resizable=false +maintas=false +boxing=false + ; Majesty Gold [Majesty] minfps=-2 @@ -706,6 +878,12 @@ releasealt=true adjmouse=true hook_peekmessage=true +; Nancy Drew (All games) +[Game/3] +checkfile=.\Nancy.cid +limiter_type=1 +maxgameticks=120 + ; Nox [NOX] checkfile=.\NOX.ICD @@ -730,10 +908,91 @@ maxgameticks=60 adjmouse=true renderer=gdi +; Pajama Sam's Games to Play on Any Day +[PJGAMES] +renderer=gdi + +; Pajama Sam +[PajamaTAL] +renderer=gdi + +; Pajama Sam: No Need to Hide When It's Dark Outside +[PajamaNHD] +renderer=gdi + +; Pajama Sam 3 +[Pajama3] +renderer=gdi + +; Pajama Sam(r): Life is Rough When You Lose Your Stuff(tm) +[PajamaLRS] +keytogglefullscreen=0x08 + +; Pajama Sam's One-Stop Fun Shop +[SamsFunShop] +renderer=gdi + +; Pajama Sam DON'T FEAR THE DARK +[pjSam] +renderer=gdi + +; Pajama Sam 3: You Are What You Eat From Your Head To Your Feet +[UKpajamaEAT] +renderer=gdi + ; Pharaoh [Pharaoh] adjmouse=true +; Putt-Putt Saves The Zoo +[PUTTZOO] +renderer=gdi +hook=3 + +; Putt-Putt's One-Stop Fun Shop +[PuttsFunShop] +renderer=gdi + +; Putt-Putt and Pep's Dog On A Stick +[DOG] +renderer=gdi + +; Putt-Putt Joins the Circus +[puttcircus] +renderer=gdi + +; Putt-Putt Enters The Race +[UKPuttRace] +renderer=gdi + +; Putt-Putt: Travels Through Time +[PuttTTT] +renderer=gdi + +; Putt-Putt and Pep's Balloon-o-Rama +[Balloon] +renderer=gdi + +; Putt-Putt Travels Through Time +[PUTTPUTTTTT] +renderer=gdi + +; Putt-Putt Joins the Circus +[puttputtjtc] +renderer=gdi + +; Putt-Putt: Pep's Birthday Surprise +[PuttsFunShop] +keytogglefullscreen=0x08 + +; Pizza Syndicate +[Pizza2] +renderer=opengl + +; Pizza Syndicate - Mehr Biss (Mission CD) +[Pizza_Mission] +renderer=opengl + ; Pax Imperia [Pax Imperia] nonexclusive=true @@ -742,10 +1001,45 @@ nonexclusive=true [RT2] adjmouse=true +; Reader Rabbit Thinking Ages 4-6 (US) +[rrta32] +adjmouse=false +width=0 +height=0 +resizable=false +maintas=false +boxing=false + +; Reader Rabbit Reading Ages 4-6 +[rrirjw32] +renderer=gdi +adjmouse=false +width=0 +height=0 +resizable=false +maintas=false +boxing=false + +; Reader Rabbit Reading Ages 6-9 +[irj2w32] +renderer=gdi +adjmouse=false +width=0 +height=0 +resizable=false +maintas=false +boxing=false + ; ROAD RASH [RoadRash] adjmouse=true -fixchilds=1 +nonexclusive=true + +; Scooby-Doo(TM), Case File #1 The Glowing Bug Man - NOT WORKING YET +[Case File #1] +windowed=true +nonexclusive=true +fake_mode=640x480x32 ; Sim Copter [SimCopter] @@ -781,6 +1075,34 @@ game_handles_close=true [Rangers] hook_peekmessage=true +; SPYFox: Hold the Mustard +[mustard] +renderer=gdi + +; SPY Fox: Some Assembly Required +[Spyfox2] +renderer=gdi + +; SPY Fox in Dry Cereal (2008) +[SpyFox] +renderer=gdi + +; SPY Fox in Dry Cereal (2001) +[SPYFOXDC] +renderer=gdi + +; SPY Fox : Some Assembly Required +[SPYFOXSR] +renderer=gdi + +; SPY Fox: Operation Ozone +[spyozon] +renderer=gdi + +; SPY Fox: Operation Ozone +[spyfoxozu] +renderer=gdi + ; Stronghold Crusader HD [Stronghold Crusader] resolutions=2 @@ -818,29 +1140,42 @@ boxing=false [TotalA] max_resolutions=32 lock_surfaces=true -singlecpu=false ; Total Annihilation Replay Viewer (Unofficial Beta Patch v3.9.02) [Viewer] max_resolutions=32 lock_surfaces=true -singlecpu=false ; Total Annihilation: Kingdoms [Kingdoms] game_handles_close=true max_resolutions=32 +; The X-Files DVD +[XFiles] +windowed=true +fullscreen=true +toggle_borderless=true + +; The Learning Company Launcher +[TLCLauncher] +tlc_hack=true +adjmouse=false +width=0 +height=0 +resizable=false +maintas=false +boxing=false + ; Three Kingdoms: Fate of the Dragon [sanguo] maxgameticks=60 noactivateapp=true -limit_bltfast=true +limiter_type=2 ; RollerCoaster Tycoon [rct] no_dinput_hook=true -singlecpu=false maxfps=0 adjmouse=true @@ -876,7 +1211,7 @@ adjmouse=true ; Vermeer [vermeer] adjmouse=true -vermeer_hack=true +fake_mode=640x480x32 ; Wizardry 8 [Wiz8] @@ -884,6 +1219,13 @@ fixmousehook=true noactivateapp=true releasealt=true +; Worms 2 +[worms2] +vhack=true +flipclear=true +game_handles_close=true +center_cursor_fix=true + ; Worms Armageddon [WA] adjmouse=true diff --git a/app/src/main/assets/dxwrapper/cnc-ddraw-6.6/ddraw.tzst b/app/src/main/assets/dxwrapper/cnc-ddraw-6.6/ddraw.tzst new file mode 100644 index 0000000..6d03ec5 Binary files /dev/null and b/app/src/main/assets/dxwrapper/cnc-ddraw-6.6/ddraw.tzst differ diff --git a/app/src/main/assets/dxwrapper/cnc-ddraw/ddraw.tzst b/app/src/main/assets/dxwrapper/cnc-ddraw/ddraw.tzst deleted file mode 100644 index 92975eb..0000000 Binary files a/app/src/main/assets/dxwrapper/cnc-ddraw/ddraw.tzst and /dev/null differ diff --git a/app/src/main/assets/dxwrapper/d8vk.tzst b/app/src/main/assets/dxwrapper/d8vk-1.0.tzst similarity index 100% rename from app/src/main/assets/dxwrapper/d8vk.tzst rename to app/src/main/assets/dxwrapper/d8vk-1.0.tzst diff --git a/app/src/main/assets/dxwrapper/dxvk-1.5.5.tzst b/app/src/main/assets/dxwrapper/dxvk-1.5.5.tzst deleted file mode 100644 index e900429..0000000 Binary files a/app/src/main/assets/dxwrapper/dxvk-1.5.5.tzst and /dev/null differ diff --git a/app/src/main/assets/dxwrapper/vkd3d-2.12.tzst b/app/src/main/assets/dxwrapper/vkd3d-2.12.tzst new file mode 100644 index 0000000..8480298 Binary files /dev/null and b/app/src/main/assets/dxwrapper/vkd3d-2.12.tzst differ diff --git a/app/src/main/assets/gpu_cards.json b/app/src/main/assets/gpu_cards.json new file mode 100644 index 0000000..ad7a56f --- /dev/null +++ b/app/src/main/assets/gpu_cards.json @@ -0,0 +1 @@ +[{"name":"NVIDIA RIVA 128","deviceID":24,"vendorID":4318},{"name":"NVIDIA RIVA TNT","deviceID":32,"vendorID":4318},{"name":"NVIDIA RIVA TNT2\/TNT2 Pro","deviceID":40,"vendorID":4318},{"name":"NVIDIA GeForce 256","deviceID":256,"vendorID":4318},{"name":"NVIDIA GeForce2 GTS\/GeForce2 Pro","deviceID":336,"vendorID":4318},{"name":"NVIDIA GeForce2 MX\/MX 400","deviceID":272,"vendorID":4318},{"name":"NVIDIA GeForce3","deviceID":512,"vendorID":4318},{"name":"NVIDIA GeForce4 MX 460","deviceID":368,"vendorID":4318},{"name":"NVIDIA GeForce4 Ti 4200","deviceID":595,"vendorID":4318},{"name":"NVIDIA GeForce FX 5200","deviceID":800,"vendorID":4318},{"name":"NVIDIA GeForce FX 5600","deviceID":786,"vendorID":4318},{"name":"NVIDIA GeForce FX 5800","deviceID":770,"vendorID":4318},{"name":"NVIDIA GeForce 6200","deviceID":335,"vendorID":4318},{"name":"NVIDIA GeForce 6600 GT","deviceID":320,"vendorID":4318},{"name":"NVIDIA GeForce 6800","deviceID":65,"vendorID":4318},{"name":"NVIDIA GeForce Go 7300","deviceID":2026952880896,"vendorID":4318},{"name":"NVIDIA GeForce Go 7400","deviceID":472,"vendorID":4318},{"name":"NVIDIA GeForce 7600 GT","deviceID":913,"vendorID":4318},{"name":"NVIDIA GeForce 7800 GT","deviceID":146,"vendorID":4318},{"name":"NVIDIA GeForce 8200","deviceID":9113598691403,"vendorID":4318},{"name":"NVIDIA GeForce 8300 GS","deviceID":1059,"vendorID":4318},{"name":"NVIDIA GeForce 8400 GS","deviceID":1028,"vendorID":4318},{"name":"NVIDIA GeForce 8500 GT","deviceID":1057,"vendorID":4318},{"name":"NVIDIA GeForce 8600 GT","deviceID":1026,"vendorID":4318},{"name":"NVIDIA GeForce 8600M GT","deviceID":1031,"vendorID":4318},{"name":"NVIDIA GeForce 8800 GTS","deviceID":403,"vendorID":4318},{"name":"NVIDIA GeForce 8800 GTX","deviceID":401,"vendorID":4318},{"name":"NVIDIA GeForce 9200","deviceID":2157,"vendorID":4318},{"name":"NVIDIA GeForce 9300","deviceID":2156,"vendorID":4318},{"name":"NVIDIA GeForce 9400M","deviceID":2147,"vendorID":4318},{"name":"NVIDIA GeForce 9400 GT","deviceID":1068,"vendorID":4318},{"name":"NVIDIA GeForce 9500 GT","deviceID":1600,"vendorID":4318},{"name":"NVIDIA GeForce 9600 GT","deviceID":1570,"vendorID":4318},{"name":"NVIDIA GeForce 9700M GT","deviceID":1610,"vendorID":4318},{"name":"NVIDIA GeForce 9800 GT","deviceID":1556,"vendorID":4318},{"name":"NVIDIA GeForce 210","deviceID":2595,"vendorID":4318},{"name":"NVIDIA GeForce GT 220","deviceID":2592,"vendorID":4318},{"name":"NVIDIA GeForce GT 240","deviceID":3235,"vendorID":4318},{"name":"NVIDIA GeForce GTS 250","deviceID":1557,"vendorID":4318},{"name":"NVIDIA GeForce GTX 260","deviceID":1506,"vendorID":4318},{"name":"NVIDIA GeForce GTX 275","deviceID":1510,"vendorID":4318},{"name":"NVIDIA GeForce GTX 280","deviceID":1505,"vendorID":4318},{"name":"NVIDIA GeForce 315M","deviceID":2682,"vendorID":4318},{"name":"NVIDIA GeForce 320M","deviceID":2211,"vendorID":4318},{"name":"NVIDIA GeForce GT 320M","deviceID":2605,"vendorID":4318},{"name":"NVIDIA GeForce GT 325M","deviceID":2613,"vendorID":4318},{"name":"NVIDIA GeForce GT 330","deviceID":3232,"vendorID":4318},{"name":"NVIDIA GeForce GTS 350M","deviceID":3248,"vendorID":4318},{"name":"NVIDIA GeForce 410M","deviceID":4181,"vendorID":4318},{"name":"NVIDIA GeForce GT 420","deviceID":3554,"vendorID":4318},{"name":"NVIDIA GeForce GT 425M","deviceID":3568,"vendorID":4318},{"name":"NVIDIA GeForce GT 430","deviceID":3553,"vendorID":4318},{"name":"NVIDIA GeForce GT 440","deviceID":3552,"vendorID":4318},{"name":"NVIDIA GeForce GTS 450","deviceID":3524,"vendorID":4318},{"name":"NVIDIA GeForce GTX 460","deviceID":3618,"vendorID":4318},{"name":"NVIDIA GeForce GTX 460M","deviceID":3537,"vendorID":4318},{"name":"NVIDIA GeForce GTX 465","deviceID":1732,"vendorID":4318},{"name":"NVIDIA GeForce GTX 470","deviceID":1741,"vendorID":4318},{"name":"NVIDIA GeForce GTX 480","deviceID":1728,"vendorID":4318},{"name":"NVIDIA GeForce GT 520","deviceID":4160,"vendorID":4318},{"name":"NVIDIA GeForce GT 525M","deviceID":3564,"vendorID":4318},{"name":"NVIDIA GeForce GT 540M","deviceID":3572,"vendorID":4318},{"name":"NVIDIA GeForce GTX 550 Ti","deviceID":4676,"vendorID":4318},{"name":"NVIDIA GeForce GT 555M","deviceID":1208,"vendorID":4318},{"name":"NVIDIA GeForce GTX 560 Ti","deviceID":4608,"vendorID":4318},{"name":"NVIDIA GeForce GTX 560M","deviceID":4689,"vendorID":4318},{"name":"NVIDIA GeForce GTX 560","deviceID":4609,"vendorID":4318},{"name":"NVIDIA GeForce GTX 570","deviceID":4225,"vendorID":4318},{"name":"NVIDIA GeForce GTX 580","deviceID":4224,"vendorID":4318},{"name":"NVIDIA GeForce GT 610","deviceID":4170,"vendorID":4318},{"name":"NVIDIA GeForce GT 630","deviceID":3840,"vendorID":4318},{"name":"NVIDIA GeForce GT 630M","deviceID":3561,"vendorID":4318},{"name":"NVIDIA GeForce GT 640","deviceID":4033,"vendorID":4318},{"name":"NVIDIA GeForce GT 640M","deviceID":4050,"vendorID":4318},{"name":"NVIDIA GeForce GT 650M","deviceID":4049,"vendorID":4318},{"name":"NVIDIA GeForce GTX 650","deviceID":4038,"vendorID":4318},{"name":"NVIDIA GeForce GTX 650 Ti","deviceID":4550,"vendorID":4318},{"name":"NVIDIA GeForce GTX 660","deviceID":4544,"vendorID":4318},{"name":"NVIDIA GeForce GTX 660M","deviceID":4052,"vendorID":4318},{"name":"NVIDIA GeForce GTX 660 Ti","deviceID":4483,"vendorID":4318},{"name":"NVIDIA GeForce GTX 670","deviceID":4489,"vendorID":4318},{"name":"NVIDIA GeForce GTX 670MX","deviceID":4513,"vendorID":4318},{"name":"NVIDIA GeForce GTX 675MX","deviceID":4519,"vendorID":4318},{"name":"NVIDIA GeForce GTX 675MX","deviceID":4514,"vendorID":4318},{"name":"NVIDIA GeForce GTX 680","deviceID":4480,"vendorID":4318},{"name":"NVIDIA GeForce GTX 690","deviceID":4488,"vendorID":4318},{"name":"NVIDIA GeForce GT 720","deviceID":4747,"vendorID":4318},{"name":"NVIDIA GeForce GT 730","deviceID":4743,"vendorID":4318},{"name":"NVIDIA GeForce GT 730M","deviceID":4065,"vendorID":4318},{"name":"NVIDIA GeForce GT 740M","deviceID":4754,"vendorID":4318},{"name":"NVIDIA GeForce GT 750M","deviceID":4073,"vendorID":4318},{"name":"NVIDIA GeForce GT 755M","deviceID":4045,"vendorID":4318},{"name":"NVIDIA GeForce GTX 750","deviceID":4993,"vendorID":4318},{"name":"NVIDIA GeForce GTX 750 Ti","deviceID":4992,"vendorID":4318},{"name":"NVIDIA GeForce GTX 760","deviceID":4487,"vendorID":4318},{"name":"NVIDIA GeForce GTX 760 Ti","deviceID":4499,"vendorID":4318},{"name":"NVIDIA GeForce GTX 765M","deviceID":4578,"vendorID":4318},{"name":"NVIDIA GeForce GTX 770M","deviceID":4576,"vendorID":4318},{"name":"NVIDIA GeForce GTX 770","deviceID":4484,"vendorID":4318},{"name":"NVIDIA GeForce GTX 775M","deviceID":4509,"vendorID":4318},{"name":"NVIDIA GeForce GTX 780","deviceID":4100,"vendorID":4318},{"name":"NVIDIA GeForce GTX 780M","deviceID":4510,"vendorID":4318},{"name":"NVIDIA GeForce GTX 780 Ti","deviceID":4106,"vendorID":4318},{"name":"NVIDIA GeForce GTX TITAN","deviceID":4101,"vendorID":4318},{"name":"NVIDIA GeForce GTX TITAN Black","deviceID":4108,"vendorID":4318},{"name":"NVIDIA GeForce GTX TITAN X","deviceID":6082,"vendorID":4318},{"name":"NVIDIA GeForce GTX TITAN Z","deviceID":4097,"vendorID":4318},{"name":"NVIDIA GeForce 820M","deviceID":4077,"vendorID":4318},{"name":"NVIDIA GeForce 830M","deviceID":4928,"vendorID":4318},{"name":"NVIDIA GeForce 840M","deviceID":4929,"vendorID":4318},{"name":"NVIDIA GeForce 845M","deviceID":4932,"vendorID":4318},{"name":"NVIDIA GeForce GTX 850M","deviceID":5009,"vendorID":4318},{"name":"NVIDIA GeForce GTX 860M","deviceID":21521759211930,"vendorID":4318},{"name":"NVIDIA GeForce GTX 870M","deviceID":4505,"vendorID":4318},{"name":"NVIDIA GeForce GTX 880M","deviceID":4504,"vendorID":4318},{"name":"NVIDIA GeForce 940M","deviceID":4935,"vendorID":4318},{"name":"NVIDIA GeForce GTX 950","deviceID":5122,"vendorID":4318},{"name":"NVIDIA GeForce GTX 950M","deviceID":5018,"vendorID":4318},{"name":"NVIDIA GeForce GTX 960","deviceID":5121,"vendorID":4318},{"name":"NVIDIA GeForce GTX 960M","deviceID":5019,"vendorID":4318},{"name":"NVIDIA GeForce GTX 970","deviceID":5058,"vendorID":4318},{"name":"NVIDIA GeForce GTX 970M","deviceID":5080,"vendorID":4318},{"name":"NVIDIA GeForce GTX 980","deviceID":5056,"vendorID":4318},{"name":"NVIDIA GeForce GTX 980 Ti","deviceID":6088,"vendorID":4318},{"name":"NVIDIA GeForce GT 1030","deviceID":7425,"vendorID":4318},{"name":"NVIDIA GeForce GTX 1050","deviceID":7297,"vendorID":4318},{"name":"NVIDIA GeForce GTX 1050 Ti","deviceID":7298,"vendorID":4318},{"name":"NVIDIA GeForce GTX 1060 3GB","deviceID":7170,"vendorID":4318},{"name":"NVIDIA GeForce GTX 1060","deviceID":7171,"vendorID":4318},{"name":"NVIDIA GeForce GTX 1060M","deviceID":7200,"vendorID":4318},{"name":"NVIDIA GeForce GTX 1070","deviceID":7041,"vendorID":4318},{"name":"NVIDIA GeForce GTX 1080","deviceID":7040,"vendorID":4318},{"name":"NVIDIA GeForce GTX 1080M","deviceID":7136,"vendorID":4318},{"name":"NVIDIA GeForce GTX 1080 Ti","deviceID":6918,"vendorID":4318},{"name":"NVIDIA TITAN X (Pascal)","deviceID":6912,"vendorID":4318},{"name":"NVIDIA TITAN V","deviceID":7553,"vendorID":4318},{"name":"NVIDIA GeForce GTX 1650 SUPER","deviceID":8583,"vendorID":4318},{"name":"NVIDIA GeForce GTX 1660 SUPER","deviceID":8644,"vendorID":4318},{"name":"NVIDIA GeForce GTX 1660 Ti","deviceID":8578,"vendorID":4318},{"name":"NVIDIA GeForce RTX 2060","deviceID":7944,"vendorID":4318},{"name":"NVIDIA GeForce RTX 2070","deviceID":7943,"vendorID":4318},{"name":"NVIDIA GeForce RTX 2080","deviceID":7815,"vendorID":4318},{"name":"NVIDIA GeForce RTX 2080 Ti","deviceID":7687,"vendorID":4318},{"name":"NVIDIA GeForce RTX 3070","deviceID":9373,"vendorID":4318},{"name":"NVIDIA Tesla T4","deviceID":7864,"vendorID":4318},{"name":"NVIDIA Ampere A10","deviceID":8758,"vendorID":4318},{"name":"ATI Rage Fury","deviceID":21062,"vendorID":4098},{"name":"ATI RADEON 7200 SERIES","deviceID":20804,"vendorID":4098},{"name":"ATI RADEON 8500 SERIES","deviceID":20812,"vendorID":4098},{"name":"ATI Radeon 9500","deviceID":16708,"vendorID":4098},{"name":"ATI RADEON XPRESS 200M Series","deviceID":22869,"vendorID":4098},{"name":"ATI Radeon X700 SE","deviceID":24140,"vendorID":4098},{"name":"ATI Radeon X1600 Series","deviceID":29122,"vendorID":4098},{"name":"ATI Mobility Radeon HD 2350","deviceID":38087,"vendorID":4098},{"name":"ATI Mobility Radeon HD 2600","deviceID":38273,"vendorID":4098},{"name":"ATI Radeon HD 2900 XT","deviceID":37888,"vendorID":4098},{"name":"ATI Radeon HD 3200 Graphics","deviceID":38432,"vendorID":4098},{"name":"ATI Radeon HD 3850 AGP","deviceID":38165,"vendorID":4098},{"name":"ATI Mobility Radeon HD 4200","deviceID":38674,"vendorID":4098},{"name":"ATI Radeon HD 4350","deviceID":38223,"vendorID":4098},{"name":"ATI Radeon HD 4600 Series","deviceID":38037,"vendorID":4098},{"name":"ATI Radeon HD 4700 Series","deviceID":37966,"vendorID":4098},{"name":"ATI Radeon HD 4800 Series","deviceID":37964,"vendorID":4098},{"name":"ATI Radeon HD 5400 Series","deviceID":26873,"vendorID":4098},{"name":"ATI Radeon HD 5600 Series","deviceID":26840,"vendorID":4098},{"name":"ATI Radeon HD 5700 Series","deviceID":26814,"vendorID":4098},{"name":"ATI Radeon HD 5800 Series","deviceID":26776,"vendorID":4098},{"name":"ATI Radeon HD 5900 Series","deviceID":26780,"vendorID":4098},{"name":"AMD Radeon HD 6300 series Graphics","deviceID":38915,"vendorID":4098},{"name":"AMD Radeon HD 6400 Series","deviceID":26480,"vendorID":4098},{"name":"AMD Radeon HD 6410D","deviceID":38468,"vendorID":4098},{"name":"AMD Radeon HD 6480G","deviceID":38472,"vendorID":4098},{"name":"AMD Radeon HD 6490M","deviceID":26464,"vendorID":4098},{"name":"AMD Radeon HD 6550D","deviceID":38464,"vendorID":4098},{"name":"AMD Radeon HD 6600 Series","deviceID":26456,"vendorID":4098},{"name":"AMD Radeon HD 6600M Series","deviceID":26433,"vendorID":4098},{"name":"AMD Radeon HD 6700 Series","deviceID":26810,"vendorID":4098},{"name":"AMD Radeon HD 6800 Series","deviceID":26425,"vendorID":4098},{"name":"AMD Radeon HD 6900 Series","deviceID":26393,"vendorID":4098},{"name":"AMD Radeon HD 7660D","deviceID":39169,"vendorID":4098},{"name":"AMD Radeon HD 7700 Series","deviceID":26685,"vendorID":4098},{"name":"AMD Radeon HD 7800 Series","deviceID":26649,"vendorID":4098},{"name":"AMD Radeon HD 7870 Series","deviceID":26648,"vendorID":4098},{"name":"AMD Radeon HD 7900 Series","deviceID":26522,"vendorID":4098},{"name":"AMD Radeon HD 8600M Series","deviceID":26208,"vendorID":4098},{"name":"AMD Radeon HD 8670","deviceID":26128,"vendorID":4098},{"name":"AMD Radeon HD 8770","deviceID":26204,"vendorID":4098},{"name":"AMD Radeon HD 8400 \/ R3 Series","deviceID":38960,"vendorID":4098},{"name":"AMD Radeon(TM) R7 Graphics","deviceID":4879,"vendorID":4098},{"name":"AMD Radeon R9 285","deviceID":26937,"vendorID":4098},{"name":"AMD Radeon R9 290","deviceID":26545,"vendorID":4098},{"name":"AMD Radeon R9 290X","deviceID":26544,"vendorID":4098},{"name":"AMD Radeon (TM) R9 Fury Series","deviceID":29440,"vendorID":4098},{"name":"AMD Radeon R9 M370X","deviceID":26657,"vendorID":4098},{"name":"AMD Radeon R9 M380","deviceID":26183,"vendorID":4098},{"name":"AMD Radeon R9 M395X","deviceID":26912,"vendorID":4098},{"name":"Radeon(TM) RX 460 Graphics","deviceID":26607,"vendorID":4098},{"name":"Radeon (TM) RX 480 Graphics","deviceID":26591,"vendorID":4098},{"name":"Radeon RX Vega","deviceID":26751,"vendorID":4098},{"name":"Radeon Pro Vega 20","deviceID":27055,"vendorID":4098},{"name":"AMD Radeon(TM) Vega 10 Mobile Graphics","deviceID":5597,"vendorID":4098},{"name":"Radeon RX Vega 20","deviceID":26287,"vendorID":4098},{"name":"Radeon RX 5700 \/ 5700 XT","deviceID":29471,"vendorID":4098},{"name":"Radeon RX 5500M","deviceID":29504,"vendorID":4098},{"name":"Radeon RX 6800\/6800 XT \/ 6900 XT","deviceID":29631,"vendorID":4098},{"name":"Radeon Pro V620","deviceID":29601,"vendorID":4098},{"name":"Radeon Pro V620 VF","deviceID":29614,"vendorID":4098},{"name":"AMD VANGOGH","deviceID":5695,"vendorID":4098},{"name":"AMD Radeon(TM) Graphics","deviceID":5710,"vendorID":4098},{"name":"Intel(R) 82830M Graphics Controller","deviceID":13687,"vendorID":32902},{"name":"Intel(R) 82852\/82855 GM\/GME Graphics Controller","deviceID":13698,"vendorID":32902},{"name":"Intel(R) 845G","deviceID":9570,"vendorID":32902},{"name":"Intel(R) 82865G Graphics Controller","deviceID":9586,"vendorID":32902},{"name":"Intel(R) 82915G\/GV\/910GL Express Chipset Family","deviceID":9602,"vendorID":32902},{"name":"Intel(R) E7221G","deviceID":9610,"vendorID":32902},{"name":"Mobile Intel(R) 915GM\/GMS","deviceID":9618,"vendorID":32902},{"name":"Intel(R) 945G","deviceID":10098,"vendorID":32902},{"name":"Mobile Intel(R) 945GM Express Chipset Family","deviceID":10146,"vendorID":32902},{"name":"Intel(R) 945GME","deviceID":10158,"vendorID":32902},{"name":"Intel(R) Q35","deviceID":10674,"vendorID":32902},{"name":"Intel(R) G33","deviceID":10690,"vendorID":32902},{"name":"Intel(R) Q33","deviceID":10706,"vendorID":32902},{"name":"Intel(R) IGD","deviceID":40961,"vendorID":32902},{"name":"Intel(R) IGD","deviceID":40977,"vendorID":32902},{"name":"Intel(R) 965Q","deviceID":10642,"vendorID":32902},{"name":"Intel(R) 965G","deviceID":10626,"vendorID":32902},{"name":"Intel(R) 946GZ","deviceID":10610,"vendorID":32902},{"name":"Mobile Intel(R) 965 Express Chipset Family","deviceID":10754,"vendorID":32902},{"name":"Intel(R) 965GME","deviceID":10770,"vendorID":32902},{"name":"Mobile Intel(R) GM45 Express Chipset Family","deviceID":10818,"vendorID":32902},{"name":"Intel(R) Integrated Graphics Device","deviceID":11778,"vendorID":32902},{"name":"Intel(R) G45\/G43","deviceID":11810,"vendorID":32902},{"name":"Intel(R) Q45\/Q43","deviceID":11794,"vendorID":32902},{"name":"Intel(R) G41","deviceID":11826,"vendorID":32902},{"name":"Intel(R) B43","deviceID":11922,"vendorID":32902},{"name":"Intel(R) HD Graphics","deviceID":66,"vendorID":32902},{"name":"Intel(R) HD Graphics","deviceID":70,"vendorID":32902},{"name":"Intel(R) HD Graphics 3000","deviceID":290,"vendorID":32902},{"name":"Intel(R) HD Graphics 3000","deviceID":294,"vendorID":32902},{"name":"Intel(R) HD Graphics Family","deviceID":266,"vendorID":32902},{"name":"Intel(R) HD Graphics 4000","deviceID":354,"vendorID":32902},{"name":"Intel(R) HD Graphics 4000","deviceID":358,"vendorID":32902},{"name":"Intel(R) HD Graphics Family","deviceID":346,"vendorID":32902},{"name":"Intel(R) HD Graphics 4600","deviceID":1042,"vendorID":32902},{"name":"Intel(R) HD Graphics 4600","deviceID":1046,"vendorID":32902},{"name":"Intel(R) HD Graphics 5000","deviceID":2598,"vendorID":32902},{"name":"Intel(R) HD Graphics 5000","deviceID":1058,"vendorID":32902},{"name":"Intel(R) Iris(TM) Graphics 5100","deviceID":2594,"vendorID":32902},{"name":"Intel(R) Iris(TM) Graphics 5100","deviceID":2602,"vendorID":32902},{"name":"Intel(R) Iris(TM) Graphics 5100","deviceID":2603,"vendorID":32902},{"name":"Intel(R) Iris(TM) Graphics 5100","deviceID":2606,"vendorID":32902},{"name":"Intel(R) Iris(TM) Pro Graphics 5200","deviceID":3362,"vendorID":32902},{"name":"Intel(R) Iris(TM) Pro Graphics 5200","deviceID":3366,"vendorID":32902},{"name":"Intel(R) Iris(TM) Pro Graphics 5200","deviceID":3370,"vendorID":32902},{"name":"Intel(R) Iris(TM) Pro Graphics 5200","deviceID":3371,"vendorID":32902},{"name":"Intel(R) Iris(TM) Pro Graphics 5200","deviceID":3374,"vendorID":32902},{"name":"Intel(R) Iris(TM) Pro Graphics 5200","deviceID":3106,"vendorID":32902},{"name":"Intel(R) HD Graphics 5300","deviceID":5662,"vendorID":32902},{"name":"Intel(R) HD Graphics 5500","deviceID":5654,"vendorID":32902},{"name":"Intel(R) HD Graphics 5600","deviceID":5650,"vendorID":32902},{"name":"Intel(R) HD Graphics 6000","deviceID":5670,"vendorID":32902},{"name":"Intel(R) Iris(TM) Graphics 6100","deviceID":5675,"vendorID":32902},{"name":"Intel(R) Iris(TM) Pro Graphics 6200","deviceID":5666,"vendorID":32902},{"name":"Intel(R) Iris(TM) Pro Graphics P6300","deviceID":5674,"vendorID":32902},{"name":"Intel(R) HD Graphics 510","deviceID":6402,"vendorID":32902},{"name":"Intel(R) HD Graphics 510","deviceID":6406,"vendorID":32902},{"name":"Intel(R) HD Graphics 510","deviceID":6411,"vendorID":32902},{"name":"Intel(R) HD Graphics 515","deviceID":6430,"vendorID":32902},{"name":"Intel(R) HD Graphics 520","deviceID":6422,"vendorID":32902},{"name":"Intel(R) HD Graphics 520","deviceID":6433,"vendorID":32902},{"name":"Intel(R) HD Graphics 530","deviceID":6418,"vendorID":32902},{"name":"Intel(R) HD Graphics 530","deviceID":6427,"vendorID":32902},{"name":"Intel(R) HD Graphics P530","deviceID":6429,"vendorID":32902},{"name":"Intel(R) Iris(TM) Graphics 540","deviceID":6438,"vendorID":32902},{"name":"Intel(R) Iris(TM) Graphics 550","deviceID":6439,"vendorID":32902},{"name":"Intel(R) Iris(TM) Graphics 555","deviceID":6443,"vendorID":32902},{"name":"Intel(R) Iris(TM) Graphics P555","deviceID":6445,"vendorID":32902},{"name":"Intel(R) Iris(TM) Pro Graphics 580","deviceID":6450,"vendorID":32902},{"name":"Intel(R) Iris(TM) Pro Graphics 580","deviceID":6459,"vendorID":32902},{"name":"Intel(R) Iris(TM) Pro Graphics P580","deviceID":6458,"vendorID":32902},{"name":"Intel(R) Iris(TM) Pro Graphics P580","deviceID":6461,"vendorID":32902},{"name":"Intel(R) UHD Graphics 617","deviceID":34752,"vendorID":32902},{"name":"Intel(R) UHD Graphics 620","deviceID":16032,"vendorID":32902},{"name":"Intel(R) HD Graphics 615","deviceID":22814,"vendorID":32902},{"name":"Intel(R) HD Graphics 620","deviceID":22806,"vendorID":32902},{"name":"Intel(R) HD Graphics 630","deviceID":22802,"vendorID":32902},{"name":"Intel(R) HD Graphics 630","deviceID":22811,"vendorID":32902},{"name":"Intel(R) UHD Graphics 630","deviceID":16027,"vendorID":32902},{"name":"Intel(R) UHD Graphics 630","deviceID":16017,"vendorID":32902}] \ No newline at end of file diff --git a/app/src/main/assets/gpu_names.json b/app/src/main/assets/gpu_names.json deleted file mode 100644 index dab847d..0000000 --- a/app/src/main/assets/gpu_names.json +++ /dev/null @@ -1,57 +0,0 @@ -[ - { - "name" : "6800GT", - "deviceID" : 65, - "vendorID" : 4318 - }, - { - "name" : "7800GT", - "deviceID" : 146, - "vendorID" : 4318 - }, - { - "name" : "8800GT", - "deviceID" : 401, - "vendorID" : 4318 - }, - { - "name" : "9600GT", - "deviceID" : 1570, - "vendorID" : 4318 - }, - { - "name" : "9800GT", - "deviceID" : 1556, - "vendorID" : 4318 - }, - { - "name" : "GeForce 2", - "deviceID" : 272, - "vendorID" : 4318 - }, - { - "name" : "GeForce 3", - "deviceID" : 512, - "vendorID" : 4318 - }, - { - "name" : "GeForce 256", - "deviceID" : 256, - "vendorID" : 4318 - }, - { - "name" : "GTX 470", - "deviceID" : 1741, - "vendorID" : 4318 - }, - { - "name" : "GTX 1070", - "deviceID" : 7041, - "vendorID" : 4318 - }, - { - "name" : "Intel HD 4000", - "deviceID" : 358, - "vendorID" : 32902 - } -] \ No newline at end of file diff --git a/app/src/main/assets/graphics_driver/turnip-23.0.0.tzst b/app/src/main/assets/graphics_driver/turnip-23.0.0.tzst deleted file mode 100644 index 235f455..0000000 Binary files a/app/src/main/assets/graphics_driver/turnip-23.0.0.tzst and /dev/null differ diff --git a/app/src/main/assets/graphics_driver/turnip-24.1.0.tzst b/app/src/main/assets/graphics_driver/turnip-24.1.0.tzst index 8f77c91..6603aaa 100644 Binary files a/app/src/main/assets/graphics_driver/turnip-24.1.0.tzst and b/app/src/main/assets/graphics_driver/turnip-24.1.0.tzst differ diff --git a/app/src/main/assets/graphics_driver/virgl-22.1.7.tzst b/app/src/main/assets/graphics_driver/virgl-22.1.7.tzst deleted file mode 100644 index a2f4c9e..0000000 Binary files a/app/src/main/assets/graphics_driver/virgl-22.1.7.tzst and /dev/null differ diff --git a/app/src/main/assets/graphics_driver/virgl-23.1.9.tzst b/app/src/main/assets/graphics_driver/virgl-23.1.9.tzst new file mode 100644 index 0000000..1961439 Binary files /dev/null and b/app/src/main/assets/graphics_driver/virgl-23.1.9.tzst differ diff --git a/app/src/main/assets/graphics_driver/zink-22.2.2.tzst b/app/src/main/assets/graphics_driver/zink-22.2.2.tzst deleted file mode 100644 index da1ecf5..0000000 Binary files a/app/src/main/assets/graphics_driver/zink-22.2.2.tzst and /dev/null differ diff --git a/app/src/main/assets/graphics_driver/zink-22.2.5.tzst b/app/src/main/assets/graphics_driver/zink-22.2.5.tzst new file mode 100644 index 0000000..8c6c9fe Binary files /dev/null and b/app/src/main/assets/graphics_driver/zink-22.2.5.tzst differ diff --git a/app/src/main/assets/imagefs.txz b/app/src/main/assets/imagefs.txz index f8678a5..ebff812 100644 --- a/app/src/main/assets/imagefs.txz +++ b/app/src/main/assets/imagefs.txz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:68491a479524185489abae06045bf9f9d0018b57ec7bd7d26faeb58edcd2f1b5 -size 167532776 +oid sha256:00a283c7d3e9ed2399b8d73175f92a3932b65e86925f7a5bd0fe0d4736e81e8a +size 165829076 diff --git a/app/src/main/assets/imagefs_patches.tzst b/app/src/main/assets/imagefs_patches.tzst index 463ed2f..f2b6051 100644 Binary files a/app/src/main/assets/imagefs_patches.tzst and b/app/src/main/assets/imagefs_patches.tzst differ diff --git a/app/src/main/assets/inputcontrols/profiles/controls-1.icp b/app/src/main/assets/inputcontrols/profiles/controls-1.icp index f1ad644..9edb7f0 100644 --- a/app/src/main/assets/inputcontrols/profiles/controls-1.icp +++ b/app/src/main/assets/inputcontrols/profiles/controls-1.icp @@ -1 +1 @@ -{"id":1,"name":"RTS","cursorSpeed":1,"elements":[{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_DEL","NONE","NONE","NONE"],"scale":1,"x":0.12745098769664764,"y":0.35555556416511536,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_DOWN","NONE","NONE","NONE"],"scale":1,"x":0.12745098769664764,"y":0.7555555701255798,"toggleSwitch":false,"text":"","iconId":5},{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_RIGHT","NONE","NONE","NONE"],"scale":1,"x":0.12745098769664764,"y":0.6222222447395325,"toggleSwitch":false,"text":"","iconId":4},{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_LEFT","NONE","NONE","NONE"],"scale":1,"x":0.06862745434045792,"y":0.6222222447395325,"toggleSwitch":false,"text":"","iconId":2},{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_UP","NONE","NONE","NONE"],"scale":1,"x":0.12745098769664764,"y":0.4888888895511627,"toggleSwitch":false,"text":"","iconId":3},{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_ESC","NONE","NONE","NONE"],"scale":1,"x":0.06862745434045792,"y":0.35555556416511536,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"SQUARE","bindings":["MOUSE_RIGHT_BUTTON","NONE","NONE","NONE"],"scale":1,"x":0.8721405267715454,"y":0.7555555701255798,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_TAB","NONE","NONE","NONE"],"scale":1,"x":0.06862745434045792,"y":0.4888888895511627,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_SHIFT","NONE","NONE","NONE"],"scale":1,"x":0.06862745434045792,"y":0.7555555701255798,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_CTRL","NONE","NONE","NONE"],"scale":1,"x":0.06862745434045792,"y":0.8888888955116272,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_ALT","NONE","NONE","NONE"],"scale":1,"x":0.12745098769664764,"y":0.8888888955116272,"toggleSwitch":false,"text":"","iconId":0},{"type":"RANGE_BUTTON","shape":"CIRCLE","bindings":["NONE","NONE","NONE","NONE"],"scale":1,"x":0.1568627506494522,"y":0.08888889104127884,"toggleSwitch":false,"text":"","iconId":0,"range":"FROM_0_TO_9"},{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_SPACE","NONE","NONE","NONE"],"scale":1,"x":0.8721405267715454,"y":0.8888888955116272,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_BKSP","NONE","NONE","NONE"],"scale":1,"x":0.9309640526771545,"y":0.7555555701255798,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_ENTER","NONE","NONE","NONE"],"scale":1,"x":0.9309640526771545,"y":0.8888888955116272,"toggleSwitch":false,"text":"","iconId":0},{"type":"RANGE_BUTTON","shape":"CIRCLE","bindings":["NONE","NONE","NONE","NONE"],"scale":1,"x":0.843137264251709,"y":0.08888889104127884,"toggleSwitch":false,"text":"","iconId":0}]} \ No newline at end of file +{"id":1,"name":"RTS","cursorSpeed":1,"elements":[{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_DEL","NONE","NONE","NONE"],"scale":1,"x":0.12745098769664764,"y":0.35555556416511536,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_DOWN","NONE","NONE","NONE"],"scale":1,"x":0.12745098769664764,"y":0.7555555701255798,"toggleSwitch":false,"text":"","iconId":5},{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_RIGHT","NONE","NONE","NONE"],"scale":1,"x":0.12745098769664764,"y":0.6222222447395325,"toggleSwitch":false,"text":"","iconId":4},{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_LEFT","NONE","NONE","NONE"],"scale":1,"x":0.06862745434045792,"y":0.6222222447395325,"toggleSwitch":false,"text":"","iconId":2},{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_UP","NONE","NONE","NONE"],"scale":1,"x":0.12745098769664764,"y":0.4888888895511627,"toggleSwitch":false,"text":"","iconId":3},{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_ESC","NONE","NONE","NONE"],"scale":1,"x":0.06862745434045792,"y":0.35555556416511536,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"SQUARE","bindings":["MOUSE_RIGHT_BUTTON","NONE","NONE","NONE"],"scale":1,"x":0.8721405267715454,"y":0.7555555701255798,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_TAB","NONE","NONE","NONE"],"scale":1,"x":0.06862745434045792,"y":0.4888888895511627,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_SHIFT_L","NONE","NONE","NONE"],"scale":1,"x":0.06862745434045792,"y":0.7555555701255798,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_CTRL_L","NONE","NONE","NONE"],"scale":1,"x":0.06862745434045792,"y":0.8888888955116272,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_ALT_L","NONE","NONE","NONE"],"scale":1,"x":0.12745098769664764,"y":0.8888888955116272,"toggleSwitch":false,"text":"","iconId":0},{"type":"RANGE_BUTTON","shape":"CIRCLE","bindings":["NONE","NONE","NONE","NONE","NONE","NONE"],"scale":1,"x":0.1568627506494522,"y":0.08888889104127884,"toggleSwitch":false,"text":"","iconId":0,"range":"FROM_0_TO_9"},{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_SPACE","NONE","NONE","NONE"],"scale":1,"x":0.8721405267715454,"y":0.8888888955116272,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_BKSP","NONE","NONE","NONE"],"scale":1,"x":0.9309640526771545,"y":0.7555555701255798,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"SQUARE","bindings":["KEY_ENTER","NONE","NONE","NONE"],"scale":1,"x":0.9309640526771545,"y":0.8888888955116272,"toggleSwitch":false,"text":"","iconId":0},{"type":"RANGE_BUTTON","shape":"CIRCLE","bindings":["NONE","NONE","NONE","NONE","NONE","NONE"],"scale":1,"x":0.843137264251709,"y":0.08888889104127884,"toggleSwitch":false,"text":"","iconId":0}]} \ No newline at end of file diff --git a/app/src/main/assets/inputcontrols/profiles/controls-3.icp b/app/src/main/assets/inputcontrols/profiles/controls-3.icp index 66d49ab..cf10357 100644 --- a/app/src/main/assets/inputcontrols/profiles/controls-3.icp +++ b/app/src/main/assets/inputcontrols/profiles/controls-3.icp @@ -1 +1 @@ -{"id":3,"name":"Virtual Gamepad","cursorSpeed":1,"elements":[{"type":"D_PAD","shape":"CIRCLE","bindings":["GAMEPAD_DPAD_UP","GAMEPAD_DPAD_RIGHT","GAMEPAD_DPAD_DOWN","GAMEPAD_DPAD_LEFT"],"scale":0.85,"x":0.21568627655506134,"y":0.35555556416511536,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"CIRCLE","bindings":["GAMEPAD_BUTTON_X","NONE","NONE","NONE"],"scale":1,"x":0.8133170008659363,"y":0.7333333492279053,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"CIRCLE","bindings":["GAMEPAD_BUTTON_Y","NONE","NONE","NONE"],"scale":1,"x":0.8721405267715454,"y":0.6000000238418579,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"CIRCLE","bindings":["GAMEPAD_BUTTON_A","NONE","NONE","NONE"],"scale":1,"x":0.8721405267715454,"y":0.8666666746139526,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"CIRCLE","bindings":["GAMEPAD_BUTTON_B","NONE","NONE","NONE"],"scale":1,"x":0.9309640526771545,"y":0.7333333492279053,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"RECT","bindings":["GAMEPAD_BUTTON_R2","NONE","NONE","NONE"],"scale":1,"x":0.9215686321258545,"y":0.2888889014720917,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"RECT","bindings":["GAMEPAD_BUTTON_R1","NONE","NONE","NONE"],"scale":1,"x":0.9215686321258545,"y":0.42222222685813904,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"RECT","bindings":["GAMEPAD_BUTTON_L1","NONE","NONE","NONE"],"scale":1,"x":0.0784313753247261,"y":0.42222222685813904,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"RECT","bindings":["GAMEPAD_BUTTON_L2","NONE","NONE","NONE"],"scale":1,"x":0.0784313753247261,"y":0.2888889014720917,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"ROUND_RECT","bindings":["GAMEPAD_BUTTON_START","NONE","NONE","NONE"],"scale":0.85,"x":0.538807213306427,"y":0.9111111164093018,"toggleSwitch":false,"text":"","iconId":15},{"type":"BUTTON","shape":"ROUND_RECT","bindings":["GAMEPAD_BUTTON_SELECT","NONE","NONE","NONE"],"scale":0.85,"x":0.46078431606292725,"y":0.9111111164093018,"toggleSwitch":false,"text":"","iconId":16},{"type":"STICK","shape":"CIRCLE","bindings":["GAMEPAD_LEFT_THUMB_UP","GAMEPAD_LEFT_THUMB_RIGHT","GAMEPAD_LEFT_THUMB_DOWN","GAMEPAD_LEFT_THUMB_LEFT"],"scale":1,"x":0.10784313827753067,"y":0.7333333492279053,"toggleSwitch":false,"text":"","iconId":0},{"type":"STICK","shape":"CIRCLE","bindings":["GAMEPAD_RIGHT_THUMB_UP","GAMEPAD_RIGHT_THUMB_RIGHT","GAMEPAD_RIGHT_THUMB_DOWN","GAMEPAD_RIGHT_THUMB_LEFT"],"scale":1,"x":0.7843137383460999,"y":0.35555556416511536,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"CIRCLE","bindings":["GAMEPAD_BUTTON_L3","NONE","NONE","NONE"],"scale":0.85,"x":0.21568627655506134,"y":0.9111111164093018,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"CIRCLE","bindings":["GAMEPAD_BUTTON_R3","NONE","NONE","NONE"],"scale":0.85,"x":0.7843137383460999,"y":0.9111111164093018,"toggleSwitch":false,"text":"","iconId":0}]} \ No newline at end of file +{"id":3,"name":"Virtual Gamepad","cursorSpeed":1,"elements":[{"type":"D_PAD","shape":"CIRCLE","bindings":["GAMEPAD_DPAD_UP","GAMEPAD_DPAD_RIGHT","GAMEPAD_DPAD_DOWN","GAMEPAD_DPAD_LEFT"],"scale":0.85,"x":0.21568627655506134,"y":0.35555556416511536,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"CIRCLE","bindings":["GAMEPAD_BUTTON_X","NONE","NONE","NONE"],"scale":1,"x":0.8133170008659363,"y":0.7333333492279053,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"CIRCLE","bindings":["GAMEPAD_BUTTON_Y","NONE","NONE","NONE"],"scale":1,"x":0.8721405267715454,"y":0.6000000238418579,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"CIRCLE","bindings":["GAMEPAD_BUTTON_A","NONE","NONE","NONE"],"scale":1,"x":0.8721405267715454,"y":0.8666666746139526,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"CIRCLE","bindings":["GAMEPAD_BUTTON_B","NONE","NONE","NONE"],"scale":1,"x":0.9309640526771545,"y":0.7333333492279053,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"RECT","bindings":["GAMEPAD_BUTTON_R2","NONE","NONE","NONE"],"scale":1,"x":0.9215686321258545,"y":0.2888889014720917,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"RECT","bindings":["GAMEPAD_BUTTON_R1","NONE","NONE","NONE"],"scale":1,"x":0.9215686321258545,"y":0.42222222685813904,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"RECT","bindings":["GAMEPAD_BUTTON_L1","NONE","NONE","NONE"],"scale":1,"x":0.0784313753247261,"y":0.42222222685813904,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"RECT","bindings":["GAMEPAD_BUTTON_L2","NONE","NONE","NONE"],"scale":1,"x":0.0784313753247261,"y":0.2888889014720917,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"ROUND_RECT","bindings":["GAMEPAD_BUTTON_START","NONE","NONE","NONE"],"scale":0.85,"x":0.538807213306427,"y":0.9111111164093018,"toggleSwitch":false,"text":"","iconId":15},{"type":"BUTTON","shape":"ROUND_RECT","bindings":["GAMEPAD_BUTTON_SELECT","NONE","NONE","NONE"],"scale":0.85,"x":0.46078431606292725,"y":0.9111111164093018,"toggleSwitch":false,"text":"","iconId":16},{"type":"STICK","shape":"CIRCLE","bindings":["GAMEPAD_LEFT_THUMB_UP","GAMEPAD_LEFT_THUMB_RIGHT","GAMEPAD_LEFT_THUMB_DOWN","GAMEPAD_LEFT_THUMB_LEFT"],"scale":1,"x":0.10784313827753067,"y":0.7333333492279053,"toggleSwitch":false,"text":"","iconId":0},{"type":"TRACKPAD","shape":"CIRCLE","bindings":["GAMEPAD_RIGHT_THUMB_UP","GAMEPAD_RIGHT_THUMB_RIGHT","GAMEPAD_RIGHT_THUMB_DOWN","GAMEPAD_RIGHT_THUMB_LEFT"],"scale":1,"x":0.7843137383460999,"y":0.35555556416511536,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"CIRCLE","bindings":["GAMEPAD_BUTTON_L3","NONE","NONE","NONE"],"scale":0.85,"x":0.21568627655506134,"y":0.9111111164093018,"toggleSwitch":false,"text":"","iconId":0},{"type":"BUTTON","shape":"CIRCLE","bindings":["GAMEPAD_BUTTON_R3","NONE","NONE","NONE"],"scale":0.85,"x":0.7843137383460999,"y":0.9111111164093018,"toggleSwitch":false,"text":"","iconId":0}]} \ No newline at end of file diff --git a/app/src/main/assets/wincomponents/wincomponents.json b/app/src/main/assets/wincomponents/wincomponents.json index 94d236e..e23fb49 100644 --- a/app/src/main/assets/wincomponents/wincomponents.json +++ b/app/src/main/assets/wincomponents/wincomponents.json @@ -4,5 +4,6 @@ "directmusic" : ["dmband", "dmcompos", "dmime", "dmloader", "dmscript", "dmstyle", "dmsynth", "dmusic", "dmusic32", "dswave"], "directshow" : ["amstream", "qasf", "qcap", "qdvd", "qedit", "quartz"], "directplay" : ["dplaysvr.exe", "dplayx", "dpmodemx", "dpnet", "dpnhpast", "dpnhupnp", "dpnsvr.exe", "dpwsockx"], - "vcrun2010" : ["msvcp100", "msvcr100", "vcomp100", "atl100"] + "vcrun2010" : ["msvcp100", "msvcr100", "vcomp100", "atl100"], + "wmdecoder" : ["wmvcore", "wmasf", "wmadmod", "wmvdecod"] } \ No newline at end of file diff --git a/app/src/main/assets/wincomponents/wmdecoder.tzst b/app/src/main/assets/wincomponents/wmdecoder.tzst new file mode 100644 index 0000000..30f493a Binary files /dev/null and b/app/src/main/assets/wincomponents/wmdecoder.tzst differ diff --git a/app/src/main/assets/wine_debug_channels.json b/app/src/main/assets/wine_debug_channels.json new file mode 100644 index 0000000..69cd920 --- /dev/null +++ b/app/src/main/assets/wine_debug_channels.json @@ -0,0 +1 @@ +["acledit","aclui","actctx","activeds","actxprxy","adpcm","adsldp","advapi","advpack","alsa","amsi","animate","appbar","apphelp","appwizcpl","appx","asmshader","aspi","atl","atlthunk","atmlib","atom","authz","avicap","avifile","avrt","bcrypt","bidi","bitblt","bitmap","bluetooth","bluetoothapis","browseui","button","bytecodewriter","cabinet","capi","capture","cards","cdosys","class","clipboard","clipping","clusapi","combase","combo","comboex","comm","commctrl","commdlg","compstui","comsvcs","concrt","connect","console","context","coreaudio","cred","credentials","credui","crypt","cryptasn","cryptdlg","cryptext","cryptnet","crypto","cryptui","ctapi32","cursor","d2d","d3d","d3d10","d3d10core","d3d11","d3d12","d3d8","d3d9","d3d_decl","d3d_shader","d3dcompiler","d3drm","d3dx","d3dxof","d3dxof_parsing","data","datetime","davclnt","dbgeng","dbghelp","dbghelp_coff","dbghelp_dwarf","dbghelp_macho","dbghelp_msc","dbghelp_stabs","dc","dciman","dcomp","ddeml","ddraw","ddrawex","debug_buffer","debugstr","devenum","dhcpcsvc","dhtmled","dialog","diasymreader","difxapi","dinput","display","dll","dmband","dmcompos","dmfile","dmime","dmloader","dmobj","dmscript","dmstyle","dmsynth","dmusic","dmusic32","dnsapi","dosmem","dpa","dplay","dpnet","dpnhpast","dpnhupnp","dpvoice","dragdrop","driver","dsa","dsdmo","dsound","dsound3d","dsquery","dssenh","dsuiext","dswave","dwmapi","dwrite","dx8vb","dxcore","dxdiag","dxgi","dxtrans","dxva2","edit","enhmetafile","enumeration","environ","err","event","eventlog","evr","exception","exec","explorerframe","faultrep","file","fixme","fixup","fltlib","fltmgr","font","fontcache","fontsub","fusion","fwpuclnt","g711","gamebar","gameux","gamingtcui","gdi","gdiplus","geolocator","gl_compat","global","globalmem","glu","graphics","gsm","handle","header","heap","hid","hlink","hnetcfg","hook","hostname","hotkey","htmlhelp","http","hvsi","iccvid","icm","icon","ieframe","image","imagehlp","imagelist","imm","inetcomm","inetcpl","inetmib1","infosoft","inkobj","input","inseng","int","int21","int31","ipaddress","iphlpapi","ir50_32","itss","joycpl","jscript","jsproxy","kerberos","kernelbase","keyboard","ksecdd","lanman","listbox","listview","loaddll","loadperf","local","locale","localspl","localui","macdrv","manipulation","mapi","mci","mciavi","mcicda","mcimidi","mciqtz","mciwave","mdi","media","mediacontrol","menu","message","metafile","mfplat","mgmtapi","midi","mlang","mmaux","mmc","mmdevapi","mmio","mmsys","mmtime","model","module","monthcal","mountmgr","mp3dmod","mpeg3","mpr","mprapi","msacm","msado15","msasn1","msauddecmft","mscms","msctf","msctfmonitor","msdasql","msdmo","msdrm","msftedit","msg","mshtml","msi","msidb","msident","msimg32","msimtf","msisip","msisys","msmpeg2vdec","msnet","msopc","mspatcha","msrle32","msscript","mssign","mstask","msttsengine","msvcirt","msvcm","msvcp","msvcrt","msvidc32","msvideo","mswsock","msxml","nativefont","ncrypt","nddeapi","ndis","netapi32","netbios","netcfgx","netio","netprofm","ninput","nls","nonclient","nsi","nstc","ntdll","ntdsapi","ntlm","ntoskrnl","ntprint","objsel","odbc","ole","oleacc","oledb","oledlg","olemalloc","olepicture","opencl","opengl","oss","packager","pager","palette","path","pdh","perception","pidgen","pidl","plugplay","powermgnt","powrprof","print","printui","prntvpt","process","profile","progress","propsheet","propsys","psdrv","pstores","pulse","qmgr","quartz","query","qwave","ras","rasdlg","rawinput","rebar","recyclebin","reg","region","relay","resource","richedit","richedit_lists","rpc","rstrtmgr","rtutils","sapi","schannel","schedsvc","scrobj","scroll","scrrun","scsiport","secur32","security","seh","selector","sensapi","service","setupapi","sfc","shcore","shdocvw","shell","shlctrl","slc","smbios","snmpapi","snoop","sound","speech","spoolss","sspicli","static","statusbar","sti","storage","stress","string","sxs","sync","syslevel","syslink","system","systray","t2embed","tab","tape","tapi","task","taskdialog","taskschd","tbs","tdh","tdi","text","theme_scroll","thread","threadpool","thunk","toolbar","toolhelp","tooltips","trackbar","traffic","treeview","twain","twinapi","ui","uianimation","uiautomation","uiribbon","unloaddll","unwind","updown","updspapi","url","urlmon","usb","usbd","user","uxtheme","variant","vbscript","vcomp","vcruntime","vdmdbg","ver","virtdisk","volume","vulkan","vxd","warn","wavemap","waylanddrv","wbemdisp","wbemprox","webservices","wer","wevtapi","wgl","wia","wimgapi","win","wincodecs","winemapi","wineusb","wing","winhttp","wininet","winmm","winprint","winscard","winsock","winspool","winsta","winstation","winstring","wintab","wintab32","wintrust","wintypes","winusb","wlanapi","wldap32","wldp","wmadec","wmi","wmiutils","wmp","wmvcore","wnet","wofutil","wow","wpc","wpcap","wsdapi","wshom","wsnmp32","wtsapi","wuapi","x11drv","xaudio2","xdnd","xim","xinput","xmllite","xolehlp","xrandr","xrender","xvidmode"] \ No newline at end of file diff --git a/app/src/main/assets/wine_startmenu.json b/app/src/main/assets/wine_startmenu.json index 934e96d..a2f4cb8 100644 --- a/app/src/main/assets/wine_startmenu.json +++ b/app/src/main/assets/wine_startmenu.json @@ -33,6 +33,10 @@ { "name" : "System Tools", "children" : [ + { + "name" : "Test Direct3D", + "path" : "Z:/opt/apps/TestD3D.exe" + }, { "name" : "Computer", "path" : "C:/windows/wfm.exe" @@ -51,8 +55,15 @@ }, { "name" : "Wine Mono Installer", - "path" : "C:/windows/system32/wineboot.exe", - "cmdArgs" : "-u", + "path" : "C:/windows/system32/control.exe", + "cmdArgs" : "appwiz.cpl install_mono", + "iconLocation" : "shell32.dll", + "iconIndex" : -25 + }, + { + "name" : "Wine Gecko Installer", + "path" : "C:/windows/system32/control.exe", + "cmdArgs" : "appwiz.cpl install_gecko", "iconLocation" : "shell32.dll", "iconIndex" : -25 }, diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index da22641..9a0a5fe 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -15,16 +15,18 @@ add_library(winlator SHARED xr/main.c xr/math.c xr/renderer.c - drawable.c - gpu_image.c - sysvshared_memory.c - xconnector_epoll.c) + winlator/drawable.c + winlator/gpu_image.c + winlator/sysvshared_memory.c + winlator/xconnector_epoll.c + winlator/alsa_client.c) target_link_libraries(winlator log android jnigraphics openxr_loader + aaudio EGL GLESv2 GLESv3) \ No newline at end of file diff --git a/app/src/main/cpp/proot/CMakeLists.txt b/app/src/main/cpp/proot/CMakeLists.txt index b04e6d4..e9090b7 100644 --- a/app/src/main/cpp/proot/CMakeLists.txt +++ b/app/src/main/cpp/proot/CMakeLists.txt @@ -16,10 +16,8 @@ add_executable(libproot.so src/cli/note.c src/execve/enter.c src/execve/exit.c - src/execve/shebang.c src/execve/elf.c src/execve/auxv.c - src/execve/aoxp.c src/path/binding.c src/path/glue.c src/path/canon.c diff --git a/app/src/main/cpp/proot/src/cli/proot.c b/app/src/main/cpp/proot/src/cli/proot.c index 2a3f812..eb7c4e5 100644 --- a/app/src/main/cpp/proot/src/cli/proot.c +++ b/app/src/main/cpp/proot/src/cli/proot.c @@ -33,6 +33,8 @@ /* These should be included last. */ #include "cli/proot.h" +char *root_path = NULL; + static int handle_option_r(Tracee *tracee, const Cli *cli UNUSED, const char *value) { Binding *binding; @@ -43,6 +45,7 @@ static int handle_option_r(Tracee *tracee, const Cli *cli UNUSED, const char *va if (binding == NULL) return -1; + root_path = binding->host.path; return 0; } @@ -136,7 +139,7 @@ int pre_initialize_bindings(Tracee *tracee, const Cli *cli) } /* The default guest rootfs is "/" if none was specified. */ - if (get_root(tracee) == NULL) { + if (root_path == NULL) { status = handle_option_r(tracee, cli, "/"); if (status < 0) return -1; diff --git a/app/src/main/cpp/proot/src/execve/aoxp.c b/app/src/main/cpp/proot/src/execve/aoxp.c deleted file mode 100644 index b818651..0000000 --- a/app/src/main/cpp/proot/src/execve/aoxp.c +++ /dev/null @@ -1,336 +0,0 @@ -/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*- - * - * This file is part of PRoot. - * - * Copyright (C) 2015 STMicroelectronics - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301 USA. - */ - -#include /* ARG_MAX, */ -#include /* assert(3), */ -#include /* strlen(3), memcmp(3), memcpy(3), */ -#include /* bzero(3), */ -#include /* bool, true, false, */ -#include /* E*, */ -#include /* va_*, */ -#include /* uint32_t, */ -#include /* talloc_*, */ - -#include "arch.h" -#include "tracee/tracee.h" -#include "tracee/mem.h" -#include "tracee/abi.h" - -struct mixed_pointer { - /* Pointer -- in tracee's address space -- to the current - * object, if local == NULL. */ - word_t remote; - - /* Pointer -- in tracer's address space -- to the current - * object, if local != NULL. */ - void *local; -}; - -#include "execve/aoxp.h" - -/** - * Read string pointed to by @array[@index] from tracee's memory, then - * make @local_pointer points to the locally *cached* version. This - * function returns -errno when an error occured, otherwise 0. - */ -int read_xpointee_as_string(ArrayOfXPointers *array, size_t index, char **local_pointer) -{ - char tmp[ARG_MAX]; - int status; - - assert(index < array->length); - - /* Already cached locally? */ - if (array->_xpointers[index].local != NULL) - goto end; - - /* Remote NULL is mapped to local NULL. */ - if (array->_xpointers[index].remote == 0) { - array->_xpointers[index].local = NULL; - goto end; - } - - /* Copy locally the remote string into a temporary buffer. */ - status = read_string(TRACEE(array), tmp, array->_xpointers[index].remote, ARG_MAX); - if (status < 0) - return status; - if (status >= ARG_MAX) - return -ENOMEM; - - /* Save the local string in a "persistent" buffer. */ - array->_xpointers[index].local = talloc_strdup(array, tmp); - if (array->_xpointers[index].local == NULL) - return -ENOMEM; - -end: - *local_pointer = array->_xpointers[index].local; - return 0; -} - -/** - * This function returns the number of bytes of the string pointed to - * by @array[@index], otherwise -errno if an error occured. - */ -int sizeof_xpointee_as_string(ArrayOfXPointers *array, size_t index) -{ - char *string; - int status; - - assert(index < array->length); - - status = read_xpointee_as_string(array, index, &string); - if (status < 0) - return status; - - if (string == NULL) - return 0; - - return strlen(string) + 1; -} - -/** - * Make @array[@index] points to a copy of the string pointed to by - * @string. This function returns -errno when an error occured, - * otherwise 0. - */ -int write_xpointee_as_string(ArrayOfXPointers *array, size_t index, const char *string) -{ - assert(index < array->length); - - array->_xpointers[index].local = talloc_strdup(array, string); - if (array->_xpointers[index].local == NULL) - return -ENOMEM; - - return 0; -} - -/** - * Make @array[@index ... @index + @nb_xpointees] points to a copy of - * the variadic arguments. This function returns -errno when an error - * occured, otherwise 0. - */ -int write_xpointees(ArrayOfXPointers *array, size_t index, size_t nb_xpointees, ...) -{ - va_list va_xpointees; - int status; - size_t i; - - va_start(va_xpointees, nb_xpointees); - - for (i = 0; i < nb_xpointees; i++) { - void *object = va_arg(va_xpointees, void *); - - status = write_xpointee(array, index + i, object); - if (status < 0) - goto end; - } - status = 0; - -end: - va_end(va_xpointees); - return status; -} - - -/** - * Resize the @array at the given @index by the @delta_nb_entries. - * This function returns -errno when an error occured, otherwise 0. - */ -int resize_array_of_xpointers(ArrayOfXPointers *array, size_t index, ssize_t delta_nb_entries) -{ - size_t nb_moved_entries; - size_t new_length; - void *tmp; - - assert(index < array->length); - - if (delta_nb_entries == 0) - return 0; - - new_length = array->length + delta_nb_entries; - nb_moved_entries = array->length - index; - - if (delta_nb_entries > 0) { - tmp = talloc_realloc(array, array->_xpointers, XPointer, new_length); - if (tmp == NULL) - return -ENOMEM; - array->_xpointers = tmp; - - memmove(array->_xpointers + index + delta_nb_entries, array->_xpointers + index, - nb_moved_entries * sizeof(XPointer)); - - bzero(array->_xpointers + index, delta_nb_entries * sizeof(XPointer)); - } - else { - assert(delta_nb_entries <= 0); - assert(index >= (size_t) -delta_nb_entries); - - memmove(array->_xpointers + index + delta_nb_entries, array->_xpointers + index, - nb_moved_entries * sizeof(XPointer)); - - tmp = talloc_realloc(array, array->_xpointers, XPointer, new_length); - if (tmp == NULL) - return -ENOMEM; - array->_xpointers = tmp; - } - - array->length = new_length; - return 0; -} - -/** - * Copy into *@array_ the pointer array pointed to by @reg from - * @tracee's memory space. Only the first @nb_entries are copied, - * unless it is 0 then all the entries up to the NULL pointer are - * copied. This function returns -errno when an error occured, - * otherwise 0. - */ -int fetch_array_of_xpointers(Tracee *tracee, ArrayOfXPointers **array_, Reg reg, size_t nb_entries) -{ - word_t pointer = 1; /* ie. != 0 */ - word_t address; - ArrayOfXPointers *array; - size_t i; - - assert(array_ != NULL); - - *array_ = talloc_zero(tracee->ctx, ArrayOfXPointers); - if (*array_ == NULL) - return -ENOMEM; - array = *array_; - - address = peek_reg(tracee, CURRENT, reg); - - for (i = 0; nb_entries != 0 ? i < nb_entries : pointer != 0; i++) { - void *tmp = talloc_realloc(array, array->_xpointers, XPointer, i + 1); - if (tmp == NULL) - return -ENOMEM; - array->_xpointers = tmp; - - pointer = peek_word(tracee, address + i * sizeof_word(tracee)); - if (errno != 0) - return -errno; - - array->_xpointers[i].remote = pointer; - array->_xpointers[i].local = NULL; - } - array->length = i; - - /* By default, assume it is an array of string pointers. */ - array->sizeof_xpointee = sizeof_xpointee_as_string; - array->write_xpointee = (write_xpointee_t) write_xpointee_as_string; - - return 0; -} - -/** - * Copy @array into tracee's memory space, then put in @reg the - * address where it was copied. This function returns -errno if an - * error occured, otherwise 0. - */ -int push_array_of_xpointers(ArrayOfXPointers *array, Reg reg) -{ - Tracee *tracee; - struct iovec *local; - size_t local_count; - size_t total_size; - word_t *pod_array; - word_t tracee_ptr; - int status; - size_t i; - - /* Nothing to do, for sure. */ - if (array == NULL) - return 0; - - tracee = TRACEE(array); - - /* The pointer table is a POD array in the tracee's memory. */ - pod_array = talloc_zero_size(tracee->ctx, array->length * sizeof_word(tracee)); - if (pod_array == NULL) - return -ENOMEM; - - /* There's one vector per modified pointee + one vector for the - * pod array. */ - local = talloc_zero_array(tracee->ctx, struct iovec, array->length + 1); - if (local == NULL) - return -ENOMEM; - - /* The pod array is expected to be at the beginning of the - * allocated memory by the caller. */ - total_size = array->length * sizeof_word(tracee); - local[0].iov_base = pod_array; - local[0].iov_len = total_size; - local_count = 1; - - /* Create one vector for each modified pointee. */ - for (i = 0; i < array->length; i++) { - ssize_t size; - - if (array->_xpointers[i].local == NULL) - continue; - - /* At this moment, we only know the offsets in the - * tracee's memory block. */ - array->_xpointers[i].remote = total_size; - - size = sizeof_xpointee(array, i); - if (size < 0) - return size; - total_size += size; - - local[local_count].iov_base = array->_xpointers[i].local; - local[local_count].iov_len = size; - local_count++; - } - - /* Nothing has changed, don't update anything. */ - if (local_count == 1) - return 0; - assert(local_count < array->length + 1); - - /* Modified pointees and the pod array are stored in a tracee's - * memory block. */ - tracee_ptr = alloc_mem(tracee, total_size); - if (tracee_ptr == 0) - return -E2BIG; - - /* Now, we know the absolute addresses in the tracee's - * memory. */ - for (i = 0; i < array->length; i++) { - if (array->_xpointers[i].local != NULL) - array->_xpointers[i].remote += tracee_ptr; - - if (is_32on64_mode(tracee)) - ((uint32_t *) pod_array)[i] = array->_xpointers[i].remote; - else - pod_array[i] = array->_xpointers[i].remote; - } - - /* Write all the modified pointees and the pod array at once. */ - status = writev_data(tracee, tracee_ptr, local, local_count); - if (status < 0) - return status; - - poke_reg(tracee, reg, tracee_ptr); - return 0; -} diff --git a/app/src/main/cpp/proot/src/execve/aoxp.h b/app/src/main/cpp/proot/src/execve/aoxp.h deleted file mode 100644 index 5760dbb..0000000 --- a/app/src/main/cpp/proot/src/execve/aoxp.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*- - * - * This file is part of PRoot. - * - * Copyright (C) 2015 STMicroelectronics - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301 USA. - */ - -#ifndef AOXP_H -#define AOXP_H - -#include - -#include "tracee/reg.h" -#include "arch.h" - -typedef struct array_of_xpointers ArrayOfXPointers; -typedef int (*write_xpointee_t)(ArrayOfXPointers *array, size_t index, const void *object); -typedef int (*sizeof_xpointee_t)(ArrayOfXPointers *array, size_t index); - -typedef struct mixed_pointer XPointer; -struct array_of_xpointers { - XPointer *_xpointers; - size_t length; - - write_xpointee_t write_xpointee; - sizeof_xpointee_t sizeof_xpointee; -}; - -static inline int write_xpointee(ArrayOfXPointers *array, size_t index, const void *object) -{ - return array->write_xpointee(array, index, object); -} - -static inline int sizeof_xpointee(ArrayOfXPointers *array, size_t index) -{ - return array->sizeof_xpointee(array, index); -} - -extern int resize_array_of_xpointers(ArrayOfXPointers *array, size_t index, ssize_t nb_delta_entries); -extern int fetch_array_of_xpointers(Tracee *tracee, ArrayOfXPointers **array, Reg reg, size_t nb_entries); -extern int push_array_of_xpointers(ArrayOfXPointers *array, Reg reg); - -extern int read_xpointee_as_string(ArrayOfXPointers *array, size_t index, char **string); -extern int write_xpointee_as_string(ArrayOfXPointers *array, size_t index, const char *string); -extern int write_xpointees(ArrayOfXPointers *array, size_t index, size_t nb_xpointees, ...); -extern int sizeof_xpointee_as_string(ArrayOfXPointers *array, size_t index); - -#endif /* AOXP_H */ diff --git a/app/src/main/cpp/proot/src/execve/enter.c b/app/src/main/cpp/proot/src/execve/enter.c index 43c7666..215d299 100644 --- a/app/src/main/cpp/proot/src/execve/enter.c +++ b/app/src/main/cpp/proot/src/execve/enter.c @@ -33,8 +33,6 @@ #include /* assert(3), */ #include "execve/execve.h" -#include "execve/shebang.h" -#include "execve/aoxp.h" #include "execve/elf.h" #include "path/path.h" #include "path/temp.h" @@ -364,7 +362,6 @@ int translate_execve_enter(Tracee *tracee) char user_path[PATH_MAX]; char host_path[PATH_MAX]; char new_exe[PATH_MAX]; - char *raw_path; const char *loader_path; int status; @@ -382,23 +379,10 @@ int translate_execve_enter(Tracee *tracee) if (status < 0) return status; - /* Remember the user path before it is overwritten by - * expand_shebang(). This "raw" path is useful to fix the - * value of AT_EXECFN and /proc/{@tracee->pid}/comm. */ - raw_path = talloc_strdup(tracee->ctx, user_path); - if (raw_path == NULL) - return -ENOMEM; - - status = expand_shebang(tracee, host_path, user_path); - if (status < 0) - /* The Linux kernel actually returns -EACCES when - * trying to execute a directory. */ - return status == -EISDIR ? -EACCES : status; - - /* user_path is modified only if there's an interpreter - * (ie. for a script). */ - if (status == 0) - TALLOC_FREE(raw_path); + /* Translate this path (user -> host), then check it is executable. */ + status = translate_and_check_exec(tracee, host_path, user_path); + if (status < 0) + return status; strcpy(new_exe, host_path); status = detranslate_path(tracee, new_exe, NULL); @@ -423,12 +407,6 @@ int translate_execve_enter(Tracee *tracee) if (tracee->load_info->user_path == NULL) return -ENOMEM; - tracee->load_info->raw_path = (raw_path != NULL - ? talloc_reparent(tracee->ctx, tracee->load_info, raw_path) - : talloc_reference(tracee->load_info, tracee->load_info->user_path)); - if (tracee->load_info->raw_path == NULL) - return -ENOMEM; - status = extract_load_info(tracee, tracee->load_info); if (status < 0) return status; diff --git a/app/src/main/cpp/proot/src/execve/execve.h b/app/src/main/cpp/proot/src/execve/execve.h index 4a1a409..93da9eb 100644 --- a/app/src/main/cpp/proot/src/execve/execve.h +++ b/app/src/main/cpp/proot/src/execve/execve.h @@ -46,7 +46,6 @@ typedef struct mapping { typedef struct load_info { char *host_path; char *user_path; - char *raw_path; Mapping *mappings; ElfHeader elf_header; bool needs_executable_stack; diff --git a/app/src/main/cpp/proot/src/execve/exit.c b/app/src/main/cpp/proot/src/execve/exit.c index bf3ce1a..48a1b4a 100644 --- a/app/src/main/cpp/proot/src/execve/exit.c +++ b/app/src/main/cpp/proot/src/execve/exit.c @@ -183,12 +183,10 @@ static int transfer_load_script(Tracee *tracee) size_t strings_size; size_t string1_size; size_t string2_size; - size_t string3_size; size_t padding_size; word_t string1_address; word_t string2_address; - word_t string3_address; void *buffer; size_t buffer_size; @@ -219,20 +217,13 @@ static int transfer_load_script(Tracee *tracee) string2_size = (tracee->load_info->interp == NULL ? 0 : strlen(tracee->load_info->interp->user_path) + 1); - string3_size = (tracee->load_info->raw_path == tracee->load_info->user_path ? 0 - : strlen(tracee->load_info->raw_path) + 1); - /* A padding will be appended at the end of the load script * (a.k.a "strings area") to ensure this latter is aligned properly. */ - padding_size = (stack_pointer - string1_size - string2_size - string3_size) - % STACK_ALIGNMENT; + padding_size = (stack_pointer - string1_size - string2_size) % STACK_ALIGNMENT; - strings_size = string1_size + string2_size + string3_size + padding_size; + strings_size = string1_size + string2_size + padding_size; string1_address = stack_pointer - strings_size; string2_address = stack_pointer - strings_size + string1_size; - string3_address = (string3_size == 0 - ? string1_address - : stack_pointer - strings_size + string1_size + string2_size); /* Compute the size of the load script. */ script_size = @@ -307,7 +298,7 @@ static int transfer_load_script(Tracee *tracee) statement->start.at_entry = ELF_FIELD(tracee->load_info->elf_header, entry); statement->start.at_phdr = ELF_FIELD(tracee->load_info->elf_header, phoff) + tracee->load_info->mappings[0].addr; - statement->start.at_execfn = string3_address; + statement->start.at_execfn = string1_address; cursor += LOAD_STATEMENT_SIZE(*statement, start); @@ -330,11 +321,6 @@ static int transfer_load_script(Tracee *tracee) cursor += string2_size; } - if (string3_size != 0) { - memcpy(cursor, tracee->load_info->raw_path, string3_size); - cursor += string3_size; - } - /* Sanity check. */ cursor += padding_size; assert((uintptr_t) cursor - (uintptr_t) buffer == buffer_size); diff --git a/app/src/main/cpp/proot/src/execve/shebang.c b/app/src/main/cpp/proot/src/execve/shebang.c deleted file mode 100644 index 83ceeda..0000000 --- a/app/src/main/cpp/proot/src/execve/shebang.c +++ /dev/null @@ -1,307 +0,0 @@ -/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*- - * - * This file is part of PRoot. - * - * Copyright (C) 2015 STMicroelectronics - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301 USA. - */ - -#include /* open(2), */ -#include /* open(2), */ -#include /* open(2), */ -#include /* PATH_MAX, */ -#include /* BINPRM_BUF_SIZE, */ -#include /* read(2), close(2), */ -#include /* -E*, */ -#include /* MAXSYMLINKS, */ -#include /* bool, */ -#include /* assert(3), */ - -#include "execve/shebang.h" -#include "execve/execve.h" -#include "execve/aoxp.h" -#include "tracee/tracee.h" -#include "attribute.h" - -/** - * Extract into @user_path and @argument the shebang from @host_path. - * This function returns -errno if an error occured, 1 if a shebang - * was found and extracted, otherwise 0. - * - * Extract from "man 2 execve": - * - * On Linux, the entire string following the interpreter name is - * passed as a *single* argument to the interpreter, and this - * string can include white space. - */ -static int extract_shebang(const Tracee *tracee UNUSED, const char *host_path, - char user_path[PATH_MAX], char argument[BINPRM_BUF_SIZE]) -{ - char tmp2[2]; - char tmp; - - size_t current_length; - size_t i; - - int status; - int fd; - - /* Assumption. */ - assert(BINPRM_BUF_SIZE < PATH_MAX); - - argument[0] = '\0'; - - /* Inspect the executable. */ - fd = open(host_path, O_RDONLY); - if (fd < 0) - return -errno; - - status = read(fd, tmp2, 2 * sizeof(char)); - if (status < 0) { - status = -errno; - goto end; - } - if ((size_t) status < 2 * sizeof(char)) { /* EOF */ - status = 0; - goto end; - } - - /* Check if it really is a script text. */ - if (tmp2[0] != '#' || tmp2[1] != '!') { - status = 0; - goto end; - } - current_length = 2; - user_path[0] = '\0'; - - /* Skip leading spaces. */ - do { - status = read(fd, &tmp, sizeof(char)); - if (status < 0) { - status = -errno; - goto end; - } - if ((size_t) status < sizeof(char)) { /* EOF */ - status = -ENOEXEC; - goto end; - } - - current_length++; - } while ((tmp == ' ' || tmp == '\t') && current_length < BINPRM_BUF_SIZE); - - /* Slurp the interpreter path until the first space or end-of-line. */ - for (i = 0; current_length < BINPRM_BUF_SIZE; current_length++, i++) { - switch (tmp) { - case ' ': - case '\t': - /* Remove spaces in between the interpreter - * and the hypothetical argument. */ - user_path[i] = '\0'; - break; - - case '\n': - case '\r': - /* There is no argument. */ - user_path[i] = '\0'; - argument[0] = '\0'; - status = 1; - goto end; - - default: - /* There is an argument if the previous - * character in user_path[] is '\0'. */ - if (i > 1 && user_path[i - 1] == '\0') - goto argument; - else - user_path[i] = tmp; - break; - } - - status = read(fd, &tmp, sizeof(char)); - if (status < 0) { - status = -errno; - goto end; - } - if ((size_t) status < sizeof(char)) { /* EOF */ - user_path[i] = '\0'; - argument[0] = '\0'; - status = 1; - goto end; - } - } - - /* The interpreter path is too long, truncate it. */ - user_path[i] = '\0'; - argument[0] = '\0'; - status = 1; - goto end; - -argument: - - /* Slurp the argument until the end-of-line. */ - for (i = 0; current_length < BINPRM_BUF_SIZE; current_length++, i++) { - switch (tmp) { - case '\n': - case '\r': - argument[i] = '\0'; - - /* Remove trailing spaces. */ - for (i--; i > 0 && (argument[i] == ' ' || argument[i] == '\t'); i--) - argument[i] = '\0'; - - status = 1; - goto end; - - default: - argument[i] = tmp; - break; - } - - status = read(fd, &tmp, sizeof(char)); - if (status < 0) { - status = -errno; - goto end; - } - if ((size_t) status < sizeof(char)) { /* EOF */ - argument[0] = '\0'; - status = 1; - goto end; - } - } - - /* The argument is too long, truncate it. */ - argument[i] = '\0'; - status = 1; - -end: - close(fd); - - /* Did an error occur or isn't a script? */ - if (status <= 0) - return status; - - return 1; -} - -/** - * Expand in argv[] the shebang of @user_path, if any. This function - * returns -errno if an error occurred, 1 if a shebang was found and - * extracted, otherwise 0. On success, both @host_path and @user_path - * point to the program to execute (respectively from host - * point-of-view and as-is), and @tracee's argv[] (pointed to by - * SYSARG_2) is correctly updated. - */ -int expand_shebang(Tracee *tracee, char host_path[PATH_MAX], char user_path[PATH_MAX]) -{ - ArrayOfXPointers *argv = NULL; - bool has_shebang = false; - - char argument[BINPRM_BUF_SIZE]; - int status; - size_t i; - - /* "The interpreter must be a valid pathname for an executable - * which is not itself a script [1]. If the filename - * argument of execve() specifies an interpreter script, then - * interpreter will be invoked with the following arguments: - * - * interpreter [optional-arg] filename arg... - * - * where arg... is the series of words pointed to by the argv - * argument of execve()." -- man 2 execve - * - * [1]: as of this writing (3.10.17) this is true only for the - * ELF interpreter; ie. a script can use a script as - * interpreter. - */ - for (i = 0; i < MAXSYMLINKS; i++) { - char *old_user_path; - - /* Translate this path (user -> host), then check it is executable. */ - status = translate_and_check_exec(tracee, host_path, user_path); - if (status < 0) - return status; - - /* Remember the initial user path. */ - old_user_path = talloc_strdup(tracee->ctx, user_path); - if (old_user_path == NULL) - return -ENOMEM; - - /* Extract into user_path and argument the shebang from host_path. */ - status = extract_shebang(tracee, host_path, user_path, argument); - if (status < 0) - return status; - - /* No more shebang. */ - if (status == 0) - break; - has_shebang = true; - - /* Translate new path (user -> host), then check it is executable. */ - status = translate_and_check_exec(tracee, host_path, user_path); - if (status < 0) - return status; - - /* Fetch argv[] only on demand. */ - if (argv == NULL) { - status = fetch_array_of_xpointers(tracee, &argv, SYSARG_2, 0); - if (status < 0) - return status; - } - - /* Assuming the shebang of "script" is "#!/bin/sh -x", - * a call to: - * - * execve("./script", { "script.sh", NULL }, ...) - * - * becomes: - * - * execve("/bin/sh", { "/bin/sh", "-x", "./script", NULL }, ...) - * - * See commit 8c8fbe85 about "argv->length == 1". */ - if (argument[0] != '\0') { - status = resize_array_of_xpointers(argv, 0, 2 + (argv->length == 1)); - if (status < 0) - return status; - - status = write_xpointees(argv, 0, 3, user_path, argument, old_user_path); - if (status < 0) - return status; - } - else { - status = resize_array_of_xpointers(argv, 0, 1 + (argv->length == 1)); - if (status < 0) - return status; - - status = write_xpointees(argv, 0, 2, user_path, old_user_path); - if (status < 0) - return status; - } - } - - if (i == MAXSYMLINKS) - return -ELOOP; - - /* Push argv[] only on demand. */ - if (argv != NULL) { - status = push_array_of_xpointers(argv, SYSARG_2); - if (status < 0) - return status; - } - - return (has_shebang ? 1 : 0); -} diff --git a/app/src/main/cpp/proot/src/execve/shebang.h b/app/src/main/cpp/proot/src/execve/shebang.h deleted file mode 100644 index 1ae63be..0000000 --- a/app/src/main/cpp/proot/src/execve/shebang.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*- - * - * This file is part of PRoot. - * - * Copyright (C) 2015 STMicroelectronics - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301 USA. - */ - -#ifndef SHEBANG_H -#define SHEBANG_H - -#include /* PATH_MAX, ARG_MAX, */ - -#include "tracee/tracee.h" - -extern int expand_shebang(Tracee *tracee, char host_path[PATH_MAX], char user_path[PATH_MAX]); - -#endif /* SHEBANG_H */ diff --git a/app/src/main/cpp/proot/src/path/binding.c b/app/src/main/cpp/proot/src/path/binding.c index 589e011..1012846 100644 --- a/app/src/main/cpp/proot/src/path/binding.c +++ b/app/src/main/cpp/proot/src/path/binding.c @@ -93,6 +93,7 @@ talloc_unlink((tracee)->fs->bindings.name, binding); \ } while (0) +extern char *root_path; /** * Print all bindings (verbose purpose). @@ -154,8 +155,8 @@ Binding *get_binding(const Tracee *tracee, Side side, const char path[PATH_MAX]) * proot -m /usr:/location /usr/local/slackware */ if ( side == HOST - && compare_paths(get_root(tracee), "/") != PATHS_ARE_EQUAL - && belongs_to_guestfs(tracee, path)) + && compare_paths(root_path, "/") != PATHS_ARE_EQUAL + && belongs_to_guestfs(path)) continue; return binding; @@ -189,41 +190,6 @@ const char *get_path_binding(const Tracee *tracee, Side side, const char path[PA } } -/** - * Return the path to the guest rootfs for the given @tracee, from the - * host point-of-view obviously. Depending on whether - * initialize_bindings() was called or not, the path is retrieved from - * the "bindings.guest" list or from the "bindings.pending" list, - * respectively. - */ -const char *get_root(const Tracee* tracee) -{ - const Binding *binding; - - if (tracee == NULL || tracee->fs == NULL) - return NULL; - - if (tracee->fs->bindings.guest == NULL) { - if (tracee->fs->bindings.pending == NULL - || CIRCLEQ_EMPTY(tracee->fs->bindings.pending)) - return NULL; - - binding = CIRCLEQ_LAST(tracee->fs->bindings.pending); - if (compare_paths(binding->guest.path, "/") != PATHS_ARE_EQUAL) - return NULL; - - return binding->host.path; - } - - assert(!CIRCLEQ_EMPTY(tracee->fs->bindings.guest)); - - binding = CIRCLEQ_LAST(tracee->fs->bindings.guest); - - assert(strcmp(binding->guest.path, "/") == 0); - - return binding->host.path; -} - /** * Substitute the guest path (if any) with the host path in @path. * This function returns: @@ -674,7 +640,7 @@ int initialize_bindings(Tracee *tracee) Binding *binding; /* Sanity checks. */ - assert(get_root(tracee) != NULL); + assert(root_path != NULL); assert(tracee->fs->bindings.pending != NULL); assert(tracee->fs->bindings.guest == NULL); assert(tracee->fs->bindings.host == NULL); diff --git a/app/src/main/cpp/proot/src/path/binding.h b/app/src/main/cpp/proot/src/path/binding.h index 441a902..8945e76 100644 --- a/app/src/main/cpp/proot/src/path/binding.h +++ b/app/src/main/cpp/proot/src/path/binding.h @@ -50,7 +50,6 @@ extern Binding *new_binding(Tracee *tracee, const char *host, const char *guest, extern int initialize_bindings(Tracee *tracee); extern const char *get_path_binding(const Tracee* tracee, Side side, const char path[PATH_MAX]); extern Binding *get_binding(const Tracee *tracee, Side side, const char path[PATH_MAX]); -extern const char *get_root(const Tracee* tracee); extern int substitute_binding(const Tracee* tracee, Side side, char path[PATH_MAX]); extern void remove_binding_from_all_lists(const Tracee *tracee, Binding *binding); diff --git a/app/src/main/cpp/proot/src/path/canon.c b/app/src/main/cpp/proot/src/path/canon.c index fb939bd..0382a25 100644 --- a/app/src/main/cpp/proot/src/path/canon.c +++ b/app/src/main/cpp/proot/src/path/canon.c @@ -86,7 +86,7 @@ static inline Finality next_component(char component[NAME_MAX], const char **cur bool want_dir; /* Skip leading path separators. */ - while (**cursor != '\0' && **cursor == '/') + while (**cursor == '/') (*cursor)++; /* Find the next component. */ @@ -106,7 +106,7 @@ static inline Finality next_component(char component[NAME_MAX], const char **cur want_dir = (**cursor == '/'); /* Skip trailing path separators. */ - while (**cursor != '\0' && **cursor == '/') + while (**cursor == '/') (*cursor)++; if (**cursor == '\0') @@ -124,8 +124,7 @@ static inline Finality next_component(char component[NAME_MAX], const char **cur * (returned value is 1), otherwise it returns -errno (-ENOENT or * -ENOTDIR). */ -static inline int substitute_binding_stat(Tracee *tracee, Finality finality, unsigned int recursion_level, - const char guest_path[PATH_MAX], char host_path[PATH_MAX]) +static inline int substitute_binding_stat(Tracee *tracee, Finality finality, const char guest_path[PATH_MAX], char host_path[PATH_MAX]) { struct stat statl; int status; @@ -191,7 +190,7 @@ int canonicalize(Tracee *tracee, const char *user_path, bool deref_final, /* Resolve bindings for the initial '/' component or user_path, * which is not handled in the loop below. * In particular HOST_PATH extensions are called from there. */ - status = substitute_binding_stat(tracee, NOT_FINAL, recursion_level, guest_path, host_path); + status = substitute_binding_stat(tracee, NOT_FINAL, guest_path, host_path); if (status < 0) return status; @@ -227,7 +226,7 @@ int canonicalize(Tracee *tracee, const char *user_path, bool deref_final, * symlink. For this latter case, we check that the * symlink points to a directory once it is * canonicalized, at the end of this loop. */ - status = substitute_binding_stat(tracee, finality, recursion_level, scratch_path, host_path); + status = substitute_binding_stat(tracee, finality, scratch_path, host_path); if (status < 0) return status; @@ -303,7 +302,7 @@ int canonicalize(Tracee *tracee, const char *user_path, bool deref_final, /* Check that a non-final canonicalized/dereferenced * symlink exists and is a directory. */ - status = substitute_binding_stat(tracee, finality, recursion_level, guest_path, host_path); + status = substitute_binding_stat(tracee, finality, guest_path, host_path); if (status < 0) return status; diff --git a/app/src/main/cpp/proot/src/path/path.c b/app/src/main/cpp/proot/src/path/path.c index 0e2a8c3..f201b11 100644 --- a/app/src/main/cpp/proot/src/path/path.c +++ b/app/src/main/cpp/proot/src/path/path.c @@ -41,6 +41,8 @@ #include "compat.h" +extern char *root_path; + /** * Copy in @result the concatenation of several paths (@number_paths) * and adds a path separator ('/') in between when needed. This @@ -162,7 +164,7 @@ not_found: strcpy(path, ""); note(tracee, ERROR, USER, "'%s' not found (root = %s, cwd = %s, $PATH=%s)", - command, get_root(tracee), path, paths); + command, root_path, path, paths); /* Check if the command was found without any $PATH look-up * but it didn't contain "/". */ @@ -376,7 +378,7 @@ int detranslate_path(Tracee *tracee, char path[PATH_MAX], const char t_referrer[ * file-system namespace by design. */ follow_binding = true; } - else if (!belongs_to_guestfs(tracee, t_referrer)) { + else if (!belongs_to_guestfs(t_referrer)) { const char *binding_referree; const char *binding_referrer; @@ -414,10 +416,10 @@ int detranslate_path(Tracee *tracee, char path[PATH_MAX], const char t_referrer[ } } - switch (compare_paths(get_root(tracee), path)) { + switch (compare_paths(root_path, path)) { case PATH1_IS_PREFIX: /* Remove the leading part, that is, the "root". */ - prefix_length = strlen(get_root(tracee)); + prefix_length = strlen(root_path); /* Special case when path to the guest rootfs == "/". */ if (prefix_length == 1) @@ -450,11 +452,11 @@ int detranslate_path(Tracee *tracee, char path[PATH_MAX], const char t_referrer[ * Check if the translated @host_path belongs to the guest rootfs, * that is, isn't from a binding. */ -bool belongs_to_guestfs(const Tracee *tracee, const char *host_path) +bool belongs_to_guestfs(const char *host_path) { Comparison comparison; - comparison = compare_paths(get_root(tracee), host_path); + comparison = compare_paths(root_path, host_path); return (comparison == PATHS_ARE_EQUAL || comparison == PATH1_IS_PREFIX); } diff --git a/app/src/main/cpp/proot/src/path/path.h b/app/src/main/cpp/proot/src/path/path.h index 4f53570..2cc1adf 100644 --- a/app/src/main/cpp/proot/src/path/path.h +++ b/app/src/main/cpp/proot/src/path/path.h @@ -80,7 +80,7 @@ extern int translate_path(Tracee *tracee, char host_path[PATH_MAX], int dir_fd, const char *guest_path, bool deref_final); extern int detranslate_path(Tracee *tracee, char path[PATH_MAX], const char t_referrer[PATH_MAX]); -extern bool belongs_to_guestfs(const Tracee *tracee, const char *path); +extern bool belongs_to_guestfs(const char *path); extern void join_paths(char result[PATH_MAX], const char *path1, const char *path2); extern int list_open_fd(const Tracee *tracee); @@ -93,7 +93,4 @@ extern size_t substitute_path_prefix(char path[PATH_MAX], size_t old_prefix_leng extern int readlink_proc_pid_fd(pid_t pid, int fd, char path[PATH_MAX]); -/* Check if path interpretable relatively to dirfd, see openat(2) for details. */ -#define AT_FD(dirfd, path) ((dirfd) != AT_FDCWD && ((path) != NULL && (path)[0] != '/')) - #endif /* PATH_H */ diff --git a/app/src/main/cpp/proot/src/path/proc.c b/app/src/main/cpp/proot/src/path/proc.c index d0f2566..eb4a3b6 100644 --- a/app/src/main/cpp/proot/src/path/proc.c +++ b/app/src/main/cpp/proot/src/path/proc.c @@ -31,6 +31,8 @@ #include "path/path.h" #include "path/binding.h" +extern char *root_path; + /** * This function emulates the @result of readlink("@base/@component") * with respect to @tracee, where @base belongs to "/proc" (according @@ -104,7 +106,7 @@ Action readlink_proc(const Tracee *tracee, char result[PATH_MAX], * of tracee->???. */ SUBSTITUTE(exe, known_tracee->exe); SUBSTITUTE(cwd, known_tracee->fs->cwd); - SUBSTITUTE(root, get_root(known_tracee)); + SUBSTITUTE(root, root_path); #undef SUBSTITUTE return DEFAULT; diff --git a/app/src/main/cpp/virglrenderer/src/vrend_formats.c b/app/src/main/cpp/virglrenderer/src/vrend_formats.c index 5f0ec0b..3a1033d 100644 --- a/app/src/main/cpp/virglrenderer/src/vrend_formats.c +++ b/app/src/main/cpp/virglrenderer/src/vrend_formats.c @@ -30,11 +30,11 @@ #define NO_SWIZZLE { SWIZZLE_INVALID, SWIZZLE_INVALID, SWIZZLE_INVALID, SWIZZLE_INVALID } #define RRR1_SWIZZLE { PIPE_SWIZZLE_RED, PIPE_SWIZZLE_RED, PIPE_SWIZZLE_RED, PIPE_SWIZZLE_ONE } #define RGB1_SWIZZLE { PIPE_SWIZZLE_RED, PIPE_SWIZZLE_GREEN, PIPE_SWIZZLE_BLUE, PIPE_SWIZZLE_ONE } -#define ZZZR_SWIZZLE { PIPE_SWIZZLE_ZERO, PIPE_SWIZZLE_ZERO, PIPE_SWIZZLE_ZERO, PIPE_SWIZZLE_RED } +#define ZZZR_SWIZZLE { PIPE_SWIZZLE_ZERO, PIPE_SWIZZLE_ZERO, PIPE_SWIZZLE_ZERO, PIPE_SWIZZLE_RED } static struct vrend_format_table base_rgba_formats[] = { - { VIRGL_FORMAT_R8G8B8X8_UNORM, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, RGB1_SWIZZLE }, - { VIRGL_FORMAT_R8G8B8A8_UNORM, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, NO_SWIZZLE }, + { VIRGL_FORMAT_R8G8B8X8_UNORM, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, RGB1_SWIZZLE }, + { VIRGL_FORMAT_R8G8B8A8_UNORM, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, NO_SWIZZLE }, { VIRGL_FORMAT_B8G8R8X8_UNORM, GL_BGRA_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE, RGB1_SWIZZLE }, { VIRGL_FORMAT_B8G8R8A8_UNORM, GL_BGRA_EXT, GL_BGRA_EXT, GL_UNSIGNED_BYTE, NO_SWIZZLE }, @@ -154,11 +154,11 @@ static struct vrend_format_table snorm_la_formats[] = { }; static struct vrend_format_table srgb_formats[] = { - { VIRGL_FORMAT_R8G8B8X8_SRGB, GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, RGB1_SWIZZLE }, - { VIRGL_FORMAT_R8G8B8A8_SRGB, GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, NO_SWIZZLE }, + { VIRGL_FORMAT_R8G8B8X8_SRGB, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, RGB1_SWIZZLE }, + { VIRGL_FORMAT_R8G8B8A8_SRGB, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, NO_SWIZZLE }, - { VIRGL_FORMAT_L8_SRGB, GL_SR8_EXT, GL_RED, GL_UNSIGNED_BYTE, RRR1_SWIZZLE }, - { VIRGL_FORMAT_R8_SRGB, GL_SR8_EXT, GL_RED, GL_UNSIGNED_BYTE, NO_SWIZZLE }, + { VIRGL_FORMAT_L8_SRGB, GL_RED, GL_RED, GL_UNSIGNED_BYTE, RRR1_SWIZZLE }, + { VIRGL_FORMAT_R8_SRGB, GL_RED, GL_RED, GL_UNSIGNED_BYTE, NO_SWIZZLE }, }; static struct vrend_format_table bit10_formats[] = { diff --git a/app/src/main/cpp/winlator/alsa_client.c b/app/src/main/cpp/winlator/alsa_client.c new file mode 100644 index 0000000..8dfb28b --- /dev/null +++ b/app/src/main/cpp/winlator/alsa_client.c @@ -0,0 +1,118 @@ +#include +#include + +#define WAIT_COMPLETION_TIMEOUT 100 * 1000000L + +enum Format {U8, S16LE, S16BE, FLOATLE, FLOATBE}; + +static aaudio_format_t toAAudioFormat(int format) { + switch (format) { + case FLOATLE: + case FLOATBE: + return AAUDIO_FORMAT_PCM_FLOAT; + case U8: + return AAUDIO_FORMAT_UNSPECIFIED; + case S16LE: + case S16BE: + default: + return AAUDIO_FORMAT_PCM_I16; + } +} + +static AAudioStream *aaudioCreate(int32_t format, int8_t channelCount, int32_t sampleRate, int32_t bufferSize) { + aaudio_result_t result; + AAudioStreamBuilder *builder; + AAudioStream *stream; + + result = AAudio_createStreamBuilder(&builder); + if (result != AAUDIO_OK) return NULL; + + AAudioStreamBuilder_setPerformanceMode(builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY); + AAudioStreamBuilder_setFormat(builder, toAAudioFormat(format)); + AAudioStreamBuilder_setChannelCount(builder, channelCount); + AAudioStreamBuilder_setSampleRate(builder, sampleRate); + + result = AAudioStreamBuilder_openStream(builder, &stream); + if (result != AAUDIO_OK) { + AAudioStreamBuilder_delete(builder); + return NULL; + } + + AAudioStream_setBufferSizeInFrames(stream, bufferSize); + + result = AAudioStreamBuilder_delete(builder); + if (result != AAUDIO_OK) return NULL; + + return stream; +} + +static int aaudioWrite(AAudioStream *aaudioStream, void *buffer, int numFrames) { + aaudio_result_t framesWritten = AAudioStream_write(aaudioStream, buffer, numFrames, WAIT_COMPLETION_TIMEOUT); + return framesWritten; +} + +static void aaudioStart(AAudioStream *aaudioStream) { + AAudioStream_requestStart(aaudioStream); + AAudioStream_waitForStateChange(aaudioStream, AAUDIO_STREAM_STATE_STARTING, NULL, WAIT_COMPLETION_TIMEOUT); +} + +static void aaudioStop(AAudioStream *aaudioStream) { + AAudioStream_requestStop(aaudioStream); + AAudioStream_waitForStateChange(aaudioStream, AAUDIO_STREAM_STATE_STOPPING, NULL, WAIT_COMPLETION_TIMEOUT); +} + +static void aaudioPause(AAudioStream *aaudioStream) { + AAudioStream_requestPause(aaudioStream); + AAudioStream_waitForStateChange(aaudioStream, AAUDIO_STREAM_STATE_PAUSING, NULL, WAIT_COMPLETION_TIMEOUT); +} + +static void aaudioFlush(AAudioStream *aaudioStream) { + AAudioStream_requestFlush(aaudioStream); + AAudioStream_waitForStateChange(aaudioStream, AAUDIO_STREAM_STATE_FLUSHING, NULL, WAIT_COMPLETION_TIMEOUT); +} + +JNIEXPORT jlong JNICALL +Java_com_winlator_alsaserver_ALSAClient_create(JNIEnv *env, jobject obj, jint format, + jbyte channelCount, jint sampleRate, jint bufferSize) { + return (jlong)aaudioCreate(format, channelCount, sampleRate, bufferSize); +} + +JNIEXPORT jint JNICALL +Java_com_winlator_alsaserver_ALSAClient_write(JNIEnv *env, jobject obj, jlong streamPtr, jobject buffer, + jint numFrames) { + AAudioStream *aaudioStream = (AAudioStream*)streamPtr; + if (aaudioStream) { + return aaudioWrite(aaudioStream, (*env)->GetDirectBufferAddress(env, buffer), numFrames); + } + else return -1; +} + +JNIEXPORT void JNICALL +Java_com_winlator_alsaserver_ALSAClient_start(JNIEnv *env, jobject obj, jlong streamPtr) { + AAudioStream *aaudioStream = (AAudioStream*)streamPtr; + if (aaudioStream) aaudioStart(aaudioStream); +} + +JNIEXPORT void JNICALL +Java_com_winlator_alsaserver_ALSAClient_stop(JNIEnv *env, jobject obj, jlong streamPtr) { + AAudioStream *aaudioStream = (AAudioStream*)streamPtr; + if (aaudioStream) aaudioStop(aaudioStream); +} + +JNIEXPORT void JNICALL +Java_com_winlator_alsaserver_ALSAClient_pause(JNIEnv *env, jobject obj, jlong streamPtr) { + AAudioStream *aaudioStream = (AAudioStream*)streamPtr; + if (aaudioStream) aaudioPause(aaudioStream); +} + +JNIEXPORT void JNICALL +Java_com_winlator_alsaserver_ALSAClient_flush(JNIEnv *env, jobject obj, jlong streamPtr) { + AAudioStream *aaudioStream = (AAudioStream*)streamPtr; + if (aaudioStream) aaudioFlush(aaudioStream); +} + +JNIEXPORT void JNICALL +Java_com_winlator_alsaserver_ALSAClient_close(JNIEnv *env, jobject obj, jlong streamPtr) { + AAudioStream *aaudioStream = (AAudioStream*)streamPtr; + if (aaudioStream) AAudioStream_close(aaudioStream); +} \ No newline at end of file diff --git a/app/src/main/cpp/drawable.c b/app/src/main/cpp/winlator/drawable.c similarity index 88% rename from app/src/main/cpp/drawable.c rename to app/src/main/cpp/winlator/drawable.c index e069c1e..9c4f24b 100644 --- a/app/src/main/cpp/drawable.c +++ b/app/src/main/cpp/winlator/drawable.c @@ -94,8 +94,8 @@ Java_com_winlator_xserver_Drawable_copyArea(JNIEnv *env, jclass obj, jshort srcX jobject dstData) { uint8_t *srcDataAddr = (*env)->GetDirectBufferAddress(env, srcData); uint8_t *dstDataAddr = (*env)->GetDirectBufferAddress(env, dstData); - int64_t srcLength = (*env)->GetDirectBufferCapacity(env, srcData); - int64_t dstLength = (*env)->GetDirectBufferCapacity(env, dstData); + jlong srcLength = (*env)->GetDirectBufferCapacity(env, srcData); + jlong dstLength = (*env)->GetDirectBufferCapacity(env, dstData); if (srcX != 0 || srcY != 0 || dstX != 0 || dstY != 0 || srcLength != dstLength) { int copyAmount = width * 4; @@ -203,7 +203,7 @@ Java_com_winlator_xserver_Drawable_drawAlphaMaskedBitmap(JNIEnv *env, jclass obj int foreColor = packColor(foreRed, foreGreen, foreBlue); int backColor = packColor(backRed, backGreen, backBlue); - int dstLength = (*env)->GetDirectBufferCapacity(env, dstData) / 4; + jlong dstLength = (*env)->GetDirectBufferCapacity(env, dstData) / 4; for (int i = 0; i < dstLength; i++) { dstDataAddr[i] = maskDataAddr[i] == WHITE ? (srcDataAddr[i] == WHITE ? foreColor : backColor) | 0xff000000 : 0x00000000; } @@ -224,5 +224,27 @@ Java_com_winlator_xserver_Drawable_fromBitmap(JNIEnv *env, jclass obj, jobject b memcpy(dataAddr + i, pixels + i, 4); } + AndroidBitmap_unlockPixels(env, bitmap); +} + +JNIEXPORT void JNICALL +Java_com_winlator_xserver_Pixmap_toBitmap(JNIEnv *env, jclass obj, jobject colorData, + jobject maskData, jobject bitmap) { + char *colorDataAddr = (*env)->GetDirectBufferAddress(env, colorData); + char *maskDataAddr = maskData ? (*env)->GetDirectBufferAddress(env, maskData) : NULL; + + AndroidBitmapInfo info; + uint8_t *pixels; + + AndroidBitmap_getInfo(env, bitmap, &info); + AndroidBitmap_lockPixels(env, bitmap, (void**)&pixels); + + for (int i = 0, size = info.width * info.height * 4; i < size; i += 4) { + pixels[i+2] = colorDataAddr[i+0]; + pixels[i+1] = colorDataAddr[i+1]; + pixels[i+0] = colorDataAddr[i+2]; + pixels[i+3] = maskDataAddr ? maskDataAddr[i+0] : colorDataAddr[i+3]; + } + AndroidBitmap_unlockPixels(env, bitmap); } \ No newline at end of file diff --git a/app/src/main/cpp/gpu_image.c b/app/src/main/cpp/winlator/gpu_image.c similarity index 100% rename from app/src/main/cpp/gpu_image.c rename to app/src/main/cpp/winlator/gpu_image.c diff --git a/app/src/main/cpp/sysvshared_memory.c b/app/src/main/cpp/winlator/sysvshared_memory.c similarity index 100% rename from app/src/main/cpp/sysvshared_memory.c rename to app/src/main/cpp/winlator/sysvshared_memory.c diff --git a/app/src/main/cpp/xconnector_epoll.c b/app/src/main/cpp/winlator/xconnector_epoll.c similarity index 100% rename from app/src/main/cpp/xconnector_epoll.c rename to app/src/main/cpp/winlator/xconnector_epoll.c diff --git a/app/src/main/java/com/winlator/ContainerDetailFragment.java b/app/src/main/java/com/winlator/ContainerDetailFragment.java index 61e85f7..707917b 100644 --- a/app/src/main/java/com/winlator/ContainerDetailFragment.java +++ b/app/src/main/java/com/winlator/ContainerDetailFragment.java @@ -31,11 +31,11 @@ import com.winlator.container.Container; import com.winlator.container.ContainerManager; import com.winlator.contentdialog.AddEnvVarDialog; import com.winlator.contentdialog.DXVKConfigDialog; -import com.winlator.contentdialog.TurnipConfigDialog; import com.winlator.core.AppUtils; import com.winlator.core.Callback; import com.winlator.core.EnvVars; import com.winlator.core.FileUtils; +import com.winlator.core.KeyValueSet; import com.winlator.core.PreloaderDialog; import com.winlator.core.StringUtils; import com.winlator.core.WineInfo; @@ -44,6 +44,7 @@ import com.winlator.core.WineThemeManager; import com.winlator.core.WineUtils; import com.winlator.widget.CPUListView; import com.winlator.widget.ColorPickerView; +import com.winlator.widget.EnvVarsView; import com.winlator.widget.ImagePickerView; import org.json.JSONArray; @@ -61,7 +62,7 @@ public class ContainerDetailFragment extends Fragment { private final int containerId; private Container container; private PreloaderDialog preloaderDialog; - private JSONArray gpuNames; + private JSONArray gpuCards; private Callback openDirectoryCallback; public ContainerDetailFragment() { @@ -79,7 +80,7 @@ public class ContainerDetailFragment extends Fragment { preloaderDialog = new PreloaderDialog(getActivity()); try { - gpuNames = new JSONArray(FileUtils.readString(getContext(), "gpu_names.json")); + gpuCards = new JSONArray(FileUtils.readString(getContext(), "gpu_cards.json")); } catch (JSONException e) {} } @@ -98,7 +99,11 @@ public class ContainerDetailFragment extends Fragment { @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - ((AppCompatActivity)getActivity()).getSupportActionBar().setTitle(container != null ? R.string.edit_container : R.string.new_container); + ((AppCompatActivity)getActivity()).getSupportActionBar().setTitle(isEditMode() ? R.string.edit_container : R.string.new_container); + } + + public boolean isEditMode() { + return container != null; } @Nullable @@ -109,100 +114,99 @@ public class ContainerDetailFragment extends Fragment { final View view = inflater.inflate(R.layout.container_detail_fragment, root, false); manager = new ContainerManager(context); container = containerId > 0 ? manager.getContainerById(containerId) : null; - boolean editContainer = container != null; final EditText etName = view.findViewById(R.id.ETName); - if (editContainer) { + if (isEditMode()) { etName.setText(container.getName()); } else etName.setText(getString(R.string.container)+"-"+manager.getNextContainerId()); final ArrayList wineInfos = WineUtils.getInstalledWineInfos(context); final Spinner sWineVersion = view.findViewById(R.id.SWineVersion); - if (wineInfos.size() > 1) { - sWineVersion.setEnabled(!editContainer); - view.findViewById(R.id.LLWineVersion).setVisibility(View.VISIBLE); - sWineVersion.setAdapter(new ArrayAdapter<>(context, android.R.layout.simple_spinner_dropdown_item, wineInfos)); - if (editContainer) AppUtils.setSpinnerSelectionFromValue(sWineVersion, WineInfo.fromIdentifier(getContext(), container.getWineVersion()).toString()); - } + if (wineInfos.size() > 1) loadWineVersionSpinner(view, sWineVersion, wineInfos); - loadScreenSizeSpinner(view, editContainer ? container.getScreenSize() : Container.DEFAULT_SCREEN_SIZE); + loadScreenSizeSpinner(view, isEditMode() ? container.getScreenSize() : Container.DEFAULT_SCREEN_SIZE); final Spinner sGraphicsDriver = view.findViewById(R.id.SGraphicsDriver); final Spinner sDXWrapper = view.findViewById(R.id.SDXWrapper); final View vDXWrapperConfig = view.findViewById(R.id.BTDXWrapperConfig); - vDXWrapperConfig.setTag(editContainer ? container.getDXWrapperConfig() : ""); - - final View vGraphicsDriverConfig = view.findViewById(R.id.BTGraphicsDriverConfig); - vGraphicsDriverConfig.setTag(editContainer ? container.getGraphicsDriverConfig() : ""); + vDXWrapperConfig.setTag(isEditMode() ? container.getDXWrapperConfig() : ""); setupDXWrapperSpinner(sDXWrapper, vDXWrapperConfig); - loadGraphicsDriverSpinner(sGraphicsDriver, sDXWrapper, vGraphicsDriverConfig, - editContainer ? container.getGraphicsDriver() : Container.DEFAULT_GRAPHICS_DRIVER, editContainer ? container.getDXWrapper() : Container.DEFAULT_DXWRAPPER); + loadGraphicsDriverSpinner(sGraphicsDriver, sDXWrapper, isEditMode() ? container.getGraphicsDriver() : Container.DEFAULT_GRAPHICS_DRIVER, + isEditMode() ? container.getDXWrapper() : Container.DEFAULT_DXWRAPPER); view.findViewById(R.id.BTHelpDXWrapper).setOnClickListener((v) -> AppUtils.showHelpBox(context, v, R.string.dxwrapper_help_content)); Spinner sAudioDriver = view.findViewById(R.id.SAudioDriver); - AppUtils.setSpinnerSelectionFromIdentifier(sAudioDriver, editContainer ? container.getAudioDriver() : Container.DEFAULT_AUDIO_DRIVER); + AppUtils.setSpinnerSelectionFromIdentifier(sAudioDriver, isEditMode() ? container.getAudioDriver() : Container.DEFAULT_AUDIO_DRIVER); final CheckBox cbShowFPS = view.findViewById(R.id.CBShowFPS); - cbShowFPS.setChecked(editContainer && container.isShowFPS()); + cbShowFPS.setChecked(isEditMode() && container.isShowFPS()); - final CheckBox cbStopServicesOnStartup = view.findViewById(R.id.CBStopServicesOnStartup); - cbStopServicesOnStartup.setChecked(!editContainer || container.isStopServicesOnStartup()); + final CheckBox cbWoW64Mode = view.findViewById(R.id.CBWoW64Mode); + cbWoW64Mode.setChecked(!isEditMode() || container.isWoW64Mode()); + + final Spinner sStartupSelection = view.findViewById(R.id.SStartupSelection); + byte previousStartupSelection = isEditMode() ? container.getStartupSelection() : -1; + sStartupSelection.setSelection(previousStartupSelection != -1 ? previousStartupSelection : Container.STARTUP_SELECTION_ESSENTIAL); final Spinner sBox86Preset = view.findViewById(R.id.SBox86Preset); - Box86_64PresetManager.loadSpinner("box86", sBox86Preset, editContainer ? container.getBox86Preset() : preferences.getString("box86_preset", Box86_64Preset.COMPATIBILITY)); + Box86_64PresetManager.loadSpinner("box86", sBox86Preset, isEditMode() ? container.getBox86Preset() : preferences.getString("box86_preset", Box86_64Preset.COMPATIBILITY)); final Spinner sBox64Preset = view.findViewById(R.id.SBox64Preset); - Box86_64PresetManager.loadSpinner("box64", sBox64Preset, editContainer ? container.getBox64Preset() : preferences.getString("box64_preset", Box86_64Preset.COMPATIBILITY)); + Box86_64PresetManager.loadSpinner("box64", sBox64Preset, isEditMode() ? container.getBox64Preset() : preferences.getString("box64_preset", Box86_64Preset.COMPATIBILITY)); final CPUListView cpuListView = view.findViewById(R.id.CPUListView); - if (editContainer) cpuListView.setCheckedCPUList(container.getCPUList()); + final CPUListView cpuListViewWoW64 = view.findViewById(R.id.CPUListViewWoW64); + + cpuListView.setCheckedCPUList(isEditMode() ? container.getCPUList(true) : Container.getFallbackCPUList()); + cpuListViewWoW64.setCheckedCPUList(isEditMode() ? container.getCPUListWoW64(true) : Container.getFallbackCPUListWoW64()); createWineConfigurationTab(view); - createWinComponentsTab(view); - createEnvVarsTab(view); + final EnvVarsView envVarsView = createEnvVarsTab(view); + createWinComponentsTab(view, isEditMode() ? container.getWinComponents() : Container.DEFAULT_WINCOMPONENTS); createDrivesTab(view); - view.findViewById(R.id.BTAddEnvVar).setOnClickListener((v) -> (new AddEnvVarDialog(context, view)).show()); AppUtils.setupTabLayout(view, R.id.TabLayout, R.id.LLTabWineConfiguration, R.id.LLTabWinComponents, R.id.LLTabEnvVars, R.id.LLTabDrives, R.id.LLTabAdvanced); view.findViewById(R.id.BTConfirm).setOnClickListener((v) -> { try { String name = etName.getText().toString(); String screenSize = getScreenSize(view); - String envVars = getEnvVars(view); + String envVars = envVarsView.getEnvVars(); String graphicsDriver = StringUtils.parseIdentifier(sGraphicsDriver.getSelectedItem()); String dxwrapper = StringUtils.parseIdentifier(sDXWrapper.getSelectedItem()); String dxwrapperConfig = vDXWrapperConfig.getTag().toString(); - String graphicsDriverConfig = vGraphicsDriverConfig.getTag().toString(); String audioDriver = StringUtils.parseIdentifier(sAudioDriver.getSelectedItem()); String wincomponents = getWinComponents(view); String drives = getDrives(view); boolean showFPS = cbShowFPS.isChecked(); String cpuList = cpuListView.getCheckedCPUListAsString(); - boolean stopServicesOnStartup = cbStopServicesOnStartup.isChecked(); + String cpuListWoW64 = cpuListViewWoW64.getCheckedCPUListAsString(); + boolean wow64Mode = cbWoW64Mode.isChecked() && cbWoW64Mode.isEnabled(); + byte startupSelection = (byte)sStartupSelection.getSelectedItemPosition(); String box86Preset = Box86_64PresetManager.getSpinnerSelectedId(sBox86Preset); String box64Preset = Box86_64PresetManager.getSpinnerSelectedId(sBox64Preset); String desktopTheme = getDesktopTheme(view); - if (editContainer) { + if (isEditMode()) { container.setName(name); container.setScreenSize(screenSize); container.setEnvVars(envVars); container.setCPUList(cpuList); + container.setCPUListWoW64(cpuListWoW64); container.setGraphicsDriver(graphicsDriver); container.setDXWrapper(dxwrapper); container.setDXWrapperConfig(dxwrapperConfig); - container.setGraphicsDriverConfig(graphicsDriverConfig); container.setAudioDriver(audioDriver); container.setWinComponents(wincomponents); container.setDrives(drives); container.setShowFPS(showFPS); - container.setStopServicesOnStartup(stopServicesOnStartup); + container.setWoW64Mode(wow64Mode); + container.setStartupSelection(startupSelection); container.setBox86Preset(box86Preset); container.setBox64Preset(box64Preset); container.setDesktopTheme(desktopTheme); @@ -216,15 +220,16 @@ public class ContainerDetailFragment extends Fragment { data.put("screenSize", screenSize); data.put("envVars", envVars); data.put("cpuList", cpuList); + data.put("cpuListWoW64", cpuListWoW64); data.put("graphicsDriver", graphicsDriver); data.put("dxwrapper", dxwrapper); data.put("dxwrapperConfig", dxwrapperConfig); - data.put("graphicsDriverConfig", graphicsDriverConfig); data.put("audioDriver", audioDriver); data.put("wincomponents", wincomponents); data.put("drives", drives); data.put("showFPS", showFPS); - data.put("stopServicesOnStartup", stopServicesOnStartup); + data.put("wow64Mode", wow64Mode); + data.put("startupSelection", startupSelection); data.put("box86Preset", box86Preset); data.put("box64Preset", box64Preset); data.put("desktopTheme", desktopTheme); @@ -249,27 +254,6 @@ public class ContainerDetailFragment extends Fragment { return view; } - private void createEnvVarsTab(View view) { - final LinearLayout parent = view.findViewById(R.id.LLEnvVars); - final View emptyTextView = view.findViewById(R.id.TVEnvVarsEmptyText); - LayoutInflater inflater = LayoutInflater.from(getContext()); - final EnvVars envVars = new EnvVars(container != null ? container.getEnvVars() : Container.DEFAULT_ENV_VARS); - - for (String name : envVars) { - final View itemView = inflater.inflate(R.layout.env_vars_list_item, parent, false); - ((TextView)itemView.findViewById(R.id.TextView)).setText(name); - ((EditText)itemView.findViewById(R.id.EditText)).setText(envVars.get(name)); - - itemView.findViewById(R.id.BTRemove).setOnClickListener((v) -> { - parent.removeView(itemView); - if (parent.getChildCount() == 0) emptyTextView.setVisibility(View.VISIBLE); - }); - parent.addView(itemView); - } - - if (envVars.isEmpty()) emptyTextView.setVisibility(View.VISIBLE); - } - private void saveWineRegistryKeys(View view) { File userRegFile = new File(container.getRootDir(), ".wine/user.reg"); try (WineRegistryEditor registryEditor = new WineRegistryEditor(userRegFile)) { @@ -278,7 +262,7 @@ public class ContainerDetailFragment extends Fragment { Spinner sGPUName = view.findViewById(R.id.SGPUName); try { - JSONObject gpuName = gpuNames.getJSONObject(sGPUName.getSelectedItemPosition()); + JSONObject gpuName = gpuCards.getJSONObject(sGPUName.getSelectedItemPosition()); registryEditor.setDwordValue("Software\\Wine\\Direct3D", "VideoPciDeviceID", gpuName.getInt("deviceID")); registryEditor.setDwordValue("Software\\Wine\\Direct3D", "VideoPciVendorID", gpuName.getInt("vendorID")); } @@ -304,7 +288,7 @@ public class ContainerDetailFragment extends Fragment { private void createWineConfigurationTab(View view) { Context context = getContext(); - WineThemeManager.ThemeInfo desktopTheme = new WineThemeManager.ThemeInfo(container != null ? container.getDesktopTheme() : WineThemeManager.DEFAULT_DESKTOP_THEME); + WineThemeManager.ThemeInfo desktopTheme = new WineThemeManager.ThemeInfo(isEditMode() ? container.getDesktopTheme() : WineThemeManager.DEFAULT_DESKTOP_THEME); Spinner sDesktopTheme = view.findViewById(R.id.SDesktopTheme); sDesktopTheme.setSelection(desktopTheme.theme.ordinal()); final ImagePickerView ipvDesktopBackgroundImage = view.findViewById(R.id.IPVDesktopBackgroundImage); @@ -332,7 +316,7 @@ public class ContainerDetailFragment extends Fragment { }); sDesktopBackgroundType.setSelection(desktopTheme.backgroundType.ordinal()); - File containerDir = container != null ? container.getRootDir() : null; + File containerDir = isEditMode() ? container.getRootDir() : null; File userRegFile = new File(containerDir, ".wine/user.reg"); try (WineRegistryEditor registryEditor = new WineRegistryEditor(userRegFile)) { @@ -342,7 +326,7 @@ public class ContainerDetailFragment extends Fragment { sCSMT.setSelection(registryEditor.getDwordValue("Software\\Wine\\Direct3D", "csmt", 3) != 0 ? 1 : 0); Spinner sGPUName = view.findViewById(R.id.SGPUName); - loadGPUNameSpinner(sGPUName, registryEditor.getDwordValue("Software\\Wine\\Direct3D", "VideoPciDeviceID", 1556)); + loadGPUNameSpinner(sGPUName, registryEditor.getDwordValue("Software\\Wine\\Direct3D", "VideoPciDeviceID", 1728)); List offscreenRenderingModeList = Arrays.asList("Backbuffer", "FBO"); Spinner sOffscreenRenderingMode = view.findViewById(R.id.SOffscreenRenderingMode); @@ -369,8 +353,8 @@ public class ContainerDetailFragment extends Fragment { int selectedPosition = 0; try { - for (int i = 0; i < gpuNames.length(); i++) { - JSONObject item = gpuNames.getJSONObject(i); + for (int i = 0; i < gpuCards.length(); i++) { + JSONObject item = gpuCards.getJSONObject(i); if (item.getInt("deviceID") == selectedDeviceID) selectedPosition = i; values.add(item.getString("name")); } @@ -381,19 +365,7 @@ public class ContainerDetailFragment extends Fragment { spinner.setSelection(selectedPosition); } - private String getEnvVars(View view) { - LinearLayout parent = view.findViewById(R.id.LLEnvVars); - EnvVars envVars = new EnvVars(); - for (int i = 0; i < parent.getChildCount(); i++) { - View child = parent.getChildAt(i); - String name = ((TextView)child.findViewById(R.id.TextView)).getText().toString(); - String value = ((EditText)child.findViewById(R.id.EditText)).getText().toString().trim().replace(" ", ""); - if (!value.isEmpty()) envVars.put(name, value); - } - return envVars.toString(); - } - - private String getScreenSize(View view) { + public static String getScreenSize(View view) { Spinner sScreenSize = view.findViewById(R.id.SScreenSize); String value = sScreenSize.getSelectedItem().toString(); if (value.equalsIgnoreCase("custom")) { @@ -448,16 +420,16 @@ public class ContainerDetailFragment extends Fragment { } } - public static void loadGraphicsDriverSpinner(final Spinner sGraphicsDriver, final Spinner sDXWrapper, final View vGraphicsDriverConfig, String selectedGraphicsDriver, String selectedDXWrapper) { + public static void loadGraphicsDriverSpinner(final Spinner sGraphicsDriver, final Spinner sDXWrapper, String selectedGraphicsDriver, String selectedDXWrapper) { final Context context = sGraphicsDriver.getContext(); final String[] dxwrapperEntries = context.getResources().getStringArray(R.array.dxwrapper_entries); Runnable update = () -> { String graphicsDriver = StringUtils.parseIdentifier(sGraphicsDriver.getSelectedItem()); - boolean useDXVK = graphicsDriver.equals("turnip"); + boolean addAll = graphicsDriver.equals("turnip"); ArrayList items = new ArrayList<>(); - for (String value : dxwrapperEntries) if (useDXVK || (!value.startsWith("DXVK") && !value.startsWith("D8VK"))) items.add(value); + for (String value : dxwrapperEntries) if (addAll || (!value.equals("DXVK") && !value.equals("VKD3D"))) items.add(value); sDXWrapper.setAdapter(new ArrayAdapter<>(context, android.R.layout.simple_spinner_dropdown_item, items.toArray(new String[0]))); AppUtils.setSpinnerSelectionFromIdentifier(sDXWrapper, selectedDXWrapper); }; @@ -465,12 +437,6 @@ public class ContainerDetailFragment extends Fragment { sGraphicsDriver.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView parent, View view, int position, long id) { - String graphicsDriver = StringUtils.parseIdentifier(sGraphicsDriver.getSelectedItem()); - if (graphicsDriver.equals("turnip")) { - vGraphicsDriverConfig.setOnClickListener((v) -> (new TurnipConfigDialog(vGraphicsDriverConfig)).show()); - vGraphicsDriverConfig.setVisibility(View.VISIBLE); - } - else vGraphicsDriverConfig.setVisibility(View.GONE); update.run(); } @@ -499,36 +465,45 @@ public class ContainerDetailFragment extends Fragment { }); } - private String getWinComponents(View view) { + public static String getWinComponents(View view) { ViewGroup parent = view.findViewById(R.id.LLTabWinComponents); - int childCount = parent.getChildCount(); - String[] wincomponents = new String[childCount]; + ArrayList views = new ArrayList<>(); + AppUtils.findViewsWithClass(parent, Spinner.class, views); + String[] wincomponents = new String[views.size()]; - for (int i = 0; i < childCount; i++) { - View child = parent.getChildAt(i); - Spinner spinner = child.findViewById(R.id.Spinner); - wincomponents[i] = child.getTag().toString()+"="+spinner.getSelectedItemPosition(); + for (int i = 0; i < views.size(); i++) { + Spinner spinner = (Spinner)views.get(i); + wincomponents[i] = spinner.getTag()+"="+spinner.getSelectedItemPosition(); } return String.join(",", wincomponents); } - private void createWinComponentsTab(View view) { - final String[] wincomponents = (container != null ? container.getWinComponents() : Container.DEFAULT_WINCOMPONENTS).split(","); - - Context context = getContext(); + public static void createWinComponentsTab(View view, String wincomponents) { + Context context = view.getContext(); LayoutInflater inflater = LayoutInflater.from(context); - ViewGroup parent = view.findViewById(R.id.LLTabWinComponents); + ViewGroup tabView = view.findViewById(R.id.LLTabWinComponents); + ViewGroup directxSectionView = tabView.findViewById(R.id.LLWinComponentsDirectX); + ViewGroup generalSectionView = tabView.findViewById(R.id.LLWinComponentsGeneral); - for (String wincomponent : wincomponents) { - String[] parts = wincomponent.split("="); + for (String[] wincomponent : new KeyValueSet(wincomponents)) { + ViewGroup parent = wincomponent[0].startsWith("direct") ? directxSectionView : generalSectionView; View itemView = inflater.inflate(R.layout.wincomponent_list_item, parent, false); - ((TextView)itemView.findViewById(R.id.TextView)).setText(StringUtils.getString(context, parts[0])); - ((Spinner)itemView.findViewById(R.id.Spinner)).setSelection(Integer.parseInt(parts[1]), false); - itemView.setTag(parts[0]); + ((TextView)itemView.findViewById(R.id.TextView)).setText(StringUtils.getString(context, wincomponent[0])); + Spinner spinner = itemView.findViewById(R.id.Spinner); + spinner.setSelection(Integer.parseInt(wincomponent[1]), false); + spinner.setTag(wincomponent[0]); parent.addView(itemView); } } + private EnvVarsView createEnvVarsTab(final View view) { + final Context context = view.getContext(); + final EnvVarsView envVarsView = view.findViewById(R.id.EnvVarsView); + envVarsView.setEnvVars(new EnvVars(isEditMode() ? container.getEnvVars() : Container.DEFAULT_ENV_VARS)); + view.findViewById(R.id.BTAddEnvVar).setOnClickListener((v) -> (new AddEnvVarDialog(context, envVarsView)).show()); + return envVarsView; + } + private String getDrives(View view) { LinearLayout parent = view.findViewById(R.id.LLDrives); String drives = ""; @@ -549,7 +524,7 @@ public class ContainerDetailFragment extends Fragment { final LinearLayout parent = view.findViewById(R.id.LLDrives); final View emptyTextView = view.findViewById(R.id.TVDrivesEmptyText); LayoutInflater inflater = LayoutInflater.from(context); - final String drives = container != null ? container.getDrives() : Container.DEFAULT_DRIVES; + final String drives = isEditMode() ? container.getDrives() : Container.DEFAULT_DRIVES; final String[] driveLetters = new String[Container.MAX_DRIVE_LETTERS]; for (int i = 0; i < driveLetters.length; i++) driveLetters[i] = ((char)(i + 68))+":"; @@ -588,4 +563,25 @@ public class ContainerDetailFragment extends Fragment { if (drives.isEmpty()) emptyTextView.setVisibility(View.VISIBLE); } + + private void loadWineVersionSpinner(final View view, Spinner sWineVersion, final ArrayList wineInfos) { + final Context context = getContext(); + sWineVersion.setEnabled(!isEditMode()); + sWineVersion.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View v, int position, long id) { + WineInfo wineInfo = wineInfos.get(position); + boolean isMainWineVersion = WineInfo.isMainWineVersion(wineInfo.identifier()); + CheckBox cbWoW64Mode = view.findViewById(R.id.CBWoW64Mode); + cbWoW64Mode.setEnabled(isMainWineVersion); + if (!isMainWineVersion) cbWoW64Mode.setChecked(false); + } + + @Override + public void onNothingSelected(AdapterView parent) {} + }); + view.findViewById(R.id.LLWineVersion).setVisibility(View.VISIBLE); + sWineVersion.setAdapter(new ArrayAdapter<>(context, android.R.layout.simple_spinner_dropdown_item, wineInfos)); + if (isEditMode()) AppUtils.setSpinnerSelectionFromValue(sWineVersion, WineInfo.fromIdentifier(context, container.getWineVersion()).toString()); + } } diff --git a/app/src/main/java/com/winlator/ContainersFragment.java b/app/src/main/java/com/winlator/ContainersFragment.java index 079fb44..ef806b5 100644 --- a/app/src/main/java/com/winlator/ContainersFragment.java +++ b/app/src/main/java/com/winlator/ContainersFragment.java @@ -1,6 +1,5 @@ package com.winlator; -import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Build; @@ -26,20 +25,15 @@ import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import com.google.android.material.progressindicator.CircularProgressIndicator; import com.winlator.container.Container; import com.winlator.container.ContainerManager; -import com.winlator.core.Callback; -import com.winlator.core.FileUtils; -import com.winlator.core.PreloaderDialog; -import com.winlator.core.StringUtils; import com.winlator.contentdialog.ContentDialog; +import com.winlator.contentdialog.StorageInfoDialog; +import com.winlator.core.PreloaderDialog; import com.winlator.xenvironment.ImageFs; -import java.io.File; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.atomic.AtomicLong; public class ContainersFragment extends Fragment { private RecyclerView recyclerView; @@ -178,7 +172,7 @@ public class ContainersFragment extends Fragment { }); break; case R.id.container_info: - showStorageInfoDialog(container); + (new StorageInfoDialog(getActivity(), container)).show(); break; } return true; @@ -186,68 +180,4 @@ public class ContainersFragment extends Fragment { listItemMenu.show(); } } - - private void showStorageInfoDialog(final Container container) { - final Activity activity = getActivity(); - ContentDialog dialog = new ContentDialog(activity, R.layout.container_storage_info_dialog); - dialog.setTitle(R.string.storage_info); - dialog.setIcon(R.drawable.icon_info); - - AtomicLong driveCSize = new AtomicLong(); - driveCSize.set(0); - - AtomicLong cacheSize = new AtomicLong(); - cacheSize.set(0); - - AtomicLong totalSize = new AtomicLong(); - totalSize.set(0); - - final TextView tvDriveCSize = dialog.findViewById(R.id.TVDriveCSize); - final TextView tvCacheSize = dialog.findViewById(R.id.TVCacheSize); - final TextView tvTotalSize = dialog.findViewById(R.id.TVTotalSize); - final TextView tvUsedSpace = dialog.findViewById(R.id.TVUsedSpace); - final CircularProgressIndicator circularProgressIndicator = dialog.findViewById(R.id.CircularProgressIndicator); - - final long internalStorageSize = FileUtils.getInternalStorageSize(); - - Runnable updateUI = () -> { - tvDriveCSize.setText(StringUtils.formatBytes(driveCSize.get())); - tvCacheSize.setText(StringUtils.formatBytes(cacheSize.get())); - tvTotalSize.setText(StringUtils.formatBytes(totalSize.get())); - - int progress = (int)(((double)totalSize.get() / internalStorageSize) * 100); - tvUsedSpace.setText(progress+"%"); - circularProgressIndicator.setProgress(progress, true); - }; - - File rootDir = container.getRootDir(); - final File driveCDir = new File(rootDir, ".wine/drive_c"); - final File cacheDir = new File(rootDir, ".cache"); - AtomicLong lastTime = new AtomicLong(System.currentTimeMillis()); - - final Callback onAddSize = (size) -> { - totalSize.addAndGet(size); - long currTime = System.currentTimeMillis(); - int elapsedTime = (int)(currTime - lastTime.get()); - if (elapsedTime > 30) { - activity.runOnUiThread(updateUI); - lastTime.set(currTime); - } - }; - - FileUtils.getSizeAsync(driveCDir, (size) -> { - driveCSize.addAndGet(size); - onAddSize.call(size); - }); - - FileUtils.getSizeAsync(cacheDir, (size) -> { - cacheSize.addAndGet(size); - onAddSize.call(size); - }); - - ((TextView)dialog.findViewById(R.id.BTCancel)).setText(R.string.clear_cache); - dialog.setOnCancelCallback(() -> FileUtils.clear(cacheDir)); - - dialog.show(); - } } diff --git a/app/src/main/java/com/winlator/ControlsEditorActivity.java b/app/src/main/java/com/winlator/ControlsEditorActivity.java index 94bdd8f..7959545 100644 --- a/app/src/main/java/com/winlator/ControlsEditorActivity.java +++ b/app/src/main/java/com/winlator/ControlsEditorActivity.java @@ -223,7 +223,7 @@ public class ControlsEditorActivity extends AppCompatActivity implements View.On if (type == ControlElement.Type.BUTTON) { loadBindingSpinner(element, container, 0, R.string.binding); } - else if (type == ControlElement.Type.D_PAD || type == ControlElement.Type.STICK) { + else if (type == ControlElement.Type.D_PAD || type == ControlElement.Type.STICK || type == ControlElement.Type.TRACKPAD) { loadBindingSpinner(element, container, 0, R.string.binding_up); loadBindingSpinner(element, container, 1, R.string.binding_right); loadBindingSpinner(element, container, 2, R.string.binding_down); diff --git a/app/src/main/java/com/winlator/InputControlsFragment.java b/app/src/main/java/com/winlator/InputControlsFragment.java index 522b766..73d1c31 100644 --- a/app/src/main/java/com/winlator/InputControlsFragment.java +++ b/app/src/main/java/com/winlator/InputControlsFragment.java @@ -8,7 +8,6 @@ import android.content.res.ColorStateList; import android.os.Build; import android.os.Bundle; import android.os.Environment; -import android.preference.PreferenceManager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -28,6 +27,7 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.ContextCompat; import androidx.core.widget.ImageViewCompat; import androidx.fragment.app.Fragment; +import androidx.preference.PreferenceManager; import com.winlator.core.AppUtils; import com.winlator.core.Callback; diff --git a/app/src/main/java/com/winlator/MainActivity.java b/app/src/main/java/com/winlator/MainActivity.java index 47221e9..69f566f 100644 --- a/app/src/main/java/com/winlator/MainActivity.java +++ b/app/src/main/java/com/winlator/MainActivity.java @@ -28,13 +28,12 @@ import androidx.fragment.app.FragmentManager; import com.google.android.material.navigation.NavigationView; import com.winlator.contentdialog.ContentDialog; import com.winlator.core.Callback; -import com.winlator.xenvironment.ImageFsInstaller; import com.winlator.core.PreloaderDialog; +import com.winlator.xenvironment.ImageFsInstaller; import java.util.List; public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { - public static final byte DEBUG_LEVEL = 0; // FIXME [0=disable, 2=wine, 3=box86_64, 4=box86_64+] public static final @IntRange(from = 1, to = 19) byte CONTAINER_PATTERN_COMPRESSION_LEVEL = 9; public static final byte PERMISSION_WRITE_EXTERNAL_STORAGE_REQUEST_CODE = 1; public static final byte OPEN_FILE_REQUEST_CODE = 2; @@ -196,8 +195,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On "Wine (winehq.org)", "Box86/Box64 by ptitseb", "PRoot (proot-me.github.io)", - "Mesa3D (mesa3d.org)", + "Mesa (Turnip/Zink/VirGL) (mesa3d.org)", "DXVK (github.com/doitsujin/dxvk)", + "VKD3D (gitlab.winehq.org/wine/vkd3d)", "D8VK (github.com/AlpyneDreams/d8vk)", "CNC DDraw (github.com/FunkyFr3sh/cnc-ddraw)" ); diff --git a/app/src/main/java/com/winlator/SettingsFragment.java b/app/src/main/java/com/winlator/SettingsFragment.java index 92c024f..1207016 100644 --- a/app/src/main/java/com/winlator/SettingsFragment.java +++ b/app/src/main/java/com/winlator/SettingsFragment.java @@ -26,22 +26,26 @@ import androidx.fragment.app.FragmentManager; import androidx.preference.PreferenceManager; import com.google.android.material.navigation.NavigationView; +import com.winlator.box86_64.Box86_64EditPresetDialog; import com.winlator.box86_64.Box86_64Preset; import com.winlator.box86_64.Box86_64PresetManager; import com.winlator.container.Container; import com.winlator.container.ContainerManager; -import com.winlator.box86_64.Box86_64EditPresetDialog; +import com.winlator.contentdialog.ContentDialog; import com.winlator.core.AppUtils; +import com.winlator.core.ArrayUtils; import com.winlator.core.Callback; +import com.winlator.core.DefaultVersion; import com.winlator.core.FileUtils; import com.winlator.core.PreloaderDialog; -import com.winlator.core.DefaultVersion; import com.winlator.core.StringUtils; import com.winlator.core.WineInfo; import com.winlator.core.WineUtils; -import com.winlator.contentdialog.ContentDialog; import com.winlator.xenvironment.ImageFs; +import org.json.JSONArray; +import org.json.JSONException; + import java.io.File; import java.util.ArrayList; import java.util.Arrays; @@ -49,6 +53,7 @@ import java.util.List; import java.util.concurrent.Executors; public class SettingsFragment extends Fragment { + public static final String DEFAULT_WINE_DEBUG_CHANNELS = "warn,err,fixme"; private Callback selectWineFileCallback; private PreloaderDialog preloaderDialog; private SharedPreferences preferences; @@ -105,6 +110,15 @@ public class SettingsFragment extends Fragment { final CheckBox cbUseDRI3 = view.findViewById(R.id.CBUseDRI3); cbUseDRI3.setChecked(preferences.getBoolean("use_dri3", true)); + final CheckBox cbEnableWineDebug = view.findViewById(R.id.CBEnableWineDebug); + cbEnableWineDebug.setChecked(preferences.getBoolean("enable_wine_debug", false)); + + final ArrayList wineDebugChannels = new ArrayList<>(Arrays.asList(preferences.getString("wine_debug_channels", DEFAULT_WINE_DEBUG_CHANNELS).split(","))); + loadWineDebugChannels(view, wineDebugChannels); + + final CheckBox cbEnableBox86_64Logs = view.findViewById(R.id.CBEnableBox86_64Logs); + cbEnableBox86_64Logs.setChecked(preferences.getBoolean("enable_box86_64_logs", false)); + final TextView tvCursorSpeed = view.findViewById(R.id.TVCursorSpeed); final SeekBar sbCursorSpeed = view.findViewById(R.id.SBCursorSpeed); sbCursorSpeed.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @@ -124,30 +138,7 @@ public class SettingsFragment extends Fragment { loadInstalledWineList(view); view.findViewById(R.id.BTSelectWineFile).setOnClickListener((v) -> { - selectWineFileCallback = (uri) -> { - preloaderDialog.show(R.string.preparing_installation); - WineUtils.extractWineFileForInstallAsync(context, uri, (wineDir) -> { - if (wineDir != null) { - WineUtils.findWineVersionAsync(context, wineDir, (wineInfo) -> { - preloaderDialog.closeOnUiThread(); - if (wineInfo == null) { - AppUtils.showToast(context, R.string.unable_to_install_wine); - return; - } - - getActivity().runOnUiThread(() -> showWineInstallOptionsDialog(wineInfo)); - }); - } - else { - AppUtils.showToast(context, R.string.unable_to_install_wine); - preloaderDialog.closeOnUiThread(); - } - }); - }; - Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); - intent.addCategory(Intent.CATEGORY_OPENABLE); - intent.setType("*/*"); - getActivity().startActivityFromFragment(this, intent, MainActivity.OPEN_FILE_REQUEST_CODE); + ContentDialog.alert(context, R.string.msg_warning_install_wine, this::selectWineFileForInstall); }); view.findViewById(R.id.BTConfirm).setOnClickListener((v) -> { @@ -158,8 +149,13 @@ public class SettingsFragment extends Fragment { editor.putString("box64_preset", Box86_64PresetManager.getSpinnerSelectedId(sBox64Preset)); editor.putBoolean("use_dri3", cbUseDRI3.isChecked()); editor.putFloat("cursor_speed", sbCursorSpeed.getProgress() / 100.0f); + editor.putBoolean("enable_wine_debug", cbEnableWineDebug.isChecked()); + editor.putBoolean("enable_box86_64_logs", cbEnableBox86_64Logs.isChecked()); - if (preferences.contains("turnip_version")) editor.remove("turnip_version"); + if (!wineDebugChannels.isEmpty()) { + editor.putString("wine_debug_channels", String.join(",", wineDebugChannels)); + } + else if (preferences.contains("wine_debug_channels")) editor.remove("wine_debug_channels"); if (editor.commit()) { NavigationView navigationView = getActivity().findViewById(R.id.NavigationView); @@ -284,6 +280,35 @@ public class SettingsFragment extends Fragment { } } + private void selectWineFileForInstall() { + final Context context = getContext(); + selectWineFileCallback = (uri) -> { + preloaderDialog.show(R.string.preparing_installation); + WineUtils.extractWineFileForInstallAsync(context, uri, (wineDir) -> { + if (wineDir != null) { + WineUtils.findWineVersionAsync(context, wineDir, (wineInfo) -> { + preloaderDialog.closeOnUiThread(); + if (wineInfo == null) { + AppUtils.showToast(context, R.string.unable_to_install_wine); + return; + } + + getActivity().runOnUiThread(() -> showWineInstallOptionsDialog(wineInfo)); + }); + } + else { + AppUtils.showToast(context, R.string.unable_to_install_wine); + preloaderDialog.closeOnUiThread(); + } + }); + }; + + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("*/*"); + getActivity().startActivityFromFragment(this, intent, MainActivity.OPEN_FILE_REQUEST_CODE); + } + private void installWine(final WineInfo wineInfo) { Context context = getContext(); File installedWineDir = ImageFs.find(context).getInstalledWineDir(); @@ -323,6 +348,54 @@ public class SettingsFragment extends Fragment { dialog.show(); } + private void loadWineDebugChannels(final View view, final ArrayList debugChannels) { + final Context context = getContext(); + LinearLayout container = view.findViewById(R.id.LLWineDebugChannels); + container.removeAllViews(); + + LayoutInflater inflater = LayoutInflater.from(context); + View itemView = inflater.inflate(R.layout.wine_debug_channel_list_item, container, false); + itemView.findViewById(R.id.TextView).setVisibility(View.GONE); + itemView.findViewById(R.id.BTRemove).setVisibility(View.GONE); + + View addButton = itemView.findViewById(R.id.BTAdd); + addButton.setVisibility(View.VISIBLE); + addButton.setOnClickListener((v) -> { + JSONArray jsonArray = null; + try { + jsonArray = new JSONArray(FileUtils.readString(context, "wine_debug_channels.json")); + } + catch (JSONException e) {} + + final String[] items = ArrayUtils.toStringArray(jsonArray); + ContentDialog.showMultipleChoiceList(context, R.string.wine_debug_channel, items, (selectedPositions) -> { + for (int selectedPosition : selectedPositions) if (!debugChannels.contains(items[selectedPosition])) debugChannels.add(items[selectedPosition]); + loadWineDebugChannels(view, debugChannels); + }); + }); + + View resetButton = itemView.findViewById(R.id.BTReset); + resetButton.setVisibility(View.VISIBLE); + resetButton.setOnClickListener((v) -> { + debugChannels.clear(); + debugChannels.addAll(Arrays.asList(DEFAULT_WINE_DEBUG_CHANNELS.split(","))); + loadWineDebugChannels(view, debugChannels); + }); + container.addView(itemView); + + for (int i = 0; i < debugChannels.size(); i++) { + itemView = inflater.inflate(R.layout.wine_debug_channel_list_item, container, false); + TextView textView = itemView.findViewById(R.id.TextView); + textView.setText(debugChannels.get(i)); + final int index = i; + itemView.findViewById(R.id.BTRemove).setOnClickListener((v) -> { + debugChannels.remove(index); + loadWineDebugChannels(view, debugChannels); + }); + container.addView(itemView); + } + } + public static void resetBox86_64Version(AppCompatActivity activity) { SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity); SharedPreferences.Editor editor = preferences.edit(); diff --git a/app/src/main/java/com/winlator/XServerDisplayActivity.java b/app/src/main/java/com/winlator/XServerDisplayActivity.java index fbef357..1281d09 100644 --- a/app/src/main/java/com/winlator/XServerDisplayActivity.java +++ b/app/src/main/java/com/winlator/XServerDisplayActivity.java @@ -5,6 +5,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.view.KeyEvent; +import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; @@ -26,28 +27,28 @@ import com.winlator.container.ContainerManager; import com.winlator.container.Shortcut; import com.winlator.contentdialog.ContentDialog; import com.winlator.contentdialog.DXVKConfigDialog; -import com.winlator.contentdialog.TurnipConfigDialog; +import com.winlator.contentdialog.DebugDialog; import com.winlator.core.AppUtils; -import com.winlator.core.CursorLocker; +import com.winlator.core.DefaultVersion; import com.winlator.core.EnvVars; import com.winlator.core.FileUtils; +import com.winlator.core.GPUInformation; import com.winlator.core.KeyValueSet; import com.winlator.core.OnExtractFileListener; import com.winlator.core.PreloaderDialog; import com.winlator.core.ProcessHelper; import com.winlator.core.TarCompressorUtils; -import com.winlator.core.DefaultVersion; import com.winlator.core.WineInfo; import com.winlator.core.WineRegistryEditor; import com.winlator.core.WineStartMenuCreator; import com.winlator.core.WineThemeManager; import com.winlator.core.WineUtils; -import com.winlator.core.Workarounds; import com.winlator.inputcontrols.ControlsProfile; import com.winlator.inputcontrols.ExternalController; import com.winlator.inputcontrols.InputControlsManager; import com.winlator.math.Mathf; import com.winlator.renderer.GLRenderer; +import com.winlator.widget.FrameRating; import com.winlator.widget.InputControlsView; import com.winlator.widget.MagnifierView; import com.winlator.widget.TouchpadView; @@ -58,12 +59,13 @@ import com.winlator.xconnector.UnixSocketConfig; import com.winlator.xenvironment.ImageFs; import com.winlator.xenvironment.XEnvironment; import com.winlator.xenvironment.components.ALSAServerComponent; -import com.winlator.xenvironment.components.EtcHostsFileUpdateComponent; import com.winlator.xenvironment.components.GuestProgramLauncherComponent; +import com.winlator.xenvironment.components.NetworkInfoUpdateComponent; import com.winlator.xenvironment.components.PulseAudioComponent; import com.winlator.xenvironment.components.SysVSharedMemoryComponent; import com.winlator.xenvironment.components.VirGLRendererComponent; import com.winlator.xenvironment.components.XServerComponent; +import com.winlator.xserver.Property; import com.winlator.xserver.ScreenInfo; import com.winlator.xserver.Window; import com.winlator.xserver.WindowManager; @@ -76,8 +78,6 @@ import org.json.JSONObject; import java.io.File; import java.util.ArrayList; import java.util.Iterator; -import java.util.Timer; -import java.util.TimerTask; import java.util.concurrent.Executors; public class XServerDisplayActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { @@ -91,13 +91,13 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat private XServer xServer; private InputControlsManager inputControlsManager; private ImageFs imageFs; + private FrameRating frameRating; private Runnable editInputControlsCallback; private Shortcut shortcut; private String graphicsDriver = Container.DEFAULT_GRAPHICS_DRIVER; private String audioDriver = Container.DEFAULT_AUDIO_DRIVER; private String dxwrapper = Container.DEFAULT_DXWRAPPER; private KeyValueSet dxwrapperConfig; - private KeyValueSet graphicsDriverConfig; private WineInfo wineInfo; private final EnvVars envVars = new EnvVars(); private boolean firstTimeBoot = false; @@ -106,6 +106,10 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat private final WinHandler winHandler = new WinHandler(this); private float globalCursorSpeed = 1.0f; private MagnifierView magnifierView; + private DebugDialog debugDialog; + private short taskAffinityMask = 0; + private short taskAffinityMaskWoW64 = 0; + private int frameRatingWindowId = -1; @Override public void onCreate(Bundle savedInstanceState) { @@ -115,8 +119,6 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat setContentView(R.layout.xserver_display_activity); final PreloaderDialog preloaderDialog = new PreloaderDialog(this); - preloaderDialog.show(R.string.starting_up); - preferences = PreferenceManager.getDefaultSharedPreferences(this); drawerLayout = findViewById(R.id.DrawerLayout); @@ -124,6 +126,12 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); NavigationView navigationView = findViewById(R.id.NavigationView); + ProcessHelper.removeAllDebugCallbacks(); + boolean enableLogs = preferences.getBoolean("enable_wine_debug", false) || preferences.getBoolean("enable_box86_64_logs", false); + if (enableLogs) ProcessHelper.addDebugCallback(debugDialog = new DebugDialog(this)); + Menu menu = navigationView.getMenu(); + menu.findItem(R.id.main_menu_logs).setVisible(enableLogs); + if (XrActivity.isSupported()) menu.findItem(R.id.main_menu_magnifier).setVisible(false); navigationView.setNavigationItemSelectedListener(this); imageFs = ImageFs.find(this); @@ -134,10 +142,28 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat container = containerManager.getContainerById(getIntent().getIntExtra("container_id", 0)); containerManager.activateContainer(container); + boolean wineprefixNeedsUpdate = container.getExtra("wineprefixNeedsUpdate").equals("t"); + if (wineprefixNeedsUpdate) { + preloaderDialog.show(R.string.updating_system_files); + WineUtils.updateWineprefix(this, (status) -> { + if (status == 0) { + container.putExtra("wineprefixNeedsUpdate", null); + container.putExtra("wincomponents", null); + container.saveData(); + AppUtils.restartActivity(this); + } + else finish(); + }); + return; + } + + taskAffinityMask = (short)ProcessHelper.getAffinityMask(container.getCPUList(true)); + taskAffinityMaskWoW64 = (short)ProcessHelper.getAffinityMask(container.getCPUListWoW64(true)); firstTimeBoot = container.getExtra("appVersion").isEmpty(); String wineVersion = container.getWineVersion(); wineInfo = WineInfo.fromIdentifier(this, wineVersion); + if (wineInfo != WineInfo.MAIN_WINE_VERSION) imageFs.setWinePath(wineInfo.path); String shortcutPath = getIntent().getStringExtra("shortcut_path"); @@ -147,7 +173,6 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat audioDriver = container.getAudioDriver(); dxwrapper = container.getDXWrapper(); String dxwrapperConfig = container.getDXWrapperConfig(); - String graphicsDriverConfig = container.getGraphicsDriverConfig(); screenSize = container.getScreenSize(); if (shortcut != null) { @@ -155,7 +180,6 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat audioDriver = shortcut.getExtra("audioDriver", container.getAudioDriver()); dxwrapper = shortcut.getExtra("dxwrapper", container.getDXWrapper()); dxwrapperConfig = shortcut.getExtra("dxwrapperConfig", container.getDXWrapperConfig()); - graphicsDriverConfig = shortcut.getExtra("graphicsDriverConfig", container.getGraphicsDriverConfig()); screenSize = shortcut.getExtra("screenSize", container.getScreenSize()); String dinputMapperType = shortcut.getExtra("dinputMapperType"); @@ -163,34 +187,47 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat } if (dxwrapper.equals("dxvk")) this.dxwrapperConfig = DXVKConfigDialog.parseConfig(dxwrapperConfig); - if (graphicsDriver.equals("turnip")) this.graphicsDriverConfig = TurnipConfigDialog.parseConfig(this, graphicsDriverConfig); if (!wineInfo.isWin64()) { onExtractFileListener = (file, size) -> { - String name = file.getName(); - if (name.contains("system32/")) return null; - return new File(file.getParentFile(), name.replace("syswow64/", "system32/")); + String path = file.getPath(); + if (path.contains("system32/")) return null; + return new File(path.replace("syswow64/", "system32/")); }; } } + preloaderDialog.show(R.string.starting_up); + inputControlsManager = new InputControlsManager(this); xServer = new XServer(new ScreenInfo(screenSize)); xServer.setWinHandler(winHandler); - boolean[] started = {false}; + boolean[] winStarted = {false}; xServer.windowManager.addOnWindowModificationListener(new WindowManager.OnWindowModificationListener() { @Override public void onUpdateWindowContent(Window window) { - if (!started[0] && window.getWidth() > 1) { + if (!winStarted[0] && window.isApplicationWindow()) { xServerView.getRenderer().setCursorVisible(true); preloaderDialog.closeOnUiThread(); - started[0] = true; + winStarted[0] = true; } + + if (window.id == frameRatingWindowId) frameRating.update(); + } + + @Override + public void onModifyWindowProperty(Window window, Property property) { + changeFrameRatingVisibility(window, property); } @Override public void onMapWindow(Window window) { - Workarounds.onMapWindow(winHandler, window); + assignTaskAffinity(window); + } + + @Override + public void onUnmapWindow(Window window) { + changeFrameRatingVisibility(window, null); } }); @@ -220,15 +257,19 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat @Override public void onResume() { super.onResume(); - xServerView.onResume(); - if (environment != null) environment.onResume(); + if (environment != null) { + xServerView.onResume(); + environment.onResume(); + } } @Override public void onPause() { super.onPause(); - if (environment != null) environment.onPause(); - xServerView.onPause(); + if (environment != null) { + environment.onPause(); + xServerView.onPause(); + } } @Override @@ -285,6 +326,10 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat } drawerLayout.closeDrawers(); break; + case R.id.main_menu_logs: + debugDialog.show(); + drawerLayout.closeDrawers(); + break; case R.id.main_menu_touchpad_help: showTouchpadHelpDialog(); break; @@ -302,21 +347,14 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat } private void setupWineSystemFiles() { - File rootDir = imageFs.getRootDir(); String appVersion = String.valueOf(AppUtils.getVersionCode(this)); String imgVersion = String.valueOf(imageFs.getVersion()); boolean containerDataChanged = false; if (!container.getExtra("appVersion").equals(appVersion) || !container.getExtra("imgVersion").equals(imgVersion)) { - FileUtils.delete(new File(rootDir, "/opt/apps")); - TarCompressorUtils.extract(TarCompressorUtils.Type.ZSTD, this, "imagefs_patches.tzst", rootDir, onExtractFileListener); - TarCompressorUtils.extract(TarCompressorUtils.Type.ZSTD, this, "pulseaudio.tzst", new File(getFilesDir(), "pulseaudio")); - WineUtils.applySystemTweaks(this, wineInfo, firstTimeBoot); + applyGeneralPatches(container); container.putExtra("appVersion", appVersion); container.putExtra("imgVersion", imgVersion); - container.putExtra("graphicsDriver", null); - container.putExtra("desktopTheme", null); - SettingsFragment.resetBox86_64Version(this); containerDataChanged = true; } @@ -342,19 +380,30 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat if (!(desktopTheme+","+xServer.screenInfo).equals(container.getExtra("desktopTheme"))) { WineThemeManager.apply(this, new WineThemeManager.ThemeInfo(desktopTheme), xServer.screenInfo); container.putExtra("desktopTheme", desktopTheme+","+xServer.screenInfo); + containerDataChanged = true; + } + + WineStartMenuCreator.create(this, container); + WineUtils.createDosdevicesSymlinks(container); + + String startupSelection = String.valueOf(container.getStartupSelection()); + if (!startupSelection.equals(container.getExtra("startupSelection"))) { + WineUtils.changeServicesStatus(container, container.getStartupSelection() != Container.STARTUP_SELECTION_NORMAL); + container.putExtra("startupSelection", startupSelection); + containerDataChanged = true; } if (containerDataChanged) container.saveData(); - WineStartMenuCreator.create(this, container); - - WineUtils.createDosdevicesSymlinks(container); } private void setupXEnvironment() { envVars.put("MESA_DEBUG", "silent"); envVars.put("MESA_NO_ERROR", "1"); envVars.put("WINEPREFIX", ImageFs.WINEPREFIX); - if (MainActivity.DEBUG_LEVEL <= 1) envVars.put("WINEDEBUG", "-all"); + + boolean enableWineDebug = preferences.getBoolean("enable_wine_debug", false); + String wineDebugChannels = preferences.getString("wine_debug_channels", SettingsFragment.DEFAULT_WINE_DEBUG_CHANNELS); + envVars.put("WINEDEBUG", enableWineDebug && !wineDebugChannels.isEmpty() ? "+"+wineDebugChannels.replace(",", ",+") : "-all"); String rootPath = imageFs.getRootDir().getPath(); FileUtils.clear(imageFs.getTmpDir()); @@ -362,19 +411,16 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat GuestProgramLauncherComponent guestProgramLauncherComponent = new GuestProgramLauncherComponent(); if (container != null) { - if (container.isStopServicesOnStartup()) winHandler.killProcess("services.exe"); + if (container.getStartupSelection() == Container.STARTUP_SELECTION_AGGRESSIVE) winHandler.killProcess("services.exe"); - String guestExecutable = wineInfo.binName()+" explorer /desktop=shell,"+xServer.screenInfo+" "+getWineStartCommand(); + boolean wow64Mode = container.isWoW64Mode(); + String guestExecutable = wineInfo.getExecutable(this, wow64Mode)+" explorer /desktop=shell,"+xServer.screenInfo+" "+getWineStartCommand(); + guestProgramLauncherComponent.setWoW64Mode(wow64Mode); guestProgramLauncherComponent.setGuestExecutable(guestExecutable); - if (container.isShowFPS()) { - envVars.put("GALLIUM_HUD", "simple,fps"); - envVars.put("DXVK_HUD", "fps"); - } envVars.putAll(container.getEnvVars()); if (shortcut != null) envVars.putAll(shortcut.getExtra("envVars")); if (!envVars.has("WINEESYNC")) envVars.put("WINEESYNC", "1"); - if (graphicsDriver.equals("virgl")) envVars.put("WINEESYNC", "0"); ArrayList bindingPaths = new ArrayList<>(); for (String[] drive : container.drivesIterator()) bindingPaths.add(drive[1]); @@ -386,7 +432,7 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat environment = new XEnvironment(this, imageFs); environment.addComponent(new SysVSharedMemoryComponent(xServer, UnixSocketConfig.createSocket(rootPath, UnixSocketConfig.SYSVSHM_SERVER_PATH))); environment.addComponent(new XServerComponent(xServer, UnixSocketConfig.createSocket(rootPath, UnixSocketConfig.XSERVER_PATH))); - environment.addComponent(new EtcHostsFileUpdateComponent()); + environment.addComponent(new NetworkInfoUpdateComponent()); if (audioDriver.equals("alsa")) { envVars.put("ANDROID_ALSA_SERVER", UnixSocketConfig.ALSA_SERVER_PATH); @@ -412,11 +458,10 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat winHandler.start(); envVars.clear(); dxwrapperConfig = null; - graphicsDriverConfig = null; } private void setupUI() { - FrameLayout container = findViewById(R.id.FLXServerDisplay); + FrameLayout rootView = findViewById(R.id.FLXServerDisplay); xServerView = new XServerView(this, xServer); final GLRenderer renderer = xServerView.getRenderer(); renderer.setCursorVisible(false); @@ -427,7 +472,7 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat } xServer.setRenderer(renderer); - container.addView(xServerView); + rootView.addView(xServerView); globalCursorSpeed = preferences.getFloat("cursor_speed", 1.0f); touchpadView = new TouchpadView(this, xServer); @@ -435,14 +480,20 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat touchpadView.setFourFingersTapCallback(() -> { if (!drawerLayout.isDrawerOpen(GravityCompat.START)) drawerLayout.openDrawer(GravityCompat.START); }); - container.addView(touchpadView); + rootView.addView(touchpadView); inputControlsView = new InputControlsView(this); inputControlsView.setOverlayOpacity(preferences.getFloat("overlay_opacity", InputControlsView.DEFAULT_OVERLAY_OPACITY)); inputControlsView.setTouchpadView(touchpadView); inputControlsView.setXServer(xServer); inputControlsView.setVisibility(View.GONE); - container.addView(inputControlsView); + rootView.addView(inputControlsView); + + if (container != null && container.isShowFPS()) { + frameRating = new FrameRating(this); + frameRating.setVisibility(View.GONE); + rootView.addView(frameRating); + } if (shortcut != null) { String controlsProfile = shortcut.getExtra("controlsProfile"); @@ -462,7 +513,7 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat final Spinner sProfile = dialog.findViewById(R.id.SProfile); Runnable loadProfileSpinner = () -> { - ArrayList profiles = inputControlsManager.getProfiles(); + ArrayList profiles = inputControlsManager.getProfiles(true); ArrayList profileItems = new ArrayList<>(); int selectedPosition = 0; profileItems.add("-- "+getString(R.string.disabled)+" --"); @@ -477,8 +528,8 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat }; loadProfileSpinner.run(); - final CheckBox cbLockCursor = dialog.findViewById(R.id.CBLockCursor); - cbLockCursor.setChecked(xServer.cursorLocker.getState() == CursorLocker.State.LOCKED); + final CheckBox cbRelativeMouseMovement = dialog.findViewById(R.id.CBRelativeMouseMovement); + cbRelativeMouseMovement.setChecked(xServer.isRelativeMouseMovement()); final CheckBox cbShowTouchscreenControls = dialog.findViewById(R.id.CBShowTouchscreenControls); cbShowTouchscreenControls.setChecked(inputControlsView.isShowTouchscreenControls()); @@ -490,14 +541,14 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat intent.putExtra("selected_profile_id", position > 0 ? inputControlsManager.getProfiles().get(position - 1).id : 0); editInputControlsCallback = () -> { hideInputControls(); - inputControlsManager.loadProfiles(); + inputControlsManager.loadProfiles(true); loadProfileSpinner.run(); }; startActivityForResult(intent, MainActivity.EDIT_INPUT_CONTROLS_REQUEST_CODE); }); dialog.setOnConfirmCallback(() -> { - xServer.cursorLocker.setState(cbLockCursor.isChecked() ? CursorLocker.State.LOCKED : CursorLocker.State.CONFINED); + xServer.setRelativeMouseMovement(cbRelativeMouseMovement.isChecked()); inputControlsView.setShowTouchscreenControls(cbShowTouchscreenControls.isChecked()); int position = sProfile.getSelectedItemPosition(); if (position > 0) { @@ -535,7 +586,7 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat private void extractGraphicsDriverFiles() { String cacheId = graphicsDriver; if (graphicsDriver.equals("turnip")) { - cacheId += "-"+graphicsDriverConfig.get("version")+"-"+DefaultVersion.ZINK; + cacheId += "-"+DefaultVersion.TURNIP+"-"+DefaultVersion.ZINK; } else if (graphicsDriver.equals("virgl")) { cacheId += "-"+DefaultVersion.VIRGL; @@ -545,21 +596,32 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat File rootDir = imageFs.getRootDir(); if (changed) { - FileUtils.delete(new File(rootDir, "/usr/lib/arm-linux-gnueabihf/libvulkan_freedreno.so")); - FileUtils.delete(new File(rootDir, "/usr/lib/aarch64-linux-gnu/libvulkan_freedreno.so")); - FileUtils.delete(new File(rootDir, "/usr/lib/arm-linux-gnueabihf/libGL.so.1.7.0")); - FileUtils.delete(new File(rootDir, "/usr/lib/aarch64-linux-gnu/libGL.so.1.7.0")); + FileUtils.delete(new File(imageFs.getLib32Dir(), "libvulkan_freedreno.so")); + FileUtils.delete(new File(imageFs.getLib64Dir(), "libvulkan_freedreno.so")); + FileUtils.delete(new File(imageFs.getLib32Dir(), "libGL.so.1.7.0")); + FileUtils.delete(new File(imageFs.getLib64Dir(), "libGL.so.1.7.0")); container.putExtra("graphicsDriver", cacheId); container.saveData(); } if (graphicsDriver.equals("turnip")) { - if (dxwrapper.equals("dxvk")) DXVKConfigDialog.setEnvVars(this, dxwrapperConfig, envVars); - TurnipConfigDialog.setEnvVars(graphicsDriverConfig, envVars); + if (dxwrapper.equals("dxvk")) { + DXVKConfigDialog.setEnvVars(this, dxwrapperConfig, envVars); + } + else if (dxwrapper.equals("vkd3d")) envVars.put("VKD3D_FEATURE_LEVEL", "12_1"); + envVars.put("GALLIUM_DRIVER", "zink"); - envVars.put("MESA_VK_WSI_PRESENT_MODE", "mailbox"); + envVars.put("TU_OVERRIDE_HEAP_SIZE", "4096"); + if (!envVars.has("MESA_VK_WSI_PRESENT_MODE")) envVars.put("MESA_VK_WSI_PRESENT_MODE", "mailbox"); envVars.put("vblank_mode", "0"); + if (!GPUInformation.isAdreno6xx(this)) { + EnvVars userEnvVars = new EnvVars(container.getEnvVars()); + String tuDebug = userEnvVars.get("TU_DEBUG"); + if (!tuDebug.contains("sysmem")) userEnvVars.put("TU_DEBUG", (!tuDebug.isEmpty() ? tuDebug+"," : "")+"sysmem"); + container.setEnvVars(userEnvVars.toString()); + } + boolean useDRI3 = preferences.getBoolean("use_dri3", true); if (!useDRI3) { envVars.put("MESA_VK_WSI_PRESENT_MODE", "immediate"); @@ -567,7 +629,7 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat } if (changed) { - TarCompressorUtils.extract(TarCompressorUtils.Type.ZSTD, this, "graphics_driver/turnip-"+graphicsDriverConfig.get("version")+".tzst", rootDir); + TarCompressorUtils.extract(TarCompressorUtils.Type.ZSTD, this, "graphics_driver/turnip-"+DefaultVersion.TURNIP+".tzst", rootDir); TarCompressorUtils.extract(TarCompressorUtils.Type.ZSTD, this, "graphics_driver/zink-"+DefaultVersion.ZINK+".tzst", rootDir); } } @@ -575,7 +637,7 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat envVars.put("GALLIUM_DRIVER", "virpipe"); envVars.put("VIRGL_NO_READBACK", "true"); envVars.put("VIRGL_SERVER_PATH", UnixSocketConfig.VIRGL_SERVER_PATH); - envVars.put("MESA_EXTENSION_OVERRIDE", "-GL_EXT_vertex_array_bgra -GL_EXT_texture_sRGB_decode"); + envVars.put("MESA_EXTENSION_OVERRIDE", "-GL_EXT_vertex_array_bgra"); envVars.put("MESA_GL_VERSION_OVERRIDE", "3.1"); envVars.put("vblank_mode", "0"); if (changed) TarCompressorUtils.extract(TarCompressorUtils.Type.ZSTD, this, "graphics_driver/virgl-"+DefaultVersion.VIRGL+".tzst", rootDir); @@ -623,7 +685,7 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat FileUtils.symlink(".."+FileUtils.toRelativePath(rootDir.getPath(), containerPatternDir.getPath()), linkFile.getPath()); GuestProgramLauncherComponent guestProgramLauncherComponent = environment.getComponent(GuestProgramLauncherComponent.class); - guestProgramLauncherComponent.setGuestExecutable(wineInfo.binName()+" explorer /desktop=shell,"+Container.DEFAULT_SCREEN_SIZE+" winecfg"); + guestProgramLauncherComponent.setGuestExecutable(wineInfo.getExecutable(this, false)+" explorer /desktop=shell,"+Container.DEFAULT_SCREEN_SIZE+" winecfg"); final PreloaderDialog preloaderDialog = new PreloaderDialog(this); guestProgramLauncherComponent.setTerminationCallback((status) -> Executors.newSingleThreadExecutor().execute(() -> { @@ -666,25 +728,35 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat } private void extractDXWrapperFiles(String dxwrapper) { - final String[] dlls = {"d3d10.dll", "d3d10_1.dll", "d3d10core.dll", "d3d11.dll", "d3d8.dll", "d3d9.dll", "dxgi.dll", "ddraw.dll", "wined3d.dll"}; - if (firstTimeBoot) cloneOriginalDllFiles(dlls); + final String[] dlls = {"d3d10.dll", "d3d10_1.dll", "d3d10core.dll", "d3d11.dll", "d3d12.dll", "d3d12core.dll", "d3d8.dll", "d3d9.dll", "dxgi.dll", "ddraw.dll"}; + if (firstTimeBoot && !dxwrapper.equals("vkd3d")) cloneOriginalDllFiles(dlls); File rootDir = imageFs.getRootDir(); File windowsDir = new File(rootDir, ImageFs.WINEPREFIX+"/drive_c/windows"); - if (dxwrapper.equals("wined3d")) { - restoreOriginalDllFiles(dlls); - } - else if (dxwrapper.equals("cnc-ddraw")) { - restoreOriginalDllFiles(dlls); - File configFile = new File(rootDir, ImageFs.WINEPREFIX+"/drive_c/ProgramData/cnc-ddraw/ddraw.ini"); - if (!configFile.isFile()) FileUtils.copy(this, "dxwrapper/cnc-ddraw/ddraw.ini", configFile); - File shadersDir = new File(rootDir, ImageFs.WINEPREFIX+"/drive_c/ProgramData/cnc-ddraw/Shaders"); - if (!shadersDir.isDirectory()) FileUtils.copy(this, "dxwrapper/cnc-ddraw/Shaders", shadersDir); - TarCompressorUtils.extract(TarCompressorUtils.Type.ZSTD, this, "dxwrapper/cnc-ddraw/ddraw.tzst", windowsDir, onExtractFileListener); - } - else { - restoreOriginalDllFiles("ddraw.dll"); - TarCompressorUtils.extract(TarCompressorUtils.Type.ZSTD, this, "dxwrapper/"+dxwrapper+".tzst", windowsDir, onExtractFileListener); + switch (dxwrapper) { + case "wined3d": + restoreOriginalDllFiles(dlls); + break; + case "cnc-ddraw": + restoreOriginalDllFiles(dlls); + final String assetDir = "dxwrapper/cnc-ddraw-"+DefaultVersion.CNC_DDRAW; + File configFile = new File(rootDir, ImageFs.WINEPREFIX+"/drive_c/ProgramData/cnc-ddraw/ddraw.ini"); + if (!configFile.isFile()) FileUtils.copy(this, assetDir+"/ddraw.ini", configFile); + File shadersDir = new File(rootDir, ImageFs.WINEPREFIX+"/drive_c/ProgramData/cnc-ddraw/Shaders"); + FileUtils.delete(shadersDir); + FileUtils.copy(this, assetDir+"/Shaders", shadersDir); + TarCompressorUtils.extract(TarCompressorUtils.Type.ZSTD, this, assetDir+"/ddraw.tzst", windowsDir, onExtractFileListener); + break; + case "vkd3d": + String[] dxvkVersions = getResources().getStringArray(R.array.dxvk_version_entries); + TarCompressorUtils.extract(TarCompressorUtils.Type.ZSTD, this, "dxwrapper/dxvk-"+(dxvkVersions[dxvkVersions.length-1])+".tzst", windowsDir, onExtractFileListener); + TarCompressorUtils.extract(TarCompressorUtils.Type.ZSTD, this, "dxwrapper/vkd3d-"+DefaultVersion.VKD3D+".tzst", windowsDir, onExtractFileListener); + break; + default: + restoreOriginalDllFiles("d3d12.dll", "d3d12core.dll", "ddraw.dll"); + TarCompressorUtils.extract(TarCompressorUtils.Type.ZSTD, this, "dxwrapper/"+dxwrapper+".tzst", windowsDir, onExtractFileListener); + TarCompressorUtils.extract(TarCompressorUtils.Type.ZSTD, this, "dxwrapper/d8vk-"+DefaultVersion.D8VK+".tzst", windowsDir, onExtractFileListener); + break; } } @@ -729,26 +801,7 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat } } - if (identifier.equals("directsound")) { - try (WineRegistryEditor registryEditor = new WineRegistryEditor(systemRegFile)) { - final String key64 = "Software\\Classes\\CLSID\\{083863F1-70DE-11D0-BD40-00A0C911CE86}\\Instance\\{E30629D1-27E5-11CE-875D-00608CB78066}"; - final String key32 = "Software\\Classes\\Wow6432Node\\CLSID\\{083863F1-70DE-11D0-BD40-00A0C911CE86}\\Instance\\{E30629D1-27E5-11CE-875D-00608CB78066}"; - - if (useNative) { - registryEditor.setStringValue(key32, "CLSID", "{E30629D1-27E5-11CE-875D-00608CB78066}"); - registryEditor.setHexValue(key32, "FilterData", "02000000000080000100000000000000307069330200000000000000010000000000000000000000307479330000000038000000480000006175647300001000800000aa00389b710100000000001000800000aa00389b71"); - registryEditor.setStringValue(key32, "FriendlyName", "Wave Audio Renderer"); - - registryEditor.setStringValue(key64, "CLSID", "{E30629D1-27E5-11CE-875D-00608CB78066}"); - registryEditor.setHexValue(key64, "FilterData", "02000000000080000100000000000000307069330200000000000000010000000000000000000000307479330000000038000000480000006175647300001000800000aa00389b710100000000001000800000aa00389b71"); - registryEditor.setStringValue(key64, "FriendlyName", "Wave Audio Renderer"); - } - else { - registryEditor.removeKey(key32); - registryEditor.removeKey(key64); - } - } - } + WineUtils.setWinComponentRegistryKeys(systemRegFile, identifier, useNative); } if (!dlls.isEmpty()) restoreOriginalDllFiles(dlls.toArray(new String[0])); @@ -779,10 +832,10 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat } containerManager.extractContainerPatternFile(container.getWineVersion(), container.getRootDir(), (file, size) -> { - String name = file.getName(); - if (name.contains("system32/") || name.contains("syswow64/")) { + String path = file.getPath(); + if (path.contains("system32/") || path.contains("syswow64/")) { for (String dll : dlls) { - if (name.endsWith("system32/"+dll) || name.endsWith("syswow64/"+dll)) return file; + if (path.endsWith("system32/"+dll) || path.endsWith("syswow64/"+dll)) return file; } } return null; @@ -815,10 +868,6 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat FileUtils.clear(tempDir); String args = ""; - - String cpuList = container.getCPUList(); - if (!cpuList.isEmpty()) args += "/affinity "+ProcessHelper.getAffinityMask(cpuList)+" "; - if (shortcut != null) { String execArgs = shortcut.getExtra("execArgs"); execArgs = !execArgs.isEmpty() ? " "+execArgs : ""; @@ -850,6 +899,14 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat return winHandler; } + public XServerView getXServerView() { + return xServerView; + } + + public Container getContainer() { + return container; + } + private void changeWineAudioDriver() { if (!audioDriver.equals(container.getExtra("audioDriver"))) { File rootDir = imageFs.getRootDir(); @@ -866,4 +923,42 @@ public class XServerDisplayActivity extends AppCompatActivity implements Navigat container.saveData(); } } + + private void applyGeneralPatches(Container container) { + File rootDir = imageFs.getRootDir(); + FileUtils.delete(new File(rootDir, "/opt/apps")); + TarCompressorUtils.extract(TarCompressorUtils.Type.ZSTD, this, "imagefs_patches.tzst", rootDir, onExtractFileListener); + TarCompressorUtils.extract(TarCompressorUtils.Type.ZSTD, this, "pulseaudio.tzst", new File(getFilesDir(), "pulseaudio")); + WineUtils.applySystemTweaks(this, wineInfo); + container.putExtra("graphicsDriver", null); + container.putExtra("desktopTheme", null); + SettingsFragment.resetBox86_64Version(this); + } + + private void assignTaskAffinity(Window window) { + if (taskAffinityMask == 0) return; + int processId = window.getProcessId(); + String className = window.getClassName(); + int processAffinity = window.isWoW64() ? taskAffinityMaskWoW64 : taskAffinityMask; + + if (processId > 0) { + winHandler.setProcessAffinity(processId, processAffinity); + } + else if (!className.isEmpty()) { + winHandler.setProcessAffinity(window.getClassName(), processAffinity); + } + } + + private void changeFrameRatingVisibility(Window window, Property property) { + if (frameRating == null) return; + if (property != null) { + if (frameRatingWindowId == -1 && window.attributes.isMapped() && property.nameAsString().equals("_MESA_DRV")) { + frameRatingWindowId = window.id; + } + } + else if (window.id == frameRatingWindowId) { + frameRatingWindowId = -1; + runOnUiThread(() -> frameRating.setVisibility(View.GONE)); + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/winlator/XrActivity.java b/app/src/main/java/com/winlator/XrActivity.java index b6a8c89..cd1f479 100644 --- a/app/src/main/java/com/winlator/XrActivity.java +++ b/app/src/main/java/com/winlator/XrActivity.java @@ -237,7 +237,7 @@ public class XrActivity extends XServerDisplayActivity implements TextWatcher { } // Set mouse status - mouse.moveTo((int) smoothedMouse[0], (int) smoothedMouse[1]); + mouse.setPosition((int) smoothedMouse[0], (int) smoothedMouse[1]); mouse.setButton(Pointer.Button.BUTTON_LEFT, buttons[ControllerButton.R_TRIGGER.ordinal()]); mouse.setButton(Pointer.Button.BUTTON_RIGHT, buttons[ControllerButton.R_GRIP.ordinal()]); mouse.setButton(Pointer.Button.BUTTON_SCROLL_UP, buttons[ControllerButton.R_THUMBSTICK_UP.ordinal()]); diff --git a/app/src/main/java/com/winlator/alsaserver/ALSAClient.java b/app/src/main/java/com/winlator/alsaserver/ALSAClient.java index 39f651a..7591f5b 100644 --- a/app/src/main/java/com/winlator/alsaserver/ALSAClient.java +++ b/app/src/main/java/com/winlator/alsaserver/ALSAClient.java @@ -1,8 +1,5 @@ package com.winlator.alsaserver; -import android.media.AudioFormat; -import android.media.AudioTrack; - import com.winlator.sysvshm.SysVSharedMemory; import java.nio.ByteBuffer; @@ -18,87 +15,68 @@ public class ALSAClient { } } private DataType dataType = DataType.U8; - private AudioTrack audioTrack = null; - private byte channels = 2; + private byte channelCount = 2; private int sampleRate = 0; private int position; private int bufferSize; private int frameBytes; - private ByteBuffer buffer; + private ByteBuffer sharedBuffer; + private boolean playing = false; + private long streamPtr = 0; + + static { + System.loadLibrary("winlator"); + } public void release() { - if (buffer != null) { - SysVSharedMemory.unmapSHMSegment(buffer, buffer.capacity()); - buffer = null; + if (sharedBuffer != null) { + SysVSharedMemory.unmapSHMSegment(sharedBuffer, sharedBuffer.capacity()); + sharedBuffer = null; } - if (audioTrack != null) { - audioTrack.pause(); - audioTrack.flush(); - audioTrack.release(); - audioTrack = null; - } + stop(streamPtr); + close(streamPtr); + playing = false; + streamPtr = 0; } public void prepare() { position = 0; - frameBytes = channels * dataType.byteCount; + frameBytes = channelCount * dataType.byteCount; release(); if (!isValidBufferSize()) return; - int encoding = AudioFormat.ENCODING_DEFAULT; - switch (dataType) { - case U8: - encoding = AudioFormat.ENCODING_PCM_8BIT; - break; - case S16LE: - case S16BE: - encoding = AudioFormat.ENCODING_PCM_16BIT; - break; - case FLOATLE: - case FLOATBE: - encoding = AudioFormat.ENCODING_PCM_FLOAT; - break; - } - - int channelConfig = channels <= 1 ? AudioFormat.CHANNEL_OUT_MONO : AudioFormat.CHANNEL_OUT_STEREO; - AudioFormat format = new AudioFormat.Builder() - .setEncoding(encoding) - .setSampleRate(sampleRate) - .setChannelMask(channelConfig) - .build(); - - audioTrack = new AudioTrack.Builder() - .setAudioFormat(format) - .setBufferSizeInBytes(getBufferSizeInBytes()) - .setPerformanceMode(AudioTrack.PERFORMANCE_MODE_LOW_LATENCY) - .build(); - audioTrack.play(); + streamPtr = create(dataType.ordinal(), channelCount, sampleRate, bufferSize); + if (streamPtr > 0) start(); } public void start() { - if (audioTrack != null && audioTrack.getPlayState() != AudioTrack.PLAYSTATE_PLAYING) { - audioTrack.play(); + if (streamPtr > 0 && !playing) { + start(streamPtr); + playing = true; } } public void stop() { - if (audioTrack != null) { - audioTrack.stop(); - audioTrack.flush(); + if (streamPtr > 0 && playing) { + stop(streamPtr); + playing = false; } } public void pause() { - if (audioTrack != null) audioTrack.pause(); + if (streamPtr > 0) { + pause(streamPtr); + playing = false; + } } public void drain() { - if (audioTrack != null) audioTrack.flush(); + if (streamPtr > 0) flush(streamPtr); } - public void writeDataToTrack(ByteBuffer data) { + public void writeDataToStream(ByteBuffer data) { if (dataType == DataType.S16LE || dataType == DataType.FLOATLE) { data.order(ByteOrder.LITTLE_ENDIAN); } @@ -106,23 +84,24 @@ public class ALSAClient { data.order(ByteOrder.BIG_ENDIAN); } - if (audioTrack != null) { - int bytesWritten = audioTrack.write(data, data.limit(), AudioTrack.WRITE_BLOCKING); - if (bytesWritten > 0) position += bytesWritten; + if (playing) { + int numFrames = data.limit() / frameBytes; + int framesWritten = write(streamPtr, data, numFrames); + if (framesWritten > 0) position += framesWritten; data.rewind(); } } public int pointer() { - return audioTrack != null ? position / frameBytes : 0; + return position; } public void setDataType(DataType dataType) { this.dataType = dataType; } - public void setChannels(int channels) { - this.channels = (byte)channels; + public void setChannelCount(int channelCount) { + this.channelCount = (byte)channelCount; } public void setSampleRate(int sampleRate) { @@ -133,20 +112,20 @@ public class ALSAClient { this.bufferSize = bufferSize; } - public ByteBuffer getBuffer() { - return buffer; + public ByteBuffer getSharedBuffer() { + return sharedBuffer; } - public void setBuffer(ByteBuffer buffer) { - this.buffer = buffer; + public void setSharedBuffer(ByteBuffer sharedBuffer) { + this.sharedBuffer = sharedBuffer; } public DataType getDataType() { return dataType; } - public byte getChannels() { - return channels; + public byte getChannelCount() { + return channelCount; } public int getSampleRate() { @@ -164,4 +143,22 @@ public class ALSAClient { private boolean isValidBufferSize() { return (getBufferSizeInBytes() % frameBytes == 0) && bufferSize > 0; } + + public int computeLatencyMillis() { + return (int)(((float)bufferSize / sampleRate) * 1000); + } + + private native long create(int format, byte channelCount, int sampleRate, int bufferSize); + + private native int write(long streamPtr, ByteBuffer buffer, int numFrames); + + private native void start(long streamPtr); + + private native void stop(long streamPtr); + + private native void pause(long streamPtr); + + private native void flush(long streamPtr); + + private native void close(long streamPtr); } diff --git a/app/src/main/java/com/winlator/alsaserver/ALSARequestHandler.java b/app/src/main/java/com/winlator/alsaserver/ALSARequestHandler.java index 2454314..0996460 100644 --- a/app/src/main/java/com/winlator/alsaserver/ALSARequestHandler.java +++ b/app/src/main/java/com/winlator/alsaserver/ALSARequestHandler.java @@ -40,7 +40,7 @@ public class ALSARequestHandler implements RequestHandler { case RequestCodes.PREPARE: if (inputStream.available() < requestLength) return false; - alsaClient.setChannels(inputStream.readByte()); + alsaClient.setChannelCount(inputStream.readByte()); alsaClient.setDataType(ALSAClient.DataType.values()[inputStream.readByte()]); alsaClient.setSampleRate(inputStream.readInt()); alsaClient.setBufferSize(inputStream.readInt()); @@ -49,14 +49,14 @@ public class ALSARequestHandler implements RequestHandler { createSharedMemory(alsaClient, outputStream); break; case RequestCodes.WRITE: - ByteBuffer buffer = alsaClient.getBuffer(); + ByteBuffer buffer = alsaClient.getSharedBuffer(); if (buffer != null) { buffer.limit(requestLength); - alsaClient.writeDataToTrack(buffer); + alsaClient.writeDataToStream(buffer); } else { if (inputStream.available() < requestLength) return false; - alsaClient.writeDataToTrack(inputStream.readByteBuffer(requestLength)); + alsaClient.writeDataToStream(inputStream.readByteBuffer(requestLength)); } break; case RequestCodes.DRAIN: @@ -77,7 +77,7 @@ public class ALSARequestHandler implements RequestHandler { if (fd >= 0) { ByteBuffer buffer = SysVSharedMemory.mapSHMSegment(fd, size, 0, true); - if (buffer != null) alsaClient.setBuffer(buffer); + if (buffer != null) alsaClient.setSharedBuffer(buffer); } try (XStreamLock lock = outputStream.lock()) { diff --git a/app/src/main/java/com/winlator/box86_64/Box86_64PresetManager.java b/app/src/main/java/com/winlator/box86_64/Box86_64PresetManager.java index 691a76d..735a2d5 100644 --- a/app/src/main/java/com/winlator/box86_64/Box86_64PresetManager.java +++ b/app/src/main/java/com/winlator/box86_64/Box86_64PresetManager.java @@ -2,7 +2,6 @@ package com.winlator.box86_64; import android.content.Context; import android.content.SharedPreferences; -import android.os.Environment; import android.widget.ArrayAdapter; import android.widget.Spinner; import android.widget.SpinnerAdapter; @@ -10,13 +9,8 @@ import android.widget.SpinnerAdapter; import androidx.preference.PreferenceManager; import com.winlator.R; -import com.winlator.SettingsFragment; import com.winlator.core.EnvVars; -import com.winlator.core.FileUtils; -import com.winlator.core.ImageUtils; -import com.winlator.xenvironment.ImageFs; -import java.io.File; import java.util.ArrayList; import java.util.Iterator; import java.util.Locale; @@ -32,8 +26,9 @@ public abstract class Box86_64PresetManager { envVars.put(ucPrefix+"_DYNAREC_FASTROUND", "0"); envVars.put(ucPrefix+"_DYNAREC_X87DOUBLE", "1"); envVars.put(ucPrefix+"_DYNAREC_BIGBLOCK", "0"); - envVars.put(ucPrefix+"_DYNAREC_CALLRET", "0"); envVars.put(ucPrefix+"_DYNAREC_STRONGMEM", "2"); + envVars.put(ucPrefix+"_DYNAREC_FORWARD", "128"); + envVars.put(ucPrefix+"_DYNAREC_CALLRET", "0"); envVars.put(ucPrefix+"_DYNAREC_WAIT", "0"); } else if (id.equals(Box86_64Preset.COMPATIBILITY)) { @@ -43,26 +38,30 @@ public abstract class Box86_64PresetManager { envVars.put(ucPrefix+"_DYNAREC_X87DOUBLE", "1"); envVars.put(ucPrefix+"_DYNAREC_BIGBLOCK", "0"); envVars.put(ucPrefix+"_DYNAREC_STRONGMEM", "1"); + envVars.put(ucPrefix+"_DYNAREC_FORWARD", "128"); + envVars.put(ucPrefix+"_DYNAREC_CALLRET", "0"); envVars.put(ucPrefix+"_DYNAREC_WAIT", "1"); } else if (id.equals(Box86_64Preset.INTERMEDIATE)) { envVars.put(ucPrefix+"_DYNAREC_SAFEFLAGS", "2"); envVars.put(ucPrefix+"_DYNAREC_FASTNAN", "1"); - envVars.put(ucPrefix+"_DYNAREC_FASTROUND", "1"); + envVars.put(ucPrefix+"_DYNAREC_FASTROUND", "0"); envVars.put(ucPrefix+"_DYNAREC_X87DOUBLE", "1"); envVars.put(ucPrefix+"_DYNAREC_BIGBLOCK", "1"); envVars.put(ucPrefix+"_DYNAREC_STRONGMEM", "0"); envVars.put(ucPrefix+"_DYNAREC_FORWARD", "128"); + envVars.put(ucPrefix+"_DYNAREC_CALLRET", "0"); envVars.put(ucPrefix+"_DYNAREC_WAIT", "1"); } else if (id.equals(Box86_64Preset.PERFORMANCE)) { - envVars.put(ucPrefix+"_DYNAREC_SAFEFLAGS", "0"); + envVars.put(ucPrefix+"_DYNAREC_SAFEFLAGS", "1"); envVars.put(ucPrefix+"_DYNAREC_FASTNAN", "1"); envVars.put(ucPrefix+"_DYNAREC_FASTROUND", "1"); envVars.put(ucPrefix+"_DYNAREC_X87DOUBLE", "0"); - envVars.put(ucPrefix+"_DYNAREC_BIGBLOCK", "2"); + envVars.put(ucPrefix+"_DYNAREC_BIGBLOCK", "3"); envVars.put(ucPrefix+"_DYNAREC_STRONGMEM", "0"); envVars.put(ucPrefix+"_DYNAREC_FORWARD", "512"); + envVars.put(ucPrefix+"_DYNAREC_CALLRET", "1"); envVars.put(ucPrefix+"_DYNAREC_WAIT", "1"); } else if (id.startsWith(Box86_64Preset.CUSTOM)) { diff --git a/app/src/main/java/com/winlator/container/Container.java b/app/src/main/java/com/winlator/container/Container.java index 21e027a..0f4a363 100644 --- a/app/src/main/java/com/winlator/container/Container.java +++ b/app/src/main/java/com/winlator/container/Container.java @@ -3,7 +3,6 @@ package com.winlator.container; import android.os.Environment; import com.winlator.box86_64.Box86_64Preset; -import com.winlator.core.AppUtils; import com.winlator.core.EnvVars; import com.winlator.core.FileUtils; import com.winlator.core.KeyValueSet; @@ -18,14 +17,17 @@ import java.io.File; import java.util.Iterator; public class Container { - public static final String DEFAULT_ENV_VARS = "ZINK_DESCRIPTORS=lazy ZINK_CONTEXT_THREADED=true ZINK_DEBUG=compact MESA_SHADER_CACHE_DISABLE=false MESA_SHADER_CACHE_MAX_SIZE=512MB mesa_glthread=true WINEESYNC=1"; - public static final String DEFAULT_SCREEN_SIZE = "800x600"; + public static final String DEFAULT_ENV_VARS = "ZINK_DESCRIPTORS=lazy ZINK_DEBUG=compact MESA_SHADER_CACHE_DISABLE=false MESA_SHADER_CACHE_MAX_SIZE=512MB mesa_glthread=true WINEESYNC=1 MESA_VK_WSI_PRESENT_MODE=mailbox TU_DEBUG=noconform"; + public static final String DEFAULT_SCREEN_SIZE = "1280x720"; public static final String DEFAULT_GRAPHICS_DRIVER = "turnip"; public static final String DEFAULT_AUDIO_DRIVER = "alsa"; - public static final String DEFAULT_DXWRAPPER = "wined3d"; - public static final String DEFAULT_WINCOMPONENTS = "direct3d=1,directsound=1,directmusic=0,directshow=0,directplay=0,vcrun2010=1"; - public static final String FALLBACK_WINCOMPONENTS = "direct3d=0,directsound=0,directmusic=0,directshow=0,directplay=0,vcrun2010=0"; + public static final String DEFAULT_DXWRAPPER = "dxvk"; + public static final String DEFAULT_WINCOMPONENTS = "direct3d=1,directsound=1,directmusic=0,directshow=0,directplay=0,vcrun2010=1,wmdecoder=1"; + public static final String FALLBACK_WINCOMPONENTS = "direct3d=0,directsound=0,directmusic=0,directshow=0,directplay=0,vcrun2010=0,wmdecoder=0"; public static final String DEFAULT_DRIVES = "D:"+Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)+"E:/data/data/com.winlator/storage"; + public static final byte STARTUP_SELECTION_NORMAL = 0; + public static final byte STARTUP_SELECTION_ESSENTIAL = 1; + public static final byte STARTUP_SELECTION_AGGRESSIVE = 2; public static final byte MAX_DRIVE_LETTERS = 8; public final int id; private String name; @@ -34,14 +36,15 @@ public class Container { private String graphicsDriver = DEFAULT_GRAPHICS_DRIVER; private String dxwrapper = DEFAULT_DXWRAPPER; private String dxwrapperConfig = ""; - private String graphicsDriverConfig = ""; private String wincomponents = DEFAULT_WINCOMPONENTS; private String audioDriver = DEFAULT_AUDIO_DRIVER; private String drives = DEFAULT_DRIVES; private String wineVersion = WineInfo.MAIN_WINE_VERSION.identifier(); private boolean showFPS; - private boolean stopServicesOnStartup = true; + private boolean wow64Mode = true; + private byte startupSelection = STARTUP_SELECTION_ESSENTIAL; private String cpuList; + private String cpuListWoW64; private String desktopTheme = WineThemeManager.DEFAULT_DESKTOP_THEME; private String box86Preset = Box86_64Preset.COMPATIBILITY; private String box64Preset = Box86_64Preset.COMPATIBILITY; @@ -101,14 +104,6 @@ public class Container { this.dxwrapperConfig = dxwrapperConfig != null ? dxwrapperConfig : ""; } - public String getGraphicsDriverConfig() { - return graphicsDriverConfig; - } - - public void setGraphicsDriverConfig(String graphicsDriverConfig) { - this.graphicsDriverConfig = graphicsDriverConfig != null ? graphicsDriverConfig : ""; - } - public String getAudioDriver() { return audioDriver; } @@ -141,22 +136,46 @@ public class Container { this.showFPS = showFPS; } - public boolean isStopServicesOnStartup() { - return stopServicesOnStartup; + public boolean isWoW64Mode() { + return wow64Mode; } - public void setStopServicesOnStartup(boolean stopServicesOnStartup) { - this.stopServicesOnStartup = stopServicesOnStartup; + public void setWoW64Mode(boolean wow64Mode) { + this.wow64Mode = wow64Mode; + } + + public byte getStartupSelection() { + return startupSelection; + } + + public void setStartupSelection(byte startupSelection) { + this.startupSelection = startupSelection; } public String getCPUList() { - return cpuList; + return getCPUList(false); + } + + public String getCPUList(boolean allowFallback) { + return cpuList != null ? cpuList : (allowFallback ? getFallbackCPUList() : null); } public void setCPUList(String cpuList) { this.cpuList = cpuList != null && !cpuList.isEmpty() ? cpuList : null; } + public String getCPUListWoW64() { + return getCPUListWoW64(false); + } + + public String getCPUListWoW64(boolean allowFallback) { + return cpuListWoW64 != null ? cpuListWoW64 : (allowFallback ? getFallbackCPUListWoW64() : null); + } + + public void setCPUListWoW64(String cpuListWoW64) { + this.cpuListWoW64 = cpuListWoW64 != null && !cpuListWoW64.isEmpty() ? cpuListWoW64 : null; + } + public String getBox86Preset() { return box86Preset; } @@ -273,24 +292,22 @@ public class Container { data.put("screenSize", screenSize); data.put("envVars", envVars); data.put("cpuList", cpuList); + data.put("cpuListWoW64", cpuListWoW64); data.put("graphicsDriver", graphicsDriver); data.put("dxwrapper", dxwrapper); if (!dxwrapperConfig.isEmpty()) data.put("dxwrapperConfig", dxwrapperConfig); - if (!graphicsDriverConfig.isEmpty()) data.put("graphicsDriverConfig", graphicsDriverConfig); data.put("audioDriver", audioDriver); data.put("wincomponents", wincomponents); data.put("drives", drives); data.put("showFPS", showFPS); - data.put("stopServicesOnStartup", stopServicesOnStartup); + data.put("wow64Mode", wow64Mode); + data.put("startupSelection", startupSelection); data.put("box86Preset", box86Preset); data.put("box64Preset", box64Preset); data.put("desktopTheme", desktopTheme); data.put("extraData", extraData); - if (!wineVersion.equals(WineInfo.MAIN_WINE_VERSION.identifier())) { - data.put("wineVersion", wineVersion); - } - + if (!WineInfo.isMainWineVersion(wineVersion)) data.put("wineVersion", wineVersion); FileUtils.writeString(getConfigFile(), data.toString()); } catch (JSONException e) {} @@ -299,7 +316,6 @@ public class Container { public void loadData(JSONObject data) throws JSONException { wineVersion = WineInfo.MAIN_WINE_VERSION.identifier(); dxwrapperConfig = ""; - graphicsDriverConfig = ""; checkObsoleteOrMissingProperties(data); for (Iterator it = data.keys(); it.hasNext(); ) { @@ -317,6 +333,9 @@ public class Container { case "cpuList" : setCPUList(data.getString(key)); break; + case "cpuListWoW64" : + setCPUListWoW64(data.getString(key)); + break; case "graphicsDriver" : setGraphicsDriver(data.getString(key)); break; @@ -329,17 +348,17 @@ public class Container { case "dxwrapperConfig" : setDXWrapperConfig(data.getString(key)); break; - case "graphicsDriverConfig" : - setGraphicsDriverConfig(data.getString(key)); - break; case "drives" : setDrives(data.getString(key)); break; case "showFPS" : setShowFPS(data.getBoolean(key)); break; - case "stopServicesOnStartup" : - setStopServicesOnStartup(data.getBoolean(key)); + case "wow64Mode" : + setWoW64Mode(data.getBoolean(key)); + break; + case "startupSelection" : + setStartupSelection((byte)data.getInt(key)); break; case "extraData" : { JSONObject extraData = data.getJSONObject(key); @@ -396,7 +415,7 @@ public class Container { if (data.has("envVars") && data.has("extraData")) { JSONObject extraData = data.getJSONObject("extraData"); int appVersion = Integer.parseInt(extraData.optString("appVersion", "0")); - if (appVersion < 12) { + if (appVersion < 16) { EnvVars defaultEnvVars = new EnvVars(DEFAULT_ENV_VARS); EnvVars envVars = new EnvVars(data.getString("envVars")); for (String name : defaultEnvVars) if (!envVars.has(name)) envVars.put(name, defaultEnvVars.get(name)); @@ -425,4 +444,18 @@ public class Container { } catch (JSONException e) {} } + + public static String getFallbackCPUList() { + String cpuList = ""; + int numProcessors = Runtime.getRuntime().availableProcessors(); + for (int i = 0; i < numProcessors; i++) cpuList += (!cpuList.isEmpty() ? "," : "")+i; + return cpuList; + } + + public static String getFallbackCPUListWoW64() { + String cpuList = ""; + int numProcessors = Runtime.getRuntime().availableProcessors(); + for (int i = numProcessors / 2; i < numProcessors; i++) cpuList += (!cpuList.isEmpty() ? "," : "")+i; + return cpuList; + } } diff --git a/app/src/main/java/com/winlator/container/ContainerManager.java b/app/src/main/java/com/winlator/container/ContainerManager.java index c833dfb..324ea33 100644 --- a/app/src/main/java/com/winlator/container/ContainerManager.java +++ b/app/src/main/java/com/winlator/container/ContainerManager.java @@ -104,7 +104,7 @@ public class ContainerManager { container.setRootDir(containerDir); container.loadData(data); - boolean isMainWineVersion = !data.has("wineVersion") || data.getString("wineVersion").equals(WineInfo.MAIN_WINE_VERSION.identifier()); + boolean isMainWineVersion = !data.has("wineVersion") || WineInfo.isMainWineVersion(data.getString("wineVersion")); if (!isMainWineVersion) container.setWineVersion(data.getString("wineVersion")); if (!extractContainerPatternFile(container.getWineVersion(), containerDir, null)) { @@ -138,15 +138,16 @@ public class ContainerManager { dstContainer.setScreenSize(srcContainer.getScreenSize()); dstContainer.setEnvVars(srcContainer.getEnvVars()); dstContainer.setCPUList(srcContainer.getCPUList()); + dstContainer.setCPUListWoW64(srcContainer.getCPUListWoW64()); dstContainer.setGraphicsDriver(srcContainer.getGraphicsDriver()); dstContainer.setDXWrapper(srcContainer.getDXWrapper()); dstContainer.setDXWrapperConfig(srcContainer.getDXWrapperConfig()); - dstContainer.setGraphicsDriverConfig(srcContainer.getGraphicsDriverConfig()); dstContainer.setAudioDriver(srcContainer.getAudioDriver()); dstContainer.setWinComponents(srcContainer.getWinComponents()); dstContainer.setDrives(srcContainer.getDrives()); dstContainer.setShowFPS(srcContainer.isShowFPS()); - dstContainer.setStopServicesOnStartup(srcContainer.isStopServicesOnStartup()); + dstContainer.setWoW64Mode(srcContainer.isWoW64Mode()); + dstContainer.setStartupSelection(srcContainer.getStartupSelection()); dstContainer.setBox86Preset(srcContainer.getBox86Preset()); dstContainer.setBox64Preset(srcContainer.getBox64Preset()); dstContainer.setDesktopTheme(srcContainer.getDesktopTheme()); @@ -201,7 +202,7 @@ public class ContainerManager { } public boolean extractContainerPatternFile(String wineVersion, File containerDir, OnExtractFileListener onExtractFileListener) { - if (wineVersion == null || wineVersion.equals(WineInfo.MAIN_WINE_VERSION.identifier())) { + if (WineInfo.isMainWineVersion(wineVersion)) { boolean result = TarCompressorUtils.extract(TarCompressorUtils.Type.ZSTD, context, "container_pattern.tzst", containerDir, onExtractFileListener); if (result) { diff --git a/app/src/main/java/com/winlator/container/Shortcut.java b/app/src/main/java/com/winlator/container/Shortcut.java index eb5a3bf..ae5bcfd 100644 --- a/app/src/main/java/com/winlator/container/Shortcut.java +++ b/app/src/main/java/com/winlator/container/Shortcut.java @@ -31,7 +31,7 @@ public class Shortcut { File iconFile = null; String wmClass = ""; - File[] iconDirs = {container.getIconsDir(64), container.getIconsDir(48), container.getIconsDir(32)}; + File[] iconDirs = {container.getIconsDir(64), container.getIconsDir(48), container.getIconsDir(32), container.getIconsDir(16)}; String section = ""; int index; diff --git a/app/src/main/java/com/winlator/contentdialog/AddEnvVarDialog.java b/app/src/main/java/com/winlator/contentdialog/AddEnvVarDialog.java index 2704e2b..70fc497 100644 --- a/app/src/main/java/com/winlator/contentdialog/AddEnvVarDialog.java +++ b/app/src/main/java/com/winlator/contentdialog/AddEnvVarDialog.java @@ -1,40 +1,40 @@ package com.winlator.contentdialog; import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; +import android.view.Menu; import android.widget.EditText; -import android.widget.LinearLayout; -import android.widget.TextView; +import android.widget.PopupMenu; import com.winlator.R; +import com.winlator.widget.EnvVarsView; public class AddEnvVarDialog extends ContentDialog { - public AddEnvVarDialog(final Context context, View container) { + public AddEnvVarDialog(final Context context, final EnvVarsView envVarsView) { super(context, R.layout.add_env_var_dialog); - - EditText etName = findViewById(R.id.ETName); - EditText etValue = findViewById(R.id.ETValue); - final View emptyTextView = container.findViewById(R.id.TVEnvVarsEmptyText); + final EditText etName = findViewById(R.id.ETName); + final EditText etValue = findViewById(R.id.ETValue); setTitle(context.getString(R.string.new_environment_variable)); setIcon(R.drawable.icon_env_var); + findViewById(R.id.BTMenu).setOnClickListener((v) -> { + PopupMenu popupMenu = new PopupMenu(context, v); + Menu menu = popupMenu.getMenu(); + for (String[] knownEnvVar : EnvVarsView.knownEnvVars) menu.add(knownEnvVar[0]); + + popupMenu.setOnMenuItemClickListener((menuItem) -> { + etName.setText(menuItem.getTitle()); + return true; + }); + popupMenu.show(); + }); + setOnConfirmCallback(() -> { String name = etName.getText().toString().trim().replace(" ", ""); String value = etValue.getText().toString().trim().replace(" ", ""); - if (!name.isEmpty() && !value.isEmpty()) { - LinearLayout parent = container.findViewById(R.id.LLEnvVars); - View itemView = LayoutInflater.from(context).inflate(R.layout.env_vars_list_item, parent, false); - ((TextView)itemView.findViewById(R.id.TextView)).setText(name); - ((EditText)itemView.findViewById(R.id.EditText)).setText(value); - itemView.findViewById(R.id.BTRemove).setOnClickListener((v) -> { - parent.removeView(itemView); - emptyTextView.setVisibility(parent.getChildCount() == 0 ? View.VISIBLE : View.GONE); - }); - parent.addView(itemView); - emptyTextView.setVisibility(View.GONE); + if (!name.isEmpty() && !envVarsView.containsName(name)) { + envVarsView.add(name, value); } }); } diff --git a/app/src/main/java/com/winlator/contentdialog/ContentDialog.java b/app/src/main/java/com/winlator/contentdialog/ContentDialog.java index a63a2f6..4bad9c2 100644 --- a/app/src/main/java/com/winlator/contentdialog/ContentDialog.java +++ b/app/src/main/java/com/winlator/contentdialog/ContentDialog.java @@ -123,6 +123,14 @@ public class ContentDialog extends Dialog { } } + public static void alert(Context context, int msgResId, Runnable callback) { + ContentDialog dialog = new ContentDialog(context); + dialog.setMessage(msgResId); + dialog.setOnConfirmCallback(callback); + dialog.findViewById(R.id.BTCancel).setVisibility(View.GONE); + dialog.show(); + } + public static void confirm(Context context, int msgResId, Runnable callback) { ContentDialog dialog = new ContentDialog(context); dialog.setMessage(msgResId); diff --git a/app/src/main/java/com/winlator/contentdialog/DebugDialog.java b/app/src/main/java/com/winlator/contentdialog/DebugDialog.java new file mode 100644 index 0000000..ef97f3c --- /dev/null +++ b/app/src/main/java/com/winlator/contentdialog/DebugDialog.java @@ -0,0 +1,47 @@ +package com.winlator.contentdialog; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageButton; +import android.widget.LinearLayout; + +import androidx.annotation.NonNull; + +import com.winlator.R; +import com.winlator.core.AppUtils; +import com.winlator.core.Callback; +import com.winlator.core.UnitUtils; +import com.winlator.widget.LogView; + +public class DebugDialog extends ContentDialog implements Callback { + private final LogView logView; + private boolean paused = false; + + public DebugDialog(@NonNull Context context) { + super(context, R.layout.debug_dialog); + setIcon(R.drawable.icon_debug); + setTitle(context.getString(R.string.logs)); + logView = findViewById(R.id.LogView); + logView.getLayoutParams().width = (int)UnitUtils.dpToPx(UnitUtils.pxToDp(AppUtils.getScreenWidth()) * 0.7f); + + findViewById(R.id.BTCancel).setVisibility(View.GONE); + + LinearLayout llBottomBarPanel = findViewById(R.id.LLBottomBarPanel); + llBottomBarPanel.setVisibility(View.VISIBLE); + + View toolbarView = LayoutInflater.from(context).inflate(R.layout.debug_toolbar, llBottomBarPanel, false); + toolbarView.findViewById(R.id.BTClear).setOnClickListener((v) -> logView.clear()); + toolbarView.findViewById(R.id.BTPause).setOnClickListener((v) -> { + paused = !paused; + ((ImageButton)v).setImageResource(paused ? R.drawable.icon_play : R.drawable.icon_pause); + }); + toolbarView.findViewById(R.id.BTExport).setOnClickListener((v) -> logView.exportToFile()); + llBottomBarPanel.addView(toolbarView); + } + + @Override + public void call(final String line) { + if (!paused) logView.append(line+"\n"); + } +} diff --git a/app/src/main/java/com/winlator/contentdialog/ShortcutSettingsDialog.java b/app/src/main/java/com/winlator/contentdialog/ShortcutSettingsDialog.java index 97a694b..c2c80fc 100644 --- a/app/src/main/java/com/winlator/contentdialog/ShortcutSettingsDialog.java +++ b/app/src/main/java/com/winlator/contentdialog/ShortcutSettingsDialog.java @@ -1,31 +1,25 @@ package com.winlator.contentdialog; import android.content.Context; -import android.content.res.Resources; -import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.CheckBox; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.PopupMenu; import android.widget.Spinner; -import android.widget.TextView; import com.winlator.ContainerDetailFragment; import com.winlator.R; import com.winlator.ShortcutsFragment; import com.winlator.box86_64.Box86_64PresetManager; -import com.winlator.container.Container; import com.winlator.container.Shortcut; import com.winlator.core.AppUtils; -import com.winlator.core.ArrayUtils; import com.winlator.core.EnvVars; import com.winlator.core.StringUtils; import com.winlator.inputcontrols.ControlsProfile; import com.winlator.inputcontrols.InputControlsManager; +import com.winlator.widget.EnvVarsView; import com.winlator.winhandler.WinHandler; import java.io.File; @@ -66,12 +60,9 @@ public class ShortcutSettingsDialog extends ContentDialog { final View vDXWrapperConfig = findViewById(R.id.BTDXWrapperConfig); vDXWrapperConfig.setTag(shortcut.getExtra("dxwrapperConfig", shortcut.container.getDXWrapperConfig())); - final View vGraphicsDriverConfig = findViewById(R.id.BTGraphicsDriverConfig); - vGraphicsDriverConfig.setTag(shortcut.getExtra("graphicsDriverConfig", shortcut.container.getGraphicsDriverConfig())); - ContainerDetailFragment.setupDXWrapperSpinner(sDXWrapper, vDXWrapperConfig); - ContainerDetailFragment.loadGraphicsDriverSpinner(sGraphicsDriver, sDXWrapper, vGraphicsDriverConfig, - shortcut.getExtra("graphicsDriver", shortcut.container.getGraphicsDriver()), shortcut.getExtra("dxwrapper", shortcut.container.getDXWrapper())); + ContainerDetailFragment.loadGraphicsDriverSpinner(sGraphicsDriver, sDXWrapper, shortcut.getExtra("graphicsDriver", shortcut.container.getGraphicsDriver()), + shortcut.getExtra("dxwrapper", shortcut.container.getDXWrapper())); findViewById(R.id.BTHelpDXWrapper).setOnClickListener((v) -> AppUtils.showHelpBox(context, v, R.string.dxwrapper_help_content)); @@ -93,10 +84,9 @@ public class ShortcutSettingsDialog extends ContentDialog { final Spinner sDInputMapperType = findViewById(R.id.SDInputMapperType); sDInputMapperType.setSelection(Byte.parseByte(shortcut.getExtra("dinputMapperType", String.valueOf(WinHandler.DINPUT_MAPPER_TYPE_XINPUT)))); - createWinComponentsTab(); - createEnvVarsTab(); + ContainerDetailFragment.createWinComponentsTab(getContentView(), shortcut.getExtra("wincomponents", shortcut.container.getWinComponents())); + final EnvVarsView envVarsView = createEnvVarsTab(); - findViewById(R.id.BTAddEnvVar).setOnClickListener((v) -> (new AddEnvVarDialog(context, getContentView())).show()); AppUtils.setupTabLayout(getContentView(), R.id.TabLayout, R.id.LLTabWinComponents, R.id.LLTabEnvVars, R.id.LLTabAdvanced); findViewById(R.id.BTExtraArgsMenu).setOnClickListener((v) -> { @@ -120,20 +110,23 @@ public class ShortcutSettingsDialog extends ContentDialog { String graphicsDriver = StringUtils.parseIdentifier(sGraphicsDriver.getSelectedItem()); String dxwrapper = StringUtils.parseIdentifier(sDXWrapper.getSelectedItem()); String dxwrapperConfig = vDXWrapperConfig.getTag().toString(); - String graphicsDriverConfig = vGraphicsDriverConfig.getTag().toString(); String audioDriver = StringUtils.parseIdentifier(sAudioDriver.getSelectedItem()); + String screenSize = ContainerDetailFragment.getScreenSize(getContentView()); String execArgs = etExecArgs.getText().toString(); shortcut.putExtra("execArgs", !execArgs.isEmpty() ? execArgs : null); - shortcut.putExtra("screenSize", getScreenSize()); + shortcut.putExtra("screenSize", !screenSize.equals(shortcut.container.getScreenSize()) ? screenSize : null); shortcut.putExtra("graphicsDriver", !graphicsDriver.equals(shortcut.container.getGraphicsDriver()) ? graphicsDriver : null); shortcut.putExtra("dxwrapper", !dxwrapper.equals(shortcut.container.getDXWrapper()) ? dxwrapper : null); shortcut.putExtra("dxwrapperConfig", !dxwrapperConfig.equals(shortcut.container.getDXWrapperConfig()) ? dxwrapperConfig : null); - shortcut.putExtra("graphicsDriverConfig", !graphicsDriverConfig.equals(shortcut.container.getGraphicsDriverConfig()) ? graphicsDriverConfig : null); shortcut.putExtra("audioDriver", !audioDriver.equals(shortcut.container.getAudioDriver())? audioDriver : null); shortcut.putExtra("forceFullscreen", cbForceFullscreen.isChecked() ? "1" : null); - shortcut.putExtra("wincomponents", getWinComponents()); - shortcut.putExtra("envVars", getEnvVars()); + + String wincomponents = ContainerDetailFragment.getWinComponents(getContentView()); + shortcut.putExtra("wincomponents", !wincomponents.equals(shortcut.container.getWinComponents()) ? wincomponents : null); + + String envVars = envVarsView.getEnvVars(); + shortcut.putExtra("envVars", !envVars.isEmpty() ? envVars : null); String box86Preset = Box86_64PresetManager.getSpinnerSelectedId(sBox86Preset); String box64Preset = Box86_64PresetManager.getSpinnerSelectedId(sBox64Preset); @@ -141,7 +134,7 @@ public class ShortcutSettingsDialog extends ContentDialog { shortcut.putExtra("box64Preset", !box64Preset.equals(shortcut.container.getBox64Preset()) ? box64Preset : null); int dinputMapperType = sDInputMapperType.getSelectedItemPosition(); - ArrayList profiles = inputControlsManager.getProfiles(); + ArrayList profiles = inputControlsManager.getProfiles(true); int controlsProfile = sControlsProfile.getSelectedItemPosition() > 0 ? profiles.get(sControlsProfile.getSelectedItemPosition()-1).id : 0; shortcut.putExtra("controlsProfile", controlsProfile > 0 ? String.valueOf(controlsProfile) : null); shortcut.putExtra("dinputMapperType", dinputMapperType != WinHandler.DINPUT_MAPPER_TYPE_XINPUT ? String.valueOf(dinputMapperType) : null); @@ -150,35 +143,6 @@ public class ShortcutSettingsDialog extends ContentDialog { }); } - private String getScreenSize() { - Spinner sScreenSize = findViewById(R.id.SScreenSize); - if (sScreenSize.getSelectedItemPosition() == 0) return null; - String value = sScreenSize.getSelectedItem().toString(); - if (value.equalsIgnoreCase("custom")) { - value = Container.DEFAULT_SCREEN_SIZE; - String strWidth = ((EditText)findViewById(R.id.ETScreenWidth)).getText().toString().trim(); - String strHeight = ((EditText)findViewById(R.id.ETScreenHeight)).getText().toString().trim(); - if (strWidth.matches("[0-9]+") && strHeight.matches("[0-9]+")) { - int width = Integer.parseInt(strWidth); - int height = Integer.parseInt(strHeight); - if ((width % 2) == 0 && (height % 2) == 0) return width+"x"+height; - } - } - return StringUtils.parseIdentifier(value); - } - - private String getEnvVars() { - LinearLayout parent = findViewById(R.id.LLEnvVars); - EnvVars envVars = new EnvVars(); - for (int i = 0; i < parent.getChildCount(); i++) { - View child = parent.getChildAt(i); - String name = ((TextView)child.findViewById(R.id.TextView)).getText().toString(); - String value = ((EditText)child.findViewById(R.id.EditText)).getText().toString().trim(); - if (!value.isEmpty()) envVars.put(name, value); - } - return !envVars.isEmpty() ? envVars.toString() : null; - } - private void renameShortcut(String newName) { File parent = shortcut.file.getParentFile(); File newFile = new File(parent, newName+".desktop"); @@ -192,57 +156,13 @@ public class ShortcutSettingsDialog extends ContentDialog { fragment.loadShortcutsList(); } - private String getWinComponents() { - ViewGroup parent = findViewById(R.id.LLTabWinComponents); - int childCount = parent.getChildCount(); - String[] wincomponents = new String[childCount]; - - for (int i = 0; i < childCount; i++) { - View child = parent.getChildAt(i); - Spinner spinner = child.findViewById(R.id.Spinner); - wincomponents[i] = child.getTag().toString()+"="+spinner.getSelectedItemPosition(); - } - - String result = String.join(",", wincomponents); - return !result.equals(shortcut.container.getWinComponents()) ? result : null; - } - - private void createWinComponentsTab() { - final String[] wincomponents = shortcut.getExtra("wincomponents", shortcut.container.getWinComponents()).split(","); - - Context context = fragment.getContext(); - LayoutInflater inflater = LayoutInflater.from(context); - ViewGroup parent = findViewById(R.id.LLTabWinComponents); - - for (String wincomponent : wincomponents) { - String[] parts = wincomponent.split("="); - View itemView = inflater.inflate(R.layout.wincomponent_list_item, parent, false); - ((TextView)itemView.findViewById(R.id.TextView)).setText(StringUtils.getString(context, parts[0])); - ((Spinner)itemView.findViewById(R.id.Spinner)).setSelection(Integer.parseInt(parts[1]), false); - itemView.setTag(parts[0]); - parent.addView(itemView); - } - } - - private void createEnvVarsTab() { - final LinearLayout parent = findViewById(R.id.LLEnvVars); - final View emptyTextView = findViewById(R.id.TVEnvVarsEmptyText); - LayoutInflater inflater = LayoutInflater.from(fragment.getContext()); - final EnvVars envVars = new EnvVars(shortcut.getExtra("envVars")); - - for (String name : envVars) { - final View itemView = inflater.inflate(R.layout.env_vars_list_item, parent, false); - ((TextView)itemView.findViewById(R.id.TextView)).setText(name); - ((EditText)itemView.findViewById(R.id.EditText)).setText(envVars.get(name)); - - itemView.findViewById(R.id.BTRemove).setOnClickListener((v) -> { - parent.removeView(itemView); - if (parent.getChildCount() == 0) emptyTextView.setVisibility(View.VISIBLE); - }); - parent.addView(itemView); - } - - if (envVars.isEmpty()) emptyTextView.setVisibility(View.VISIBLE); + private EnvVarsView createEnvVarsTab() { + final View view = getContentView(); + final Context context = view.getContext(); + final EnvVarsView envVarsView = view.findViewById(R.id.EnvVarsView); + envVarsView.setEnvVars(new EnvVars(shortcut.getExtra("envVars"))); + view.findViewById(R.id.BTAddEnvVar).setOnClickListener((v) -> (new AddEnvVarDialog(context, envVarsView)).show()); + return envVarsView; } private void loadControlsProfileSpinner(Spinner spinner, String selectedValue) { diff --git a/app/src/main/java/com/winlator/contentdialog/StorageInfoDialog.java b/app/src/main/java/com/winlator/contentdialog/StorageInfoDialog.java new file mode 100644 index 0000000..1e99bf5 --- /dev/null +++ b/app/src/main/java/com/winlator/contentdialog/StorageInfoDialog.java @@ -0,0 +1,85 @@ +package com.winlator.contentdialog; + +import android.app.Activity; +import android.widget.TextView; + +import androidx.annotation.NonNull; + +import com.google.android.material.progressindicator.CircularProgressIndicator; +import com.winlator.R; +import com.winlator.container.Container; +import com.winlator.core.Callback; +import com.winlator.core.FileUtils; +import com.winlator.core.StringUtils; + +import java.io.File; +import java.util.concurrent.atomic.AtomicLong; + +public class StorageInfoDialog extends ContentDialog { + public StorageInfoDialog(@NonNull Activity activity, Container container) { + super(activity, R.layout.container_storage_info_dialog); + + setTitle(R.string.storage_info); + setIcon(R.drawable.icon_info); + + AtomicLong driveCSize = new AtomicLong(); + driveCSize.set(0); + + AtomicLong cacheSize = new AtomicLong(); + cacheSize.set(0); + + AtomicLong totalSize = new AtomicLong(); + totalSize.set(0); + + final TextView tvDriveCSize = findViewById(R.id.TVDriveCSize); + final TextView tvCacheSize = findViewById(R.id.TVCacheSize); + final TextView tvTotalSize = findViewById(R.id.TVTotalSize); + final TextView tvUsedSpace = findViewById(R.id.TVUsedSpace); + final CircularProgressIndicator circularProgressIndicator = findViewById(R.id.CircularProgressIndicator); + + final long internalStorageSize = FileUtils.getInternalStorageSize(); + + Runnable updateUI = () -> { + tvDriveCSize.setText(StringUtils.formatBytes(driveCSize.get())); + tvCacheSize.setText(StringUtils.formatBytes(cacheSize.get())); + tvTotalSize.setText(StringUtils.formatBytes(totalSize.get())); + + int progress = (int)(((double)totalSize.get() / internalStorageSize) * 100); + tvUsedSpace.setText(progress+"%"); + circularProgressIndicator.setProgress(progress, true); + }; + + File rootDir = container.getRootDir(); + final File driveCDir = new File(rootDir, ".wine/drive_c"); + final File cacheDir = new File(rootDir, ".cache"); + AtomicLong lastTime = new AtomicLong(System.currentTimeMillis()); + + final Callback onAddSize = (size) -> { + totalSize.addAndGet(size); + long currTime = System.currentTimeMillis(); + int elapsedTime = (int)(currTime - lastTime.get()); + if (elapsedTime > 30) { + activity.runOnUiThread(updateUI); + lastTime.set(currTime); + } + }; + + FileUtils.getSizeAsync(driveCDir, (size) -> { + driveCSize.addAndGet(size); + onAddSize.call(size); + }); + + FileUtils.getSizeAsync(cacheDir, (size) -> { + cacheSize.addAndGet(size); + onAddSize.call(size); + }); + + ((TextView)findViewById(R.id.BTCancel)).setText(R.string.clear_cache); + setOnCancelCallback(() -> { + FileUtils.clear(cacheDir); + + container.putExtra("desktopTheme", null); + container.saveData(); + }); + } +} diff --git a/app/src/main/java/com/winlator/contentdialog/TurnipConfigDialog.java b/app/src/main/java/com/winlator/contentdialog/TurnipConfigDialog.java deleted file mode 100644 index f498567..0000000 --- a/app/src/main/java/com/winlator/contentdialog/TurnipConfigDialog.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.winlator.contentdialog; - -import android.content.Context; -import android.view.View; -import android.view.ViewGroup; -import android.widget.CheckBox; -import android.widget.LinearLayout; -import android.widget.Spinner; - -import com.winlator.R; -import com.winlator.core.AppUtils; -import com.winlator.core.DefaultVersion; -import com.winlator.core.EnvVars; -import com.winlator.core.KeyValueSet; -import com.winlator.core.StringUtils; -import com.winlator.core.UnitUtils; - -public class TurnipConfigDialog extends ContentDialog { - private static final String[] DEBUG_OPTIONS = {"noconform", "syncdraw", "flushall"}; - - public TurnipConfigDialog(View anchor) { - super(anchor.getContext(), R.layout.turnip_config_dialog); - Context context = anchor.getContext(); - setIcon(R.drawable.icon_settings); - setTitle("Turnip "+context.getString(R.string.configuration)); - - final Spinner sVersion = findViewById(R.id.SVersion); - - KeyValueSet config = parseConfig(context, anchor.getTag()); - AppUtils.setSpinnerSelectionFromIdentifier(sVersion, config.get("version")); - loadDebugOptions(config.get("options")); - - setOnConfirmCallback(() -> { - config.put("version", StringUtils.parseNumber(sVersion.getSelectedItem())); - config.put("options", getDebugOptions()); - anchor.setTag(config.toString()); - }); - } - - private static String getDefaultConfig(Context context) { - return "version="+DefaultVersion.TURNIP(context)+",options=noconform"; - } - - private String getDebugOptions() { - String options = ""; - LinearLayout container = findViewById(R.id.LLOptions); - - for (int i = 0; i < container.getChildCount(); i++) { - CheckBox checkBox = (CheckBox)container.getChildAt(i); - if (checkBox.isChecked()) options += (!options.isEmpty() ? "|" : "")+checkBox.getText(); - } - - return options; - } - - private void loadDebugOptions(String options) { - LinearLayout container = findViewById(R.id.LLOptions); - container.removeAllViews(); - Context context = container.getContext(); - - LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); - params.setMargins(0, 0, (int)UnitUtils.dpToPx(4), 0); - for (String opt : DEBUG_OPTIONS) { - CheckBox checkBox = new CheckBox(context); - checkBox.setText(opt); - checkBox.setLayoutParams(params); - checkBox.setChecked(options.contains(opt)); - container.addView(checkBox); - } - } - - public static KeyValueSet parseConfig(Context context, Object config) { - String data = config != null && !config.toString().isEmpty() ? config.toString() : getDefaultConfig(context); - return new KeyValueSet(data); - } - - public static void setEnvVars(KeyValueSet config, EnvVars envVars) { - String options = config.get("options"); - if (!options.isEmpty()) envVars.put("TU_DEBUG", options.replace("|", ",")); - } -} diff --git a/app/src/main/java/com/winlator/core/AppUtils.java b/app/src/main/java/com/winlator/core/AppUtils.java index 7d17eb7..578dd85 100644 --- a/app/src/main/java/com/winlator/core/AppUtils.java +++ b/app/src/main/java/com/winlator/core/AppUtils.java @@ -21,7 +21,6 @@ import android.view.WindowInsets; import android.view.WindowInsetsController; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; -import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.PopupWindow; import android.widget.Spinner; @@ -34,6 +33,7 @@ import com.google.android.material.tabs.TabLayout; import com.winlator.R; import java.lang.ref.WeakReference; +import java.util.ArrayList; public abstract class AppUtils { private static WeakReference globalToastReference = null; @@ -54,6 +54,13 @@ public abstract class AppUtils { return "armhf"; } + public static void restartActivity(AppCompatActivity activity) { + Intent intent = activity.getIntent(); + activity.finish(); + activity.startActivity(intent); + activity.overridePendingTransition(0, 0); + } + public static void restartApplication(Context context) { restartApplication(context, 0); } @@ -297,4 +304,17 @@ public abstract class AppUtils { }); tabLayout.getTabAt(0).select(); } + + public static void findViewsWithClass(ViewGroup parent, Class viewClass, ArrayList outViews) { + for (int i = 0, childCount = parent.getChildCount(); i < childCount; i++) { + View child = parent.getChildAt(i); + Class _class = child.getClass(); + if (_class == viewClass || _class.getSuperclass() == viewClass) { + outViews.add(child); + } + else if (child instanceof ViewGroup) { + findViewsWithClass((ViewGroup)child, viewClass, outViews); + } + } + } } diff --git a/app/src/main/java/com/winlator/core/CubicBezierInterpolator.java b/app/src/main/java/com/winlator/core/CubicBezierInterpolator.java new file mode 100644 index 0000000..d639ed6 --- /dev/null +++ b/app/src/main/java/com/winlator/core/CubicBezierInterpolator.java @@ -0,0 +1,62 @@ +package com.winlator.core; + +import android.graphics.PointF; +import android.view.animation.Interpolator; + +public class CubicBezierInterpolator implements Interpolator { + public final PointF start; + public final PointF end; + private float ax, bx, cx; + + public CubicBezierInterpolator() { + this(new PointF(0, 0), new PointF(0, 0)); + } + + public CubicBezierInterpolator(PointF start, PointF end) { + this.start = start; + this.end = end; + } + + public CubicBezierInterpolator(float x1, float y1, float x2, float y2) { + this(new PointF(x1, y1), new PointF(x2, y2)); + } + + public void set(float x1, float y1, float x2, float y2) { + start.set(x1, y1); + end.set(x2, y2); + } + + @Override + public float getInterpolation(float time) { + return getBezierCoordinateY(getXForTime(time)); + } + + private float getBezierCoordinateY(float time) { + float cy = 3 * start.y; + float by = 3 * (end.y - start.y) - cy; + float ay = 1 - cy - by; + return time * (cy + time * (by + time * ay)); + } + + private float getXForTime(float time) { + float x = time; + float z; + for (int i = 1; i < 14; i++) { + z = getBezierCoordinateX(x) - time; + if (Math.abs(z) < 1e-3) break; + x -= z / getXDerivate(x); + } + return x; + } + + private float getXDerivate(float t) { + return cx + t * (2 * bx + 3 * ax * t); + } + + private float getBezierCoordinateX(float time) { + cx = 3 * start.x; + bx = 3 * (end.x - start.x) - cx; + ax = 1 - cx - bx; + return time * (cx + time * (bx + time * ax)); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/winlator/core/CursorLocker.java b/app/src/main/java/com/winlator/core/CursorLocker.java index 444398a..3f8cd0c 100644 --- a/app/src/main/java/com/winlator/core/CursorLocker.java +++ b/app/src/main/java/com/winlator/core/CursorLocker.java @@ -1,18 +1,17 @@ package com.winlator.core; import com.winlator.math.Mathf; -import com.winlator.xserver.Window; import com.winlator.xserver.XServer; import java.util.Timer; import java.util.TimerTask; public class CursorLocker extends TimerTask { - public enum State {NONE, LOCKED, CONFINED} private final XServer xServer; - private State state = State.CONFINED; private float damping = 0.25f; private short maxDistance; + private boolean enabled = true; + private final Object pauseLock = new Object(); public CursorLocker(XServer xServer) { this.xServer = xServer; @@ -37,40 +36,45 @@ public class CursorLocker extends TimerTask { this.damping = damping; } - public State getState() { - return state; + public boolean isEnabled() { + return enabled; } - public void setState(State state) { - this.state = state; + public void setEnabled(boolean enabled) { + if (enabled) { + synchronized (pauseLock) { + this.enabled = true; + pauseLock.notifyAll(); + } + } + else this.enabled = enabled; } @Override public void run() { - if (state == State.LOCKED) { - Window window = xServer.inputDeviceManager.getPointWindow(); - short centerX = (short)(window.getRootX() + window.getWidth() / 2); - short centerY = (short)(window.getRootY() + window.getHeight() / 2); - xServer.pointer.setX(centerX); - xServer.pointer.setY(centerY); - + synchronized (pauseLock) { + if (!enabled) { + try { + pauseLock.wait(); + } + catch (InterruptedException e) {} + } } - else if (state == State.CONFINED) { - short x = (short)Mathf.clamp(xServer.pointer.getX(), -maxDistance, xServer.screenInfo.width + maxDistance); - short y = (short)Mathf.clamp(xServer.pointer.getY(), -maxDistance, xServer.screenInfo.height + maxDistance); - if (x < 0) { - xServer.pointer.setX((short)Math.ceil(x * damping)); - } - else if (x >= xServer.screenInfo.width) { - xServer.pointer.setX((short)Math.floor(xServer.screenInfo.width + (x - xServer.screenInfo.width) * damping)); - } - if (y < 0) { - xServer.pointer.setY((short)Math.ceil(y * damping)); - } - else if (y >= xServer.screenInfo.height) { - xServer.pointer.setY((short)Math.floor(xServer.screenInfo.height + (y - xServer.screenInfo.height) * damping)); - } + short x = (short)Mathf.clamp(xServer.pointer.getX(), -maxDistance, xServer.screenInfo.width + maxDistance); + short y = (short)Mathf.clamp(xServer.pointer.getY(), -maxDistance, xServer.screenInfo.height + maxDistance); + + if (x < 0) { + xServer.pointer.setX((short)Math.ceil(x * damping)); + } + else if (x >= xServer.screenInfo.width) { + xServer.pointer.setX((short)Math.floor(xServer.screenInfo.width + (x - xServer.screenInfo.width) * damping)); + } + if (y < 0) { + xServer.pointer.setY((short)Math.ceil(y * damping)); + } + else if (y >= xServer.screenInfo.height) { + xServer.pointer.setY((short)Math.floor(xServer.screenInfo.height + (y - xServer.screenInfo.height) * damping)); } } } diff --git a/app/src/main/java/com/winlator/core/DefaultVersion.java b/app/src/main/java/com/winlator/core/DefaultVersion.java index 6c4fe89..18a6616 100644 --- a/app/src/main/java/com/winlator/core/DefaultVersion.java +++ b/app/src/main/java/com/winlator/core/DefaultVersion.java @@ -1,15 +1,13 @@ package com.winlator.core; -import android.content.Context; - public abstract class DefaultVersion { - public static final String BOX86 = "0.3.0"; - public static final String BOX64 = "0.2.6"; - public static final String ZINK = "22.2.2"; - public static final String VIRGL = "22.1.7"; + public static final String BOX86 = "0.3.2"; + public static final String BOX64 = "0.2.8"; + public static final String TURNIP = "24.1.0"; + public static final String ZINK = "22.2.5"; + public static final String VIRGL = "23.1.9"; public static final String DXVK = "1.10.3"; - - public static String TURNIP(Context context) { - return GPUInformation.isAdreno6xx(context) ? "23.0.0" : "24.1.0"; - } -} + public static final String D8VK = "1.0"; + public static final String VKD3D = "2.12"; + public static final String CNC_DDRAW = "6.6"; +} \ No newline at end of file diff --git a/app/src/main/java/com/winlator/core/ElfHelper.java b/app/src/main/java/com/winlator/core/ElfHelper.java new file mode 100644 index 0000000..07ce908 --- /dev/null +++ b/app/src/main/java/com/winlator/core/ElfHelper.java @@ -0,0 +1,31 @@ +package com.winlator.core; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +public abstract class ElfHelper { + private static final byte ELF_CLASS_32 = 1; + private static final byte ELF_CLASS_64 = 2; + + private static int getEIClass(File binFile) { + try (InputStream inStream = new FileInputStream(binFile)) { + byte[] header = new byte[52]; + inStream.read(header); + if (header[0] == 0x7F && header[1] == 'E' && header[2] == 'L' && header[3] == 'F') { + return header[4]; + } + } + catch (IOException e) {} + return 0; + } + + public static boolean is32Bit(File binFile) { + return getEIClass(binFile) == ELF_CLASS_32; + } + + public static boolean is64Bit(File binFile) { + return getEIClass(binFile) == ELF_CLASS_64; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/winlator/core/GPUInformation.java b/app/src/main/java/com/winlator/core/GPUInformation.java index 3830a70..98c9264 100644 --- a/app/src/main/java/com/winlator/core/GPUInformation.java +++ b/app/src/main/java/com/winlator/core/GPUInformation.java @@ -3,9 +3,9 @@ package com.winlator.core; import android.content.Context; import android.content.SharedPreferences; import android.opengl.EGL14; -import android.preference.PreferenceManager; import androidx.collection.ArrayMap; +import androidx.preference.PreferenceManager; import java.util.Locale; import java.util.Objects; diff --git a/app/src/main/java/com/winlator/core/MSBitmap.java b/app/src/main/java/com/winlator/core/MSBitmap.java index a21f117..6a43a1c 100644 --- a/app/src/main/java/com/winlator/core/MSBitmap.java +++ b/app/src/main/java/com/winlator/core/MSBitmap.java @@ -4,13 +4,83 @@ import android.graphics.Bitmap; import android.graphics.Color; import java.io.File; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; public abstract class MSBitmap { + public static Bitmap open(File targetFile) { + if (!targetFile.isFile()) return null; + byte[] bytes = FileUtils.read(targetFile); + if (bytes == null) return null; + + ByteBuffer data = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); + if (data.getShort() != 0x4d42) return null; + + int fileSize = data.getInt(); + if (fileSize > targetFile.length()) return null; + + data.getInt(); + int dataOffset = data.getInt(); + int infoHeaderSize = data.getInt(); + int width = data.getInt(); + int height = data.getInt(); + short planes = data.getShort(); + short bitCount = data.getShort(); + int compression = data.getInt(); + int imageSize = data.getInt(); + int hr = data.getInt(); + int vr = data.getInt(); + int colorsUsed = data.getInt(); + int colorsImportant = data.getInt(); + + if (width == 0 || height == 0) return null; + + boolean invertY = true; + if (height < 0) { + height *= -1; + invertY = false; + } + + ByteBuffer pixels = ByteBuffer.allocate(width * height * 4); + byte r1 = 0, g1 = 0, b1 = 0, r2 = 0, g2 = 0, b2 = 0; + boolean started = false; + boolean blank = true; + for (int y = height - 1, i = data.position(), j, line; y >= 0; y--) { + line = invertY ? y : height - 1 - y; + + for (int x = 0; x < width; x++) { + j = line * width * 4 + x * 4; + b1 = data.get(i++); + g1 = data.get(i++); + r1 = data.get(i++); + pixels.put(j+2, b1); + pixels.put(j+1, g1); + pixels.put(j+0, r1); + pixels.put(j+3, (byte)255); + + if (!started) { + b2 = b1; + g2 = g1; + r2 = r1; + started = true; + } + else if (r1 != r2 || b1 != b2 || g1 != g2) { + blank = false; + } + } + + i += width % 4; + } + + if (blank) return null; + + Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + bitmap.copyPixelsFromBuffer(pixels); + return bitmap; + } + public static boolean create(Bitmap bitmap, File outputFile) { int width = bitmap.getWidth(); int height = bitmap.getHeight(); @@ -32,7 +102,7 @@ public abstract class MSBitmap { ByteBuffer buffer = ByteBuffer.allocate(dataOffset + imageSize).order(ByteOrder.LITTLE_ENDIAN); - buffer.put(new byte[]{'B', 'M'}); + buffer.putShort((short)0x4d42); // "BM" buffer.putInt(dataOffset + imageSize); buffer.putInt(0); buffer.putInt(dataOffset); diff --git a/app/src/main/java/com/winlator/core/MSLogFont.java b/app/src/main/java/com/winlator/core/MSLogFont.java new file mode 100644 index 0000000..cc83792 --- /dev/null +++ b/app/src/main/java/com/winlator/core/MSLogFont.java @@ -0,0 +1,167 @@ +package com.winlator.core; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +public class MSLogFont { + private int height = -11; + private int width = 0; + private int escapement = 0; + private int orientation = 0; + private int weight = 400; + private byte italic = 0; + private byte underline = 0; + private byte strikeOut = 0; + private byte charSet = 0; + private byte outPrecision = 0; + private byte clipPrecision = 0; + private byte quality = 0; + private byte pitchAndFamily = 34; + private String faceName = "Tahoma"; + + public int getHeight() { + return height; + } + + public MSLogFont setHeight(int height) { + this.height = height; + return this; + } + + public int getWidth() { + return width; + } + + public MSLogFont setWidth(int width) { + this.width = width; + return this; + } + + public int getEscapement() { + return escapement; + } + + public MSLogFont setEscapement(int escapement) { + this.escapement = escapement; + return this; + } + + public int getOrientation() { + return orientation; + } + + public MSLogFont setOrientation(int orientation) { + this.orientation = orientation; + return this; + } + + public int getWeight() { + return weight; + } + + public MSLogFont setWeight(int weight) { + this.weight = weight; + return this; + } + + public byte getItalic() { + return italic; + } + + public MSLogFont setItalic(byte italic) { + this.italic = italic; + return this; + } + + public byte getUnderline() { + return underline; + } + + public MSLogFont setUnderline(byte underline) { + this.underline = underline; + return this; + } + + public byte getStrikeOut() { + return strikeOut; + } + + public MSLogFont setStrikeOut(byte strikeOut) { + this.strikeOut = strikeOut; + return this; + } + + public byte getCharSet() { + return charSet; + } + + public MSLogFont setCharSet(byte charSet) { + this.charSet = charSet; + return this; + } + + public byte getOutPrecision() { + return outPrecision; + } + + public MSLogFont setOutPrecision(byte outPrecision) { + this.outPrecision = outPrecision; + return this; + } + + public byte getClipPrecision() { + return clipPrecision; + } + + public MSLogFont setClipPrecision(byte clipPrecision) { + this.clipPrecision = clipPrecision; + return this; + } + + public byte getQuality() { + return quality; + } + + public MSLogFont setQuality(byte quality) { + this.quality = quality; + return this; + } + + public byte getPitchAndFamily() { + return pitchAndFamily; + } + + public MSLogFont setPitchAndFamily(byte pitchAndFamily) { + this.pitchAndFamily = pitchAndFamily; + return this; + } + + public String getFaceName() { + return faceName; + } + + public MSLogFont setFaceName(String faceName) { + this.faceName = faceName; + return this; + } + + public byte[] toByteArray() { + ByteBuffer data = ByteBuffer.allocate(92).order(ByteOrder.LITTLE_ENDIAN); + data.putInt(height); + data.putInt(width); + data.putInt(escapement); + data.putInt(orientation); + data.putInt(weight); + data.put(italic); + data.put(underline); + data.put(strikeOut); + data.put(charSet); + data.put(outPrecision); + data.put(clipPrecision); + data.put(quality); + data.put(pitchAndFamily); + + for (int i = 0; i < faceName.length(); i++) data.putChar(faceName.charAt(i)); + return data.array(); + } +} diff --git a/app/src/main/java/com/winlator/core/NetworkHelper.java b/app/src/main/java/com/winlator/core/NetworkHelper.java new file mode 100644 index 0000000..885bd8b --- /dev/null +++ b/app/src/main/java/com/winlator/core/NetworkHelper.java @@ -0,0 +1,63 @@ +package com.winlator.core; + +import android.content.Context; +import android.net.DhcpInfo; +import android.net.wifi.WifiManager; + +import java.net.InetAddress; +import java.net.InterfaceAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.UnknownHostException; + +public class NetworkHelper { + private final WifiManager wifiManager; + + public NetworkHelper(Context context) { + wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE); + } + + public int getIpAddress() { + return wifiManager != null ? wifiManager.getConnectionInfo().getIpAddress() : 0; + } + + public int getNetmask() { + if (wifiManager == null) return 0; + + DhcpInfo dhcpInfo = wifiManager.getDhcpInfo(); + if (dhcpInfo == null) return 0; + + int netmask = Integer.bitCount(dhcpInfo.netmask); + if (dhcpInfo.netmask < 8 || dhcpInfo.netmask > 32) { + try { + InetAddress inetAddress = InetAddress.getByName(formatIpAddress(getIpAddress())); + NetworkInterface networkInterface = NetworkInterface.getByInetAddress(inetAddress); + if (networkInterface != null) { + for (InterfaceAddress address : networkInterface.getInterfaceAddresses()) { + if (inetAddress != null && inetAddress.equals(address.getAddress())) { + netmask = address.getNetworkPrefixLength(); + break; + } + } + } + } + catch (SocketException | UnknownHostException ignored) {} + } + + return netmask; + } + + public int getGateway() { + if (wifiManager == null) return 0; + DhcpInfo dhcpInfo = wifiManager.getDhcpInfo(); + return dhcpInfo != null ? dhcpInfo.gateway : 0; + } + + public static String formatIpAddress(int ipAddress) { + return (ipAddress & 255)+"."+((ipAddress >> 8) & 255)+"."+((ipAddress >> 16) & 255)+"."+((ipAddress >> 24) & 255); + } + + public static String formatNetmask(int netmask) { + return netmask == 24 ? "255.255.255.0" : (netmask == 16 ? "255.255.0.0" : (netmask == 8 ? "255.0.0.0" : "0.0.0.0")); + } +} diff --git a/app/src/main/java/com/winlator/core/ProcessHelper.java b/app/src/main/java/com/winlator/core/ProcessHelper.java index b2c505c..31d237d 100644 --- a/app/src/main/java/com/winlator/core/ProcessHelper.java +++ b/app/src/main/java/com/winlator/core/ProcessHelper.java @@ -1,12 +1,9 @@ package com.winlator.core; -import android.os.Environment; import android.os.Process; import java.io.BufferedReader; -import java.io.BufferedWriter; import java.io.File; -import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -15,9 +12,8 @@ import java.util.ArrayList; import java.util.concurrent.Executors; public abstract class ProcessHelper { - public static boolean debugMode = false; - public static Callback debugCallback; - public static boolean generateDebugFile = false; + public static final boolean PRINT_DEBUG = false; // FIXME change to false + private static final ArrayList> debugCallbacks = new ArrayList<>(); private static final byte SIGCONT = 18; private static final byte SIGSTOP = 19; @@ -50,10 +46,9 @@ public abstract class ProcessHelper { pid = pidField.getInt(process); pidField.setAccessible(false); - Callback debugCallback = ProcessHelper.debugCallback; - if (debugMode || debugCallback != null) { - createDebugThread(false, process.getInputStream(), debugCallback); - createDebugThread(true, process.getErrorStream(), debugCallback); + if (!debugCallbacks.isEmpty()) { + createDebugThread(process.getInputStream()); + createDebugThread(process.getErrorStream()); } if (terminationCallback != null) createWaitForThread(process, terminationCallback); @@ -62,25 +57,16 @@ public abstract class ProcessHelper { return pid; } - private static void createDebugThread(boolean isError, final InputStream inputStream, final Callback debugCallback) { + private static void createDebugThread(final InputStream inputStream) { Executors.newSingleThreadExecutor().execute(() -> { try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { String line; - if (debugMode && generateDebugFile) { - File winlatorDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "Winlator"); - winlatorDir.mkdirs(); - final File debugFile = new File(winlatorDir, isError ? "debug-err.txt" : "debug-out.txt"); - if (debugFile.isFile()) debugFile.delete(); - try (BufferedWriter writer = new BufferedWriter(new FileWriter(debugFile))) { - while ((line = reader.readLine()) != null) writer.write(line+"\n"); - } - } - else { - while ((line = reader.readLine()) != null) { - if (debugCallback != null) { - debugCallback.call(line); + while ((line = reader.readLine()) != null) { + if (PRINT_DEBUG) System.out.println(line); + synchronized (debugCallbacks) { + if (!debugCallbacks.isEmpty()) { + for (Callback callback : debugCallbacks) callback.call(line); } - else System.out.println(line); } } } @@ -98,6 +84,24 @@ public abstract class ProcessHelper { }); } + public static void removeAllDebugCallbacks() { + synchronized (debugCallbacks) { + debugCallbacks.clear(); + } + } + + public static void addDebugCallback(Callback callback) { + synchronized (debugCallbacks) { + if (!debugCallbacks.contains(callback)) debugCallbacks.add(callback); + } + } + + public static void removeDebugCallback(Callback callback) { + synchronized (debugCallbacks) { + debugCallbacks.remove(callback); + } + } + public static String[] splitCommand(String command) { ArrayList result = new ArrayList<>(); boolean startedQuotes = false; @@ -146,7 +150,7 @@ public abstract class ProcessHelper { return result.toArray(new String[0]); } - public static String getAffinityMask(String cpuList) { + public static String getAffinityMaskAsHexString(String cpuList) { String[] values = cpuList.split(","); int affinityMask = 0; for (String value : values) { @@ -156,6 +160,17 @@ public abstract class ProcessHelper { return Integer.toHexString(affinityMask); } + public static int getAffinityMask(String cpuList) { + if (cpuList == null || cpuList.isEmpty()) return 0; + String[] values = cpuList.split(","); + int affinityMask = 0; + for (String value : values) { + byte index = Byte.parseByte(value); + affinityMask |= (int)Math.pow(2, index); + } + return affinityMask; + } + public static int getAffinityMask(boolean[] cpuList) { int affinityMask = 0; for (int i = 0; i < cpuList.length; i++) { @@ -163,4 +178,10 @@ public abstract class ProcessHelper { } return affinityMask; } + + public static int getAffinityMask(int from, int to) { + int affinityMask = 0; + for (int i = from; i < to; i++) affinityMask |= (int)Math.pow(2, i); + return affinityMask; + } } diff --git a/app/src/main/java/com/winlator/core/StringUtils.java b/app/src/main/java/com/winlator/core/StringUtils.java index 0cb7758..e6b5395 100644 --- a/app/src/main/java/com/winlator/core/StringUtils.java +++ b/app/src/main/java/com/winlator/core/StringUtils.java @@ -36,16 +36,14 @@ public class StringUtils { } public static String getString(Context context, String resName) { - String string = null; try { resName = resName.toLowerCase(Locale.ENGLISH); int resID = context.getResources().getIdentifier(resName, "string", context.getPackageName()); - string = context.getString(resID); + return context.getString(resID); } catch (Exception e) { - e.printStackTrace(); + return null; } - return string != null && !string.isEmpty() ? string : resName; } public static String formatBytes(long bytes) { diff --git a/app/src/main/java/com/winlator/core/WineInfo.java b/app/src/main/java/com/winlator/core/WineInfo.java index b767bac..6d67a2c 100644 --- a/app/src/main/java/com/winlator/core/WineInfo.java +++ b/app/src/main/java/com/winlator/core/WineInfo.java @@ -13,7 +13,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; public class WineInfo implements Parcelable { - public static final WineInfo MAIN_WINE_VERSION = new WineInfo("8.0.2", "x86_64"); + public static final WineInfo MAIN_WINE_VERSION = new WineInfo("9.2", "x86_64"); private static final Pattern pattern = Pattern.compile("^wine\\-([0-9\\.]+)\\-?([0-9\\.]+)?\\-(x86|x86_64)$"); public final String version; public final String subversion; @@ -53,12 +53,22 @@ public class WineInfo implements Parcelable { return arch.equals("x86_64"); } - public String binName() { - return isWin64() ? "wine64" : "wine"; + public String getExecutable(Context context, boolean wow64Mode) { + if (this == MAIN_WINE_VERSION) { + File wineBinDir = new File(ImageFs.find(context).getRootDir(), "/opt/wine/bin"); + File wineBinFile = new File(wineBinDir, "wine"); + File winePreloaderBinFile = new File(wineBinDir, "wine-preloader"); + FileUtils.copy(new File(wineBinDir, wow64Mode ? "wine-wow64" : "wine32"), wineBinFile); + FileUtils.copy(new File(wineBinDir, wow64Mode ? "wine-preloader-wow64" : "wine32-preloader"), winePreloaderBinFile); + FileUtils.chmod(wineBinFile, 0771); + FileUtils.chmod(winePreloaderBinFile, 0771); + return wow64Mode ? "wine" : "wine64"; + } + else return (new File(path, "/bin/wine64")).isFile() ? "wine64" : "wine"; } public String identifier() { - return "wine-"+fullVersion()+"-"+arch; + return "wine-"+fullVersion()+"-"+(this == MAIN_WINE_VERSION ? "custom" : arch); } public String fullVersion() { @@ -68,7 +78,7 @@ public class WineInfo implements Parcelable { @NonNull @Override public String toString() { - return "Wine "+fullVersion()+" ("+arch+")"; + return "Wine "+fullVersion()+(this == MAIN_WINE_VERSION ? " (Custom)" : ""); } @Override @@ -105,4 +115,8 @@ public class WineInfo implements Parcelable { } else return MAIN_WINE_VERSION; } + + public static boolean isMainWineVersion(String wineVersion) { + return wineVersion == null ||wineVersion.equals(MAIN_WINE_VERSION.identifier()); + } } diff --git a/app/src/main/java/com/winlator/core/WineRegistryEditor.java b/app/src/main/java/com/winlator/core/WineRegistryEditor.java index 27efde1..5f901ee 100644 --- a/app/src/main/java/com/winlator/core/WineRegistryEditor.java +++ b/app/src/main/java/com/winlator/core/WineRegistryEditor.java @@ -17,19 +17,22 @@ public class WineRegistryEditor implements Closeable { private final File file; private final File cloneFile; private boolean modified = false; + private boolean createKeyIfNotExist = true; + private int lastParentKeyPosition = 0; + private String lastParentKey = ""; - private static class Location { - private final int offset; - private final int start; - private final int end; + public static class Location { + public final int offset; + public final int start; + public final int end; - private Location(int offset, int start, int end) { + public Location(int offset, int start, int end) { this.offset = offset; this.start = start; this.end = end; } - private int length() { + public int length() { return end - start; } } @@ -69,7 +72,25 @@ public class WineRegistryEditor implements Closeable { else cloneFile.delete(); } + private void resetLastParentKeyPositionIfNeed(String newKey) { + int lastIndex = newKey.lastIndexOf("\\"); + if (lastIndex == -1) { + lastParentKeyPosition = 0; + lastParentKey = ""; + return; + } + + String parentKey = newKey.substring(0, lastIndex); + if (!parentKey.equals(lastParentKey)) lastParentKeyPosition = 0; + lastParentKey = parentKey; + } + + public void setCreateKeyIfNotExist(boolean createKeyIfNotExist) { + this.createKeyIfNotExist = createKeyIfNotExist; + } + private Location createKey(String key) { + lastParentKeyPosition = 0; Location location = getParentKeyLocation(key); boolean success = false; int offset = 0; @@ -153,7 +174,14 @@ public class WineRegistryEditor implements Closeable { setRawValue(key, name, "hex:"+lines); } + public void setHexValue(String key, String name, byte[] bytes) { + StringBuilder data = new StringBuilder(); + for (byte b : bytes) data.append(String.format(Locale.ENGLISH, "%02x", Byte.toUnsignedInt(b))); + setHexValue(key, name, data.toString()); + } + private String getRawValue(String key, String name) { + lastParentKeyPosition = 0; Location keyLocation = getKeyLocation(key); if (keyLocation == null) return null; @@ -171,8 +199,16 @@ public class WineRegistryEditor implements Closeable { } private void setRawValue(String key, String name, String value) { + resetLastParentKeyPositionIfNeed(key); + Location keyLocation = getKeyLocation(key); - if (keyLocation == null) keyLocation = createKey(key); + if (keyLocation == null) { + if (createKeyIfNotExist) { + keyLocation = createKey(key); + } + else return; + } + Location valueLocation = getValueLocation(keyLocation, name); char[] buffer = new char[StreamUtils.BUFFER_SIZE]; boolean success = false; @@ -210,6 +246,7 @@ public class WineRegistryEditor implements Closeable { } public void removeValue(String key, String name) { + lastParentKeyPosition = 0; Location keyLocation = getKeyLocation(key); if (keyLocation == null) return; @@ -223,6 +260,7 @@ public class WineRegistryEditor implements Closeable { } public boolean removeKey(String key, boolean removeTree) { + lastParentKeyPosition = 0; boolean removed = false; if (removeTree) { Location location; @@ -274,8 +312,12 @@ public class WineRegistryEditor implements Closeable { private Location getKeyLocation(String key, boolean keyAsPrefix) { try (BufferedReader reader = new BufferedReader(new FileReader(cloneFile), StreamUtils.BUFFER_SIZE)) { + int lastIndex = key.lastIndexOf("\\"); + String parentKey = lastParentKeyPosition == 0 && lastIndex != -1 ? "["+escape(key.substring(0, lastIndex)) : null; + + if (lastParentKeyPosition > 0) reader.skip(lastParentKeyPosition); key = "["+escape(key)+(!keyAsPrefix ? "]" : ""); - int totalLength = 0; + int totalLength = lastParentKeyPosition; int start = -1; int end = -1; int emptyLines = 0; @@ -284,7 +326,12 @@ public class WineRegistryEditor implements Closeable { String line; while ((line = reader.readLine()) != null) { if (start == -1) { - if (line.startsWith(key)) { + if (parentKey != null && line.startsWith(parentKey)) { + lastParentKeyPosition = totalLength; + parentKey = null; + } + + if (parentKey == null && line.startsWith(key)) { offset = totalLength - 1; start = totalLength + line.length() + 1; } diff --git a/app/src/main/java/com/winlator/core/WineUtils.java b/app/src/main/java/com/winlator/core/WineUtils.java index e74f39b..4601974 100644 --- a/app/src/main/java/com/winlator/core/WineUtils.java +++ b/app/src/main/java/com/winlator/core/WineUtils.java @@ -89,48 +89,48 @@ public abstract class WineUtils { return; } - File wineBin32 = new File(binDir, "wine"); + File wineBin = new File(binDir, "wine"); File wineBin64 = new File(binDir, "wine64"); - if (!wineBin32.isFile()) { + if (!wineBin.isFile()) { callback.call(null); return; } - final String arch = wineBin64.isFile() ? "x86_64" : "x86"; + final String arch = (wineBin64.isFile() && ElfHelper.is64Bit(wineBin64)) || ElfHelper.is64Bit(wineBin) ? "x86_64" : "x86"; ImageFs imageFs = ImageFs.find(context); - File rootDir = ImageFs.find(context).getRootDir(); - String wineBinAbsPath = arch.equals("x86_64") ? wineBin64.getPath() : wineBin32.getPath(); + File rootDir = imageFs.getRootDir(); + String wineBinAbsPath = wineBin64.isFile() ? wineBin64.getPath() : wineBin.getPath(); String wineBinRelPath = FileUtils.toRelativePath(rootDir.getPath(), wineBinAbsPath); final String winePath = wineDir.getPath(); - try { - final AtomicReference wineInfoRef = new AtomicReference<>(); - ProcessHelper.debugCallback = (line) -> { - Pattern pattern = Pattern.compile("^wine\\-([0-9\\.]+)\\-?([0-9\\.]+)?", Pattern.CASE_INSENSITIVE); - Matcher matcher = pattern.matcher(line); - if (matcher.find()) { - String version = matcher.group(1); - String subversion = matcher.groupCount() >= 2 ? matcher.group(2) : null; - wineInfoRef.set(new WineInfo(version, subversion, arch, winePath)); - } - }; + final AtomicReference wineInfoRef = new AtomicReference<>(); + Callback debugCallback = (line) -> { + Pattern pattern = Pattern.compile("^wine\\-([0-9\\.]+)\\-?([0-9\\.]+)?", Pattern.CASE_INSENSITIVE); + Matcher matcher = pattern.matcher(line); + if (matcher.find()) { + String version = matcher.group(1); + String subversion = matcher.groupCount() >= 2 ? matcher.group(2) : null; + wineInfoRef.set(new WineInfo(version, subversion, arch, winePath)); + } + }; - File linkFile = new File(rootDir, ImageFs.HOME_PATH); - linkFile.delete(); - FileUtils.symlink(wineDir, linkFile); + ProcessHelper.addDebugCallback(debugCallback); - XEnvironment environment = new XEnvironment(context, imageFs); - GuestProgramLauncherComponent guestProgramLauncherComponent = new GuestProgramLauncherComponent(); - guestProgramLauncherComponent.setGuestExecutable(wineBinRelPath+" --version"); - guestProgramLauncherComponent.setTerminationCallback((status) -> callback.call(wineInfoRef.get())); - environment.addComponent(guestProgramLauncherComponent); - environment.startEnvironmentComponents(); - } - finally { - ProcessHelper.debugCallback = null; - } + File linkFile = new File(rootDir, ImageFs.HOME_PATH); + linkFile.delete(); + FileUtils.symlink(wineDir, linkFile); + + XEnvironment environment = new XEnvironment(context, imageFs); + GuestProgramLauncherComponent guestProgramLauncherComponent = new GuestProgramLauncherComponent(); + guestProgramLauncherComponent.setGuestExecutable(wineBinRelPath+" --version"); + guestProgramLauncherComponent.setTerminationCallback((status) -> { + callback.call(wineInfoRef.get()); + ProcessHelper.removeDebugCallback(debugCallback); + }); + environment.addComponent(guestProgramLauncherComponent); + environment.startEnvironmentComponents(); } public static ArrayList getInstalledWineInfos(Context context) { @@ -149,21 +149,26 @@ public abstract class WineUtils { return wineInfos; } - public static void applySystemTweaks(Context context, WineInfo wineInfo, boolean firstTimeBoot) { + private static void setWindowMetrics(WineRegistryEditor registryEditor) { + byte[] fontNormalData = (new MSLogFont()).toByteArray(); + byte[] fontBoldData = (new MSLogFont()).setWeight(700).toByteArray(); + registryEditor.setHexValue("Control Panel\\Desktop\\WindowMetrics", "CaptionFont", fontBoldData); + registryEditor.setHexValue("Control Panel\\Desktop\\WindowMetrics", "IconFont", fontNormalData); + registryEditor.setHexValue("Control Panel\\Desktop\\WindowMetrics", "MenuFont", fontNormalData); + registryEditor.setHexValue("Control Panel\\Desktop\\WindowMetrics", "MessageFont", fontNormalData); + registryEditor.setHexValue("Control Panel\\Desktop\\WindowMetrics", "SmCaptionFont", fontNormalData); + registryEditor.setHexValue("Control Panel\\Desktop\\WindowMetrics", "StatusFont", fontNormalData); + } + + public static void applySystemTweaks(Context context, WineInfo wineInfo) { File rootDir = ImageFs.find(context).getRootDir(); File systemRegFile = new File(rootDir, ImageFs.WINEPREFIX+"/system.reg"); File userRegFile = new File(rootDir, ImageFs.WINEPREFIX+"/user.reg"); try (WineRegistryEditor registryEditor = new WineRegistryEditor(systemRegFile)) { - if (firstTimeBoot) { - registryEditor.setStringValue("Software\\Classes\\.reg", null, "REGfile"); - registryEditor.setStringValue("Software\\Classes\\.reg", "Content Type", "application/reg"); - registryEditor.setStringValue("Software\\Classes\\REGfile\\Shell\\Open\\command", null, "C:\\windows\\regedit.exe /C \"%1\""); - - registryEditor.setDwordValue("System\\CurrentControlSet\\Services\\winebus", "DisableHidraw", 1); - registryEditor.setDwordValue("System\\CurrentControlSet\\Services\\winebus", "DisableInput", 1); - registryEditor.setDwordValue("System\\CurrentControlSet\\Services\\winebus", "Enable SDL", 0); - } + registryEditor.setStringValue("Software\\Classes\\.reg", null, "REGfile"); + registryEditor.setStringValue("Software\\Classes\\.reg", "Content Type", "application/reg"); + registryEditor.setStringValue("Software\\Classes\\REGfile\\Shell\\Open\\command", null, "C:\\windows\\regedit.exe /C \"%1\""); registryEditor.setStringValue("Software\\Classes\\dllfile\\DefaultIcon", null, "shell32.dll,-154"); registryEditor.setStringValue("Software\\Classes\\lnkfile\\DefaultIcon", null, "shell32.dll,-30"); @@ -174,16 +179,18 @@ public abstract class WineUtils { final String[] xinputLibs = {"dinput", "dinput8", "xinput1_1", "xinput1_2", "xinput1_3", "xinput1_4", "xinput9_1_0", "xinputuap"}; final String dllOverridesKey = "Software\\Wine\\DllOverrides"; + boolean isMainWineVersion = WineInfo.isMainWineVersion(wineInfo.identifier()); + try (WineRegistryEditor registryEditor = new WineRegistryEditor(userRegFile)) { for (String name : direct3dLibs) registryEditor.setStringValue(dllOverridesKey, name, "native,builtin"); - - boolean isMainWineVersion = wineInfo.identifier().equals(WineInfo.MAIN_WINE_VERSION.identifier()); for (String name : xinputLibs) registryEditor.setStringValue(dllOverridesKey, name, isMainWineVersion ? "builtin,native" : "native,builtin"); registryEditor.removeKey("Software\\Winlator\\WFM\\ContextMenu\\7-Zip"); registryEditor.setStringValue("Software\\Winlator\\WFM\\ContextMenu\\7-Zip", "Open Archive", "Z:\\opt\\apps\\7-Zip\\7zFM.exe \"%FILE%\""); registryEditor.setStringValue("Software\\Winlator\\WFM\\ContextMenu\\7-Zip", "Extract Here", "Z:\\opt\\apps\\7-Zip\\7zG.exe x \"%FILE%\" -r -o\"%DIR%\" -y"); registryEditor.setStringValue("Software\\Winlator\\WFM\\ContextMenu\\7-Zip", "Extract to Folder", "Z:\\opt\\apps\\7-Zip\\7zG.exe x \"%FILE%\" -r -o\"%DIR%\\%BASENAME%\" -y"); + + setWindowMetrics(registryEditor); } File wineSystem32Dir = new File(rootDir, "/opt/wine/lib/wine/x86_64-windows"); @@ -209,9 +216,10 @@ public abstract class WineUtils { for (String[] wincomponent : new KeyValueSet(wincomponents)) { if (wincomponent[1].equals(oldWinComponentsIter.next()[1])) continue; + String identifier = wincomponent[0]; boolean useNative = wincomponent[1].equals("1"); - JSONArray dlnames = wincomponentsJSONObject.getJSONArray(wincomponent[0]); + JSONArray dlnames = wincomponentsJSONObject.getJSONArray(identifier); for (int i = 0; i < dlnames.length(); i++) { String dlname = dlnames.getString(i); if (useNative) { @@ -223,4 +231,78 @@ public abstract class WineUtils { } catch (JSONException e) {} } + + public static void setWinComponentRegistryKeys(File systemRegFile, String identifier, boolean useNative) { + if (identifier.equals("directsound")) { + try (WineRegistryEditor registryEditor = new WineRegistryEditor(systemRegFile)) { + final String key64 = "Software\\Classes\\CLSID\\{083863F1-70DE-11D0-BD40-00A0C911CE86}\\Instance\\{E30629D1-27E5-11CE-875D-00608CB78066}"; + final String key32 = "Software\\Classes\\Wow6432Node\\CLSID\\{083863F1-70DE-11D0-BD40-00A0C911CE86}\\Instance\\{E30629D1-27E5-11CE-875D-00608CB78066}"; + + if (useNative) { + registryEditor.setStringValue(key32, "CLSID", "{E30629D1-27E5-11CE-875D-00608CB78066}"); + registryEditor.setHexValue(key32, "FilterData", "02000000000080000100000000000000307069330200000000000000010000000000000000000000307479330000000038000000480000006175647300001000800000aa00389b710100000000001000800000aa00389b71"); + registryEditor.setStringValue(key32, "FriendlyName", "Wave Audio Renderer"); + + registryEditor.setStringValue(key64, "CLSID", "{E30629D1-27E5-11CE-875D-00608CB78066}"); + registryEditor.setHexValue(key64, "FilterData", "02000000000080000100000000000000307069330200000000000000010000000000000000000000307479330000000038000000480000006175647300001000800000aa00389b710100000000001000800000aa00389b71"); + registryEditor.setStringValue(key64, "FriendlyName", "Wave Audio Renderer"); + } + else { + registryEditor.removeKey(key32); + registryEditor.removeKey(key64); + } + } + } + else if (identifier.equals("wmdecoder")) { + try (WineRegistryEditor registryEditor = new WineRegistryEditor(systemRegFile)) { + if (useNative) { + registryEditor.setStringValue("Software\\Classes\\Wow6432Node\\CLSID\\{2EEB4ADF-4578-4D10-BCA7-BB955F56320A}\\InprocServer32", null, "C:\\windows\\system32\\wmadmod.dll"); + registryEditor.setStringValue("Software\\Classes\\Wow6432Node\\CLSID\\{82D353DF-90BD-4382-8BC2-3F6192B76E34}\\InprocServer32", null, "C:\\windows\\system32\\wmvdecod.dll"); + } + else { + registryEditor.setStringValue("Software\\Classes\\Wow6432Node\\CLSID\\{2EEB4ADF-4578-4D10-BCA7-BB955F56320A}\\InprocServer32", null, "C:\\windows\\system32\\winegstreamer.dll"); + registryEditor.setStringValue("Software\\Classes\\Wow6432Node\\CLSID\\{82D353DF-90BD-4382-8BC2-3F6192B76E34}\\InprocServer32", null, "C:\\windows\\system32\\winegstreamer.dll"); + } + } + } + } + + public static void updateWineprefix(Context context, final Callback terminationCallback) { + ImageFs imageFs = ImageFs.find(context); + final File rootDir = imageFs.getRootDir(); + File tmpDir = imageFs.getTmpDir(); + if (!tmpDir.isDirectory()) tmpDir.mkdir(); + + FileUtils.writeString(new File(rootDir, ImageFs.WINEPREFIX+"/.update-timestamp"), "0\n"); + + EnvVars envVars = new EnvVars(); + envVars.put("WINEPREFIX", ImageFs.WINEPREFIX); + envVars.put("WINEDLLOVERRIDES", "mscoree,mshtml=d"); + + XEnvironment environment = new XEnvironment(context, imageFs); + GuestProgramLauncherComponent guestProgramLauncherComponent = new GuestProgramLauncherComponent(); + guestProgramLauncherComponent.setEnvVars(envVars); + guestProgramLauncherComponent.setGuestExecutable(WineInfo.MAIN_WINE_VERSION.getExecutable(context, true)+" wineboot -u"); + guestProgramLauncherComponent.setTerminationCallback((status) -> { + FileUtils.writeString(new File(rootDir, ImageFs.WINEPREFIX+"/.update-timestamp"), "disable\n"); + if (terminationCallback != null) terminationCallback.call(status); + }); + environment.addComponent(guestProgramLauncherComponent); + environment.startEnvironmentComponents(); + } + + public static void changeServicesStatus(Container container, boolean onlyEssential) { + final String[] services = {"BITS:3", "Eventlog:2", "HTTP:3", "LanmanServer:3", "NDIS:2", "PlugPlay:2", "RpcSs:3", "scardsvr:3", "Schedule:3", "Spooler:3", "StiSvc:3", "TermService:3", "winebus:3", "winehid:3", "Winmgmt:3", "wuauserv:3"}; + File systemRegFile = new File(container.getRootDir(), ".wine/system.reg"); + + try (WineRegistryEditor registryEditor = new WineRegistryEditor(systemRegFile)) { + registryEditor.setCreateKeyIfNotExist(false); + + for (String service : services) { + String name = service.substring(0, service.indexOf(":")); + int value = onlyEssential ? 4 : Character.getNumericValue(service.charAt(service.length()-1)); + registryEditor.setDwordValue("System\\CurrentControlSet\\Services\\"+name, "Start", value); + } + } + } } diff --git a/app/src/main/java/com/winlator/core/Workarounds.java b/app/src/main/java/com/winlator/core/Workarounds.java deleted file mode 100644 index 41813ba..0000000 --- a/app/src/main/java/com/winlator/core/Workarounds.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.winlator.core; - -import com.winlator.winhandler.WinHandler; -import com.winlator.xserver.Window; - -import java.util.Timer; -import java.util.TimerTask; - -public abstract class Workarounds { - // Workaround for applications that don't work mouse/keyboard - public static void onMapWindow(final WinHandler winHandler, Window window) { - final String className = window.getClassName(); - if (className.equals("twfc.exe") || - className.equals("daggerfallunity.exe")) { - final boolean reverse = className.equals("twfc.exe"); - (new Timer()).schedule(new TimerTask() { - @Override - public void run() { - winHandler.bringToFront(className, reverse); - } - }, 500); - } - } -} diff --git a/app/src/main/java/com/winlator/inputcontrols/ControlElement.java b/app/src/main/java/com/winlator/inputcontrols/ControlElement.java index f3fd387..ffacbd3 100644 --- a/app/src/main/java/com/winlator/inputcontrols/ControlElement.java +++ b/app/src/main/java/com/winlator/inputcontrols/ControlElement.java @@ -6,14 +6,13 @@ import android.graphics.Paint; import android.graphics.Path; import android.graphics.PointF; import android.graphics.Rect; -import android.graphics.RectF; -import android.os.CountDownTimer; -import android.util.Log; import androidx.core.graphics.ColorUtils; +import com.winlator.core.CubicBezierInterpolator; import com.winlator.math.Mathf; import com.winlator.widget.InputControlsView; +import com.winlator.widget.TouchpadView; import org.json.JSONArray; import org.json.JSONException; @@ -25,8 +24,12 @@ public class ControlElement { public static final float STICK_DEAD_ZONE = 0.15f; public static final float DPAD_DEAD_ZONE = 0.3f; public static final float STICK_SENSITIVITY = 3.0f; + public static final float TRACKPAD_MIN_SPEED = 0.8f; + public static final float TRACKPAD_MAX_SPEED = 20.0f; + public static final byte TRACKPAD_ACCELERATION_THRESHOLD = 4; + public static final short BUTTON_MIN_TIME_TO_KEEP_PRESSED = 300; public enum Type { - BUTTON, D_PAD, RANGE_BUTTON, STICK; + BUTTON, D_PAD, RANGE_BUTTON, STICK, TRACKPAD; public static String[] names() { Type[] types = values(); @@ -77,101 +80,34 @@ public class ControlElement { private byte iconId; private Range range; private byte orientation; - private PointF thumbstickPosition; - //range button. handler for scrolling or key pressing - private class RangeDelayTimer extends CountDownTimer{ - private static final String TAG = "RangeDelayTimer"; - static final int DELAY_TIME=250, NO_SCROLL_THRESHOLD = 18; - long downTime = System.currentTimeMillis(); - PointF downPos = new PointF(); //finger down position when scroll not started, last finger position when scrolling. - PointF scrOff = new PointF(); //current scroll offset. range in [-totalWidth, 0] - Binding binding = Binding.NONE; //the key when finger down. not stored in ControlElement. - boolean isScrollStarted = false;//true means that finger is scrolling and should press key. - - public RangeDelayTimer() {super(DELAY_TIME, DELAY_TIME*10);} - - @Override - public void onTick(long millisUntilFinished) {} - - @Override - public void onFinish() { - if(isScrollStarted) return; - inputControlsView.post(()-> inputControlsView.handleInputEvent(binding, true)); - } - - /** handleFingerDown. init and start timer */ - public void start(float x, float y) { - Range range = getRange(); - //calculate index by scroll offset - Rect box = getBoundingBox(); - float elementSize = (float) Math.max(box.width(), box.height()) / bindings.length; - float offset = orientation == 0 ? x - box.left - this.scrOff.x : y - box.top - this.scrOff.y; - int index = Mathf.clamp((int) Math.floor(offset/elementSize), 0, getRange().max-1); - this.binding = switch (range) { - case FROM_A_TO_Z -> Binding.valueOf("KEY_" + ((char) (65 + index))); - case FROM_0_TO_9 -> Binding.valueOf("KEY_" + ((index + 1) % 10)); - case FROM_F1_TO_F12 -> Binding.valueOf("KEY_F" + (index + 1)); - case FROM_NP0_TO_NP9 -> Binding.valueOf("KEY_KP_" + ((index + 1) % 10)); - default -> Binding.NONE; - }; - Arrays.fill(bindings, Binding.NONE); - this.downTime = System.currentTimeMillis(); - this.downPos.set(x, y); - this.isScrollStarted = false; - this.start(); - } - - public void handleTouchMove(float x, float y) { - //for some reason it receives move event without down event first. So check here to make sure it goes through down event first. - if(downPos.x == -1) { - start(x, y); - return; - } - - boolean isTimeOut = System.currentTimeMillis()- this.downTime > RangeDelayTimer.DELAY_TIME; - if(isTimeOut && !this.isScrollStarted) return; - if(!isTimeOut && !this.isScrollStarted && Mathf.lengthSq(x- downPos.x, y- downPos.y) > NO_SCROLL_THRESHOLD * NO_SCROLL_THRESHOLD) { - this.isScrollStarted = true; //In a short time, and moving far away, considered as scrolling and no key event. - this.cancel(); - } - - if(this.isScrollStarted) { - int elementSize = Math.max(boundingBox.width(), boundingBox.height()) / bindings.length; - float limit = - ((getRange().max - bindings.length) * elementSize); - float offX = orientation != 0 ? 0 : Mathf.clamp(scrOff.x + x-downPos.x, limit, 0); - float offY = orientation != 1 ? 0 : Mathf.clamp(scrOff.y + y-downPos.y, limit, 0); - scrOff.set(offX, offY); - downPos.set(x, y); - inputControlsView.invalidate(); - } - } - - /** key press(maybe) and release */ - public void handleTouchUp() { - if(System.currentTimeMillis() - downTime < DELAY_TIME && !isScrollStarted) { - this.cancel(); - inputControlsView.handleInputEvent(binding, true); - try {Thread.sleep(30);} catch (InterruptedException ignored) {} - } - inputControlsView.handleInputEvent(binding, false); - downPos.set(-1,-1); //for some reason it receives move events without down event, so clear downPos here. - } - } - private final RangeDelayTimer rTimer = new RangeDelayTimer(); - + private PointF currentPosition; + private RangeScroller scroller; + private CubicBezierInterpolator interpolator; + private Object touchTime; public ControlElement(InputControlsView inputControlsView) { this.inputControlsView = inputControlsView; } private void reset() { - Arrays.fill(bindings, Binding.NONE); + setBinding(Binding.NONE); + scroller = null; + if (type == Type.D_PAD || type == Type.STICK) { bindings[0] = Binding.KEY_W; bindings[1] = Binding.KEY_D; bindings[2] = Binding.KEY_S; bindings[3] = Binding.KEY_A; } + else if (type == Type.TRACKPAD) { + bindings[0] = Binding.MOUSE_MOVE_UP; + bindings[1] = Binding.MOUSE_MOVE_RIGHT; + bindings[2] = Binding.MOUSE_MOVE_DOWN; + bindings[3] = Binding.MOUSE_MOVE_LEFT; + } + else if (type == Type.RANGE_BUTTON) { + scroller = new RangeScroller(inputControlsView, this); + } text = ""; iconId = 0; @@ -194,7 +130,7 @@ public class ControlElement { public void setBindingCount(int bindingCount) { bindings = new Binding[bindingCount]; - Arrays.fill(bindings, Binding.NONE); + setBinding(Binding.NONE); states = new boolean[bindingCount]; boundingBoxNeedsUpdate = true; } @@ -248,6 +184,10 @@ public class ControlElement { bindings[index] = binding; } + public void setBinding(Binding binding) { + Arrays.fill(bindings, binding); + } + public float getScale() { return scale; } @@ -332,13 +272,14 @@ public class ControlElement { halfHeight = snappingSize * 7; break; } + case TRACKPAD: case STICK: { halfWidth = snappingSize * 6; halfHeight = snappingSize * 6; break; } case RANGE_BUTTON: { - halfWidth = snappingSize * ((bindings.length * 4/* + 8*/) / 2); + halfWidth = snappingSize * ((bindings.length * 4) / 2); halfHeight = snappingSize * 2; if (orientation == 1) { @@ -490,32 +431,34 @@ public class ControlElement { case RANGE_BUTTON: { Range range = getRange(); int oldColor = paint.getColor(); - float radius = snappingSize * 0.75f * scale;//change to normal round rect - float elementSize = (float)Math.max(boundingBox.width(), boundingBox.height()) / (bindings.length/* + 2*/); //不包含左右按钮 + float radius = snappingSize * 0.75f * scale; + float elementSize = scroller.getElementSize(); float minTextSize = snappingSize * 2 * scale; + float scrollOffset = scroller.getScrollOffset(); + byte[] rangeIndex = scroller.getRangeIndex(); + Path path = inputControlsView.getPath(); + path.reset(); if (orientation == 0) { float lineTop = boundingBox.top + strokeWidth * 0.5f; float lineBottom = boundingBox.bottom - strokeWidth * 0.5f; - float startX = boundingBox.left; canvas.drawRoundRect(startX, boundingBox.top, boundingBox.right, boundingBox.bottom, radius, radius, paint); - //1. don't draw page button. 2. clip round rect and apply scroll offset. - canvas.save(); - inputControlsView.getPath().reset(); - inputControlsView.getPath().addRoundRect(startX, boundingBox.top, boundingBox.right, boundingBox.bottom, radius, radius, Path.Direction.CW); - canvas.clipPath(inputControlsView.getPath()); - startX += rTimer.scrOff.x; - for (byte i = 0; i < getRange().max; i++) { //loop all buttons + canvas.save(); + path.addRoundRect(startX, boundingBox.top, boundingBox.right, boundingBox.bottom, radius, radius, Path.Direction.CW); + canvas.clipPath(path); + startX -= scrollOffset % elementSize; + + for (byte i = rangeIndex[0]; i < rangeIndex[1]; i++) { + int index = i % range.max; paint.setStyle(Paint.Style.STROKE); paint.setColor(oldColor); - if(startX > boundingBox.left && startX < boundingBox.right) - canvas.drawLine(startX, lineTop, startX, lineBottom, paint); - String text = getRangeTextForIndex(range, i); + if (startX > boundingBox.left && startX < boundingBox.right) canvas.drawLine(startX, lineTop, startX, lineBottom, paint); + String text = getRangeTextForIndex(range, index); - if(startX < boundingBox.right && startX + elementSize > boundingBox.left) { + if (startX < boundingBox.right && startX + elementSize > boundingBox.left) { paint.setStyle(Paint.Style.FILL); paint.setColor(primaryColor); paint.setTextSize(Math.min(getTextSizeForWidth(paint, text, elementSize - strokeWidth * 2), minTextSize)); @@ -527,29 +470,27 @@ public class ControlElement { paint.setStyle(Paint.Style.STROKE); paint.setColor(oldColor); - //don't draw the page button. restore canvas transform. canvas.restore(); } else { float lineLeft = boundingBox.left + strokeWidth * 0.5f; float lineRight = boundingBox.right - strokeWidth * 0.5f; - float startY = boundingBox.top; canvas.drawRoundRect(boundingBox.left, startY, boundingBox.right, boundingBox.bottom, radius, radius, paint); - canvas.save(); - inputControlsView.getPath().reset(); - inputControlsView.getPath().addRoundRect(boundingBox.left, startY, boundingBox.right, boundingBox.bottom, radius, radius, Path.Direction.CW); - canvas.clipPath(inputControlsView.getPath()); - startY += rTimer.scrOff.y; - for (byte i = 0; i < getRange().max; i++) { + canvas.save(); + path.addRoundRect(boundingBox.left, startY, boundingBox.right, boundingBox.bottom, radius, radius, Path.Direction.CW); + canvas.clipPath(inputControlsView.getPath()); + startY -= scrollOffset % elementSize; + + for (byte i = rangeIndex[0]; i < rangeIndex[1]; i++) { paint.setStyle(Paint.Style.STROKE); paint.setColor(oldColor); - if(startY > boundingBox.top && startY < boundingBox.bottom) - canvas.drawLine(lineLeft, startY, lineRight, startY, paint); + + if (startY > boundingBox.top && startY < boundingBox.bottom) canvas.drawLine(lineLeft, startY, lineRight, startY, paint); String text = getRangeTextForIndex(range, i); - if(startY < boundingBox.bottom && startY + elementSize > boundingBox.top) { + if (startY < boundingBox.bottom && startY + elementSize > boundingBox.top) { paint.setStyle(Paint.Style.FILL); paint.setColor(primaryColor); paint.setTextSize(Math.min(getTextSizeForWidth(paint, text, boundingBox.width() - strokeWidth * 2), minTextSize)); @@ -565,16 +506,16 @@ public class ControlElement { } break; } - case STICK: + case STICK: { int cx = boundingBox.centerX(); int cy = boundingBox.centerY(); int oldColor = paint.getColor(); canvas.drawCircle(cx, cy, boundingBox.height() * 0.5f, paint); - float thumbstickX = thumbstickPosition != null ? thumbstickPosition.x : cx; - float thumbstickY = thumbstickPosition != null ? thumbstickPosition.y : cy; + float thumbstickX = currentPosition != null ? currentPosition.x : cx; + float thumbstickY = currentPosition != null ? currentPosition.y : cy; - short thumbRadius = (short)(snappingSize * 3.5f * scale); + short thumbRadius = (short) (snappingSize * 3.5f * scale); paint.setStyle(Paint.Style.FILL); paint.setColor(ColorUtils.setAlphaComponent(primaryColor, 50)); canvas.drawCircle(thumbstickX, thumbstickY, thumbRadius, paint); @@ -583,6 +524,18 @@ public class ControlElement { paint.setColor(oldColor); canvas.drawCircle(thumbstickX, thumbstickY, thumbRadius + strokeWidth * 0.5f, paint); break; + } + case TRACKPAD: { + float radius = boundingBox.height() * 0.15f; + canvas.drawRoundRect(boundingBox.left, boundingBox.top, boundingBox.right, boundingBox.bottom, radius, radius, paint); + float offset = strokeWidth * 2.5f; + float innerStrokeWidth = strokeWidth * 2; + float innerHeight = boundingBox.height() - offset * 2; + radius = (innerHeight / boundingBox.height()) * radius - (innerStrokeWidth * 0.5f + strokeWidth * 0.5f); + paint.setStrokeWidth(innerStrokeWidth); + canvas.drawRoundRect(boundingBox.left + offset, boundingBox.top + offset, boundingBox.right - offset, boundingBox.bottom - offset, radius, radius, paint); + break; + } } } @@ -631,53 +584,76 @@ public class ControlElement { return getBoundingBox().contains((int)(x + 0.5f), (int)(y + 0.5f)); } + private boolean isKeepButtonPressedAfterMinTime() { + Binding binding = getBindingAt(0); + return !toggleSwitch && (binding == Binding.GAMEPAD_BUTTON_L3 || binding == Binding.GAMEPAD_BUTTON_R3); + } + public boolean handleTouchDown(int pointerId, float x, float y) { if (currentPointerId == -1 && containsPoint(x, y)) { currentPointerId = pointerId; - if (type == ControlElement.Type.BUTTON) { + if (type == Type.BUTTON) { + if (isKeepButtonPressedAfterMinTime()) touchTime = System.currentTimeMillis(); if (!toggleSwitch || !selected) inputControlsView.handleInputEvent(getBindingAt(0), true); return true; } else if (type == Type.RANGE_BUTTON) { - //delay the key press. if in a short time finger moved then it should scroll instead of press key. - rTimer.start(x, y); + scroller.handleTouchDown(x, y); return true; } - else return handleTouchMove(pointerId, x, y); + else { + if (type == Type.TRACKPAD) { + if (currentPosition == null) currentPosition = new PointF(); + currentPosition.set(x, y); + } + return handleTouchMove(pointerId, x, y); + } } else return false; } public boolean handleTouchMove(int pointerId, float x, float y) { - if (pointerId == currentPointerId && (type == ControlElement.Type.D_PAD || type == Type.STICK)) { + if (pointerId == currentPointerId && (type == Type.D_PAD || type == Type.STICK || type == Type.TRACKPAD)) { + float deltaX, deltaY; Rect boundingBox = getBoundingBox(); float radius = boundingBox.width() * 0.5f; - float localX = x - boundingBox.left; - float localY = y - boundingBox.top; - float offsetX = localX - radius; - float offsetY = localY - radius; + TouchpadView touchpadView = inputControlsView.getTouchpadView(); - float distance = Mathf.lengthSq(radius - localX, radius - localY); - if (distance > radius * radius) { - float angle = (float)Math.atan2(offsetY, offsetX); - offsetX = (float)(Math.cos(angle) * radius); - offsetY = (float)(Math.sin(angle) * radius); + if (type == Type.TRACKPAD) { + if (currentPosition == null) currentPosition = new PointF(); + float[] deltaPoint = touchpadView.computeDeltaPoint(currentPosition.x, currentPosition.y, x, y); + deltaX = deltaPoint[0]; + deltaY = deltaPoint[1]; + currentPosition.set(x, y); + } + else { + float localX = x - boundingBox.left; + float localY = y - boundingBox.top; + float offsetX = localX - radius; + float offsetY = localY - radius; + + float distance = Mathf.lengthSq(radius - localX, radius - localY); + if (distance > radius * radius) { + float angle = (float)Math.atan2(offsetY, offsetX); + offsetX = (float)(Math.cos(angle) * radius); + offsetY = (float)(Math.sin(angle) * radius); + } + + deltaX = Mathf.clamp(offsetX / radius, -1, 1); + deltaY = Mathf.clamp(offsetY / radius, -1, 1); } - float deltaX = Mathf.clamp(offsetX / radius, -1, 1); - float deltaY = Mathf.clamp(offsetY / radius, -1, 1); - if (type == Type.STICK) { - if (thumbstickPosition == null) thumbstickPosition = new PointF(); - thumbstickPosition.x = boundingBox.left + deltaX * radius + radius; - thumbstickPosition.y = boundingBox.top + deltaY * radius + radius; + if (currentPosition == null) currentPosition = new PointF(); + currentPosition.x = boundingBox.left + deltaX * radius + radius; + currentPosition.y = boundingBox.top + deltaY * radius + radius; final boolean[] states = {deltaY <= -STICK_DEAD_ZONE, deltaX >= STICK_DEAD_ZONE, deltaY >= STICK_DEAD_ZONE, deltaX <= -STICK_DEAD_ZONE}; for (byte i = 0; i < 4; i++) { float value = i == 1 || i == 3 ? deltaX : deltaY; Binding binding = getBindingAt(i); if (binding.isGamepad()) { - value = Mathf.clamp(Math.max(0, Math.abs(value) - STICK_DEAD_ZONE) * Mathf.sign(value) * STICK_SENSITIVITY, -1, 1); + value = Mathf.clamp(Math.max(0, Math.abs(value) - 0.01f) * Mathf.sign(value) * STICK_SENSITIVITY, -1, 1); inputControlsView.handleInputEvent(binding, true, value); this.states[i] = true; } @@ -690,6 +666,39 @@ public class ControlElement { inputControlsView.invalidate(); } + else if (type == Type.TRACKPAD) { + final boolean[] states = {deltaY <= -TRACKPAD_MIN_SPEED, deltaX >= TRACKPAD_MIN_SPEED, deltaY >= TRACKPAD_MIN_SPEED, deltaX <= -TRACKPAD_MIN_SPEED}; + int cursorDx = 0; + int cursorDy = 0; + + for (byte i = 0; i < 4; i++) { + float value = (i == 1 || i == 3 ? deltaX : deltaY); + Binding binding = getBindingAt(i); + if (binding.isGamepad()) { + if (interpolator == null) interpolator = new CubicBezierInterpolator(); + if (Math.abs(value) > TRACKPAD_ACCELERATION_THRESHOLD) value *= STICK_SENSITIVITY; + interpolator.set(0.075f, 0.95f, 0.45f, 0.95f); + float interpolatedValue = interpolator.getInterpolation(Math.min(1.0f, Math.abs(value / TRACKPAD_MAX_SPEED))); + inputControlsView.handleInputEvent(binding, true, Mathf.clamp(interpolatedValue * Mathf.sign(value), -1, 1)); + this.states[i] = true; + } + else { + if (Math.abs(value) > TouchpadView.CURSOR_ACCELERATION_THRESHOLD) value *= TouchpadView.CURSOR_ACCELERATION; + if (binding == Binding.MOUSE_MOVE_LEFT || binding == Binding.MOUSE_MOVE_RIGHT) { + cursorDx = Mathf.roundPoint(value); + } + else if (binding == Binding.MOUSE_MOVE_UP || binding == Binding.MOUSE_MOVE_DOWN) { + cursorDy = Mathf.roundPoint(value); + } + else { + inputControlsView.handleInputEvent(binding, states[i], value); + this.states[i] = states[i]; + } + } + } + + if (cursorDx != 0 || cursorDy != 0) inputControlsView.getXServer().injectPointerMoveDelta(cursorDx, cursorDy); + } else { final boolean[] states = {deltaY <= -DPAD_DEAD_ZONE, deltaX >= DPAD_DEAD_ZONE, deltaY >= DPAD_DEAD_ZONE, deltaX <= -DPAD_DEAD_ZONE}; @@ -704,9 +713,8 @@ public class ControlElement { return true; } - else if(pointerId == currentPointerId && type == Type.RANGE_BUTTON) { - //right after press, check if should start scrolling. after that update the scroll offset. - rTimer.handleTouchMove(x, y); + else if (pointerId == currentPointerId && type == Type.RANGE_BUTTON) { + scroller.handleTouchMove(x, y); return true; } else return false; @@ -715,26 +723,34 @@ public class ControlElement { public boolean handleTouchUp(int pointerId) { if (pointerId == currentPointerId) { if (type == Type.BUTTON) { - if (!toggleSwitch || selected) inputControlsView.handleInputEvent(getBindingAt(0), false); + Binding binding = getBindingAt(0); + if (isKeepButtonPressedAfterMinTime() && touchTime != null) { + selected = (System.currentTimeMillis() - (long)touchTime) > BUTTON_MIN_TIME_TO_KEEP_PRESSED; + if (!selected) inputControlsView.handleInputEvent(binding, false); + touchTime = null; + inputControlsView.invalidate(); + } + else if (!toggleSwitch || selected) inputControlsView.handleInputEvent(binding, false); + if (toggleSwitch) { selected = !selected; inputControlsView.invalidate(); } } - else if (type == Type.RANGE_BUTTON || type == Type.D_PAD || type == Type.STICK) { + else if (type == Type.RANGE_BUTTON || type == Type.D_PAD || type == Type.STICK || type == Type.TRACKPAD) { for (byte i = 0; i < states.length; i++) { if (states[i]) inputControlsView.handleInputEvent(getBindingAt(i), false); states[i] = false; } if (type == Type.RANGE_BUTTON) { - //handle key release. if not scrolled and not pressed, press first. - rTimer.handleTouchUp(); + scroller.handleTouchUp(); } else if (type == Type.STICK) { - if (thumbstickPosition != null) thumbstickPosition = null; inputControlsView.invalidate(); } + + if (currentPosition != null) currentPosition = null; } currentPointerId = -1; return true; diff --git a/app/src/main/java/com/winlator/inputcontrols/ExternalController.java b/app/src/main/java/com/winlator/inputcontrols/ExternalController.java index e776cee..2e37a72 100644 --- a/app/src/main/java/com/winlator/inputcontrols/ExternalController.java +++ b/app/src/main/java/com/winlator/inputcontrols/ExternalController.java @@ -178,9 +178,10 @@ public class ExternalController { } public static ArrayList getControllers() { + int[] deviceIds = InputDevice.getDeviceIds(); ArrayList controllers = new ArrayList<>(); - for (int deviceId : InputDevice.getDeviceIds()) { - InputDevice device = InputDevice.getDevice(deviceId); + for (int i = deviceIds.length-1; i >= 0; i--) { + InputDevice device = InputDevice.getDevice(deviceIds[i]); if (isGameController(device)) { ExternalController controller = new ExternalController(); controller.setId(device.getDescriptor()); @@ -197,14 +198,15 @@ public class ExternalController { } public static ExternalController getController(int deviceId) { - for (int deviceId2 : InputDevice.getDeviceIds()) { - if (deviceId2 == deviceId || deviceId == 0) { - InputDevice device = InputDevice.getDevice(deviceId2); + int[] deviceIds = InputDevice.getDeviceIds(); + for (int i = deviceIds.length-1; i >= 0; i--) { + if (deviceIds[i] == deviceId || deviceId == 0) { + InputDevice device = InputDevice.getDevice(deviceIds[i]); if (isGameController(device)) { ExternalController controller = new ExternalController(); controller.setId(device.getDescriptor()); controller.setName(device.getName()); - controller.deviceId = deviceId2; + controller.deviceId = deviceIds[i]; return controller; } } diff --git a/app/src/main/java/com/winlator/inputcontrols/GamepadState.java b/app/src/main/java/com/winlator/inputcontrols/GamepadState.java index 121d13f..cdc7d26 100644 --- a/app/src/main/java/com/winlator/inputcontrols/GamepadState.java +++ b/app/src/main/java/com/winlator/inputcontrols/GamepadState.java @@ -34,12 +34,6 @@ public class GamepadState { buffer.putShort((short)(thumbRY * Short.MAX_VALUE)); } - public byte[] toByteArray() { - ByteBuffer buffer = ByteBuffer.allocate(11).order(ByteOrder.LITTLE_ENDIAN); - writeTo(buffer); - return buffer.array(); - } - public void setPressed(int buttonIdx, boolean pressed) { int flag = 1< getProfiles(boolean ignoreTemplates) { - if (!profilesLoaded) loadProfiles(); + if (!profilesLoaded) loadProfiles(ignoreTemplates); return profiles; } - public void loadProfiles() { + private void copyAssetProfilesIfNeeded() { File profilesDir = InputControlsManager.getProfilesDir(context); - if (FileUtils.isEmpty(profilesDir)) FileUtils.copy(context, "inputcontrols/profiles", profilesDir); + if (FileUtils.isEmpty(profilesDir)) { + FileUtils.copy(context, "inputcontrols/profiles", profilesDir); + return; + } + + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); + + int newVersion = AppUtils.getVersionCode(context); + int oldVersion = preferences.getInt("inputcontrols_app_version", 0); + if (oldVersion == newVersion) return; + preferences.edit().putInt("inputcontrols_app_version", newVersion).apply(); + + File[] files = profilesDir.listFiles(); + if (files == null) return; + + try { + AssetManager assetManager = context.getAssets(); + String[] assetFiles = assetManager.list("inputcontrols/profiles"); + for (String assetFile : assetFiles) { + String assetPath = "inputcontrols/profiles/"+assetFile; + ControlsProfile originProfile = loadProfile(context, assetManager.open(assetPath)); + + File targetFile = null; + for (File file : files) { + ControlsProfile targetProfile = loadProfile(context, file); + if (originProfile.id == targetProfile.id && originProfile.getName().equals(targetProfile.getName())) { + targetFile = file; + break; + } + } + + if (targetFile != null) { + FileUtils.copy(context, assetPath, targetFile); + } + } + } + catch (IOException e) {} + } + + public void loadProfiles(boolean ignoreTemplates) { + File profilesDir = InputControlsManager.getProfilesDir(context); + copyAssetProfilesIfNeeded(); ArrayList profiles = new ArrayList<>(); File[] files = profilesDir.listFiles(); if (files != null) { - boolean ignoreTemplates = context instanceof XServerDisplayActivity; for (File file : files) { ControlsProfile profile = loadProfile(context, file); if (!(ignoreTemplates && profile.isTemplate())) profiles.add(profile); @@ -146,11 +192,16 @@ public class InputControlsManager { } public static ControlsProfile loadProfile(Context context, File file) { - JsonReader reader = null; try { - FileInputStream fis = new FileInputStream(file); - reader = new JsonReader(new InputStreamReader(fis, StandardCharsets.UTF_8)); + return loadProfile(context, new FileInputStream(file)); + } + catch (FileNotFoundException e) { + return null; + } + } + public static ControlsProfile loadProfile(Context context, InputStream inStream) { + try (JsonReader reader = new JsonReader(new InputStreamReader(inStream, StandardCharsets.UTF_8))) { int profileId = 0; String profileName = null; float cursorSpeed = Float.NaN; @@ -169,7 +220,7 @@ public class InputControlsManager { fieldsRead++; } else if (name.equals("cursorSpeed")) { - cursorSpeed = (float)reader.nextDouble(); + cursorSpeed = (float) reader.nextDouble(); fieldsRead++; } else { @@ -186,12 +237,6 @@ public class InputControlsManager { catch (IOException e) { return null; } - finally { - try { - if (reader != null) reader.close(); - } - catch (IOException e) {} - } } public ControlsProfile getProfile(int id) { diff --git a/app/src/main/java/com/winlator/inputcontrols/RangeScroller.java b/app/src/main/java/com/winlator/inputcontrols/RangeScroller.java new file mode 100644 index 0000000..081bf72 --- /dev/null +++ b/app/src/main/java/com/winlator/inputcontrols/RangeScroller.java @@ -0,0 +1,135 @@ +package com.winlator.inputcontrols; + +import android.graphics.Rect; + +import com.winlator.widget.InputControlsView; +import com.winlator.widget.TouchpadView; + +import java.util.Timer; +import java.util.TimerTask; + +public class RangeScroller { + private final InputControlsView inputControlsView; + private final ControlElement element; + private float scrollOffset; + private float currentOffset; + private float lastPosition; + private long touchTime; + private Binding binding = Binding.NONE; + private boolean isActionDown = false; + private boolean scrolling = false; + private Timer timer; + + public RangeScroller(InputControlsView inputControlsView, ControlElement element) { + this.inputControlsView = inputControlsView; + this.element = element; + } + + public float getElementSize() { + Rect boundingBox = element.getBoundingBox(); + return (float)Math.max(boundingBox.width(), boundingBox.height()) / element.getBindingCount(); + } + + public float getScrollSize() { + return getElementSize() * element.getRange().max; + } + + public float getScrollOffset() { + return scrollOffset; + } + + public byte[] getRangeIndex() { + ControlElement.Range range = element.getRange(); + byte from = (byte)Math.floor((scrollOffset / getElementSize()) % range.max); + if (from < 0) from = (byte)(range.max + from); + byte to = (byte)(from + element.getBindingCount() + 1); + return new byte[]{from, to}; + } + + private Binding getBindingByPosition(float x, float y) { + Rect boundingBox = element.getBoundingBox(); + ControlElement.Range range = element.getRange(); + float offset = element.getOrientation() == 0 ? x - boundingBox.left - currentOffset : y - boundingBox.top - currentOffset; + int index = (int)Math.floor((offset / getElementSize()) % range.max); + if (index < 0) index = range.max + index; + + switch (range) { + case FROM_A_TO_Z: + return Binding.valueOf("KEY_"+((char)(65 + index))); + case FROM_0_TO_9: + return Binding.valueOf("KEY_"+((index + 1) % 10)); + case FROM_F1_TO_F12: + return Binding.valueOf("KEY_F"+(index + 1)); + case FROM_NP0_TO_NP9: + return Binding.valueOf("KEY_KP_"+((index + 1) % 10)); + default: + return Binding.NONE; + } + } + + private boolean isTap() { + return (System.currentTimeMillis() - touchTime) < TouchpadView.MAX_TAP_MILLISECONDS; + } + + private void destroyTimer() { + if (timer != null) { + timer.cancel(); + timer = null; + } + } + + public void handleTouchDown(float x, float y) { + destroyTimer(); + + scrolling = false; + isActionDown = true; + binding = getBindingByPosition(x, y); + touchTime = System.currentTimeMillis(); + lastPosition = element.getOrientation() == 0 ? x : y; + element.setBinding(Binding.NONE); + + timer = new Timer(true); + timer.schedule(new TimerTask() { + @Override + public void run() { + if (!scrolling) inputControlsView.post(() -> inputControlsView.handleInputEvent(binding, true)); + } + }, TouchpadView.MAX_TAP_MILLISECONDS); + } + + public void handleTouchMove(float x, float y) { + if (isActionDown) { + float position = element.getOrientation() == 0 ? x : y; + float deltaPosition = position - lastPosition; + + if (Math.abs(deltaPosition) >= TouchpadView.MAX_TAP_TRAVEL_DISTANCE) { + scrolling = true; + destroyTimer(); + } + + if (scrolling) { + currentOffset += deltaPosition; + + float scrollSize = getScrollSize(); + scrollOffset = -currentOffset % scrollSize; + if (scrollOffset < 0) scrollOffset = scrollSize + scrollOffset; + + lastPosition = position; + inputControlsView.invalidate(); + } + } + } + + public void handleTouchUp() { + if (isActionDown) { + destroyTimer(); + if (isTap() && !scrolling) { + inputControlsView.handleInputEvent(binding, true); + final Binding finalBinding = binding; + inputControlsView.postDelayed(() -> inputControlsView.handleInputEvent(finalBinding, false), 30); + } + else inputControlsView.handleInputEvent(binding, false); + } + isActionDown = false; + } +} diff --git a/app/src/main/java/com/winlator/math/Mathf.java b/app/src/main/java/com/winlator/math/Mathf.java index 9668f94..48b0844 100644 --- a/app/src/main/java/com/winlator/math/Mathf.java +++ b/app/src/main/java/com/winlator/math/Mathf.java @@ -13,6 +13,10 @@ public abstract class Mathf { return (float)(Math.floor(x / step) * step); } + public static int roundPoint(float x) { + return (int)(x <= 0 ? Math.floor(x) : Math.ceil(x)); + } + public static byte sign(float x) { return (byte)(x < 0 ? -1 : (x > 0 ? 1 : 0)); } diff --git a/app/src/main/java/com/winlator/renderer/GLRenderer.java b/app/src/main/java/com/winlator/renderer/GLRenderer.java index 03213ec..7cff202 100644 --- a/app/src/main/java/com/winlator/renderer/GLRenderer.java +++ b/app/src/main/java/com/winlator/renderer/GLRenderer.java @@ -37,7 +37,7 @@ public class GLRenderer implements GLSurfaceView.Renderer, WindowManager.OnWindo private final float[] tmpXForm2 = XForm.getInstance(); private final CursorMaterial cursorMaterial = new CursorMaterial(); private final WindowMaterial windowMaterial = new WindowMaterial(); - public final Viewport viewport = new Viewport(); + public final ViewTransformation viewTransformation = new ViewTransformation(); private final Drawable rootCursorDrawable; private final ArrayList renderableWindows = new ArrayList<>(); private String forceFullscreenWMClass = null; @@ -48,6 +48,7 @@ public class GLRenderer implements GLSurfaceView.Renderer, WindowManager.OnWindo private boolean screenOffsetYRelativeToCursor = false; private String[] unviewableWMClasses = null; private float magnifierZoom = 1.0f; + private boolean magnifierEnabled = true; private int surfaceWidth; private int surfaceHeight; @@ -89,11 +90,13 @@ public class GLRenderer implements GLSurfaceView.Renderer, WindowManager.OnWindo activity.init(); width = activity.getWidth(); height = activity.getHeight(); + GLES20.glViewport(0, 0, width, height); + magnifierEnabled = false; } surfaceWidth = width; surfaceHeight = height; - viewport.update(width, height, xServer.screenInfo.width, xServer.screenInfo.height); + viewTransformation.update(width, height, xServer.screenInfo.width, xServer.screenInfo.height); } @Override @@ -109,39 +112,56 @@ public class GLRenderer implements GLSurfaceView.Renderer, WindowManager.OnWindo private void drawFrame() { boolean xrFrame = false; - if (XrActivity.isSupported()) { - xrFrame = XrActivity.getInstance().beginFrame(XrActivity.getImmersive(), XrActivity.getSBS()); - } + if (XrActivity.isSupported()) xrFrame = XrActivity.getInstance().beginFrame(XrActivity.getImmersive(), XrActivity.getSBS()); - if (viewportNeedsUpdate) { + if (viewportNeedsUpdate && magnifierEnabled) { if (fullscreen) { GLES20.glViewport(0, 0, surfaceWidth, surfaceHeight); } - else GLES20.glViewport(viewport.x, viewport.y, viewport.width, viewport.height); + else GLES20.glViewport(viewTransformation.viewOffsetX, viewTransformation.viewOffsetY, viewTransformation.viewWidth, viewTransformation.viewHeight); viewportNeedsUpdate = false; } GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); - float pointerX = 0; - float pointerY = 0; - float magnifierZoom = !screenOffsetYRelativeToCursor ? this.magnifierZoom : 1.0f; + if (magnifierEnabled) { + float pointerX = 0; + float pointerY = 0; + float magnifierZoom = !screenOffsetYRelativeToCursor ? this.magnifierZoom : 1.0f; - if (magnifierZoom != 1.0f) { - pointerX = Mathf.clamp(xServer.pointer.getX() * magnifierZoom - xServer.screenInfo.width * 0.5f, 0, xServer.screenInfo.width * Math.abs(1.0f - magnifierZoom)); + if (magnifierZoom != 1.0f) { + pointerX = Mathf.clamp(xServer.pointer.getX() * magnifierZoom - xServer.screenInfo.width * 0.5f, 0, xServer.screenInfo.width * Math.abs(1.0f - magnifierZoom)); + } + + if (screenOffsetYRelativeToCursor || magnifierZoom != 1.0f) { + float scaleY = magnifierZoom != 1.0f ? Math.abs(1.0f - magnifierZoom) : 0.5f; + float offsetY = xServer.screenInfo.height * (screenOffsetYRelativeToCursor ? 0.25f : 0.5f); + pointerY = Mathf.clamp(xServer.pointer.getY() * magnifierZoom - offsetY, 0, xServer.screenInfo.height * scaleY); + } + + XForm.makeTransform(tmpXForm2, -pointerX, -pointerY, magnifierZoom, magnifierZoom, 0); } + else { + if (!fullscreen) { + int pointerY = 0; + if (screenOffsetYRelativeToCursor) { + short halfScreenHeight = (short)(xServer.screenInfo.height / 2); + pointerY = Mathf.clamp(xServer.pointer.getY() - halfScreenHeight / 2, 0, halfScreenHeight); + } - if (screenOffsetYRelativeToCursor || magnifierZoom != 1.0f) { - float scaleY = magnifierZoom != 1.0f ? Math.abs(1.0f - magnifierZoom) : 0.5f; - float offsetY = xServer.screenInfo.height * (screenOffsetYRelativeToCursor ? 0.25f : 0.5f); - pointerY = Mathf.clamp(xServer.pointer.getY() * magnifierZoom - offsetY, 0, xServer.screenInfo.height * scaleY); + XForm.makeTransform(tmpXForm2, viewTransformation.sceneOffsetX, viewTransformation.sceneOffsetY - pointerY, viewTransformation.sceneScaleX, viewTransformation.sceneScaleY, 0); + + GLES20.glEnable(GLES20.GL_SCISSOR_TEST); + GLES20.glScissor(viewTransformation.viewOffsetX, viewTransformation.viewOffsetY, viewTransformation.viewWidth, viewTransformation.viewHeight); + } + else XForm.identity(tmpXForm2); } - XForm.makeTransform(tmpXForm2, -pointerX, -pointerY, magnifierZoom, magnifierZoom, 0); - renderWindows(); if (cursorVisible) renderCursor(); + if (!magnifierEnabled && !fullscreen) GLES20.glDisable(GLES20.GL_SCISSOR_TEST); + if (xrFrame) { XrActivity.getInstance().endFrame(); XrActivity.updateControllers(); diff --git a/app/src/main/java/com/winlator/renderer/ViewTransformation.java b/app/src/main/java/com/winlator/renderer/ViewTransformation.java new file mode 100644 index 0000000..f2ea516 --- /dev/null +++ b/app/src/main/java/com/winlator/renderer/ViewTransformation.java @@ -0,0 +1,26 @@ +package com.winlator.renderer; + +public class ViewTransformation { + public int viewOffsetX; + public int viewOffsetY; + public int viewWidth; + public int viewHeight; + public float aspect; + public float sceneScaleX; + public float sceneScaleY; + public float sceneOffsetX; + public float sceneOffsetY; + + public void update(int outerWidth, int outerHeight, int innerWidth, int innerHeight) { + aspect = Math.min((float)outerWidth / innerWidth, (float)outerHeight / innerHeight); + viewWidth = (int)Math.ceil(innerWidth * aspect); + viewHeight = (int)Math.ceil(innerHeight * aspect); + viewOffsetX = (int)((outerWidth - innerWidth * aspect) * 0.5f); + viewOffsetY = (int)((outerHeight - innerHeight * aspect) * 0.5f); + + sceneScaleX = (innerWidth * aspect) / outerWidth; + sceneScaleY = (innerHeight * aspect) / outerHeight; + sceneOffsetX = (innerWidth - innerWidth * sceneScaleX) * 0.5f; + sceneOffsetY = (innerHeight - innerHeight * sceneScaleY) * 0.5f; + } +} diff --git a/app/src/main/java/com/winlator/renderer/Viewport.java b/app/src/main/java/com/winlator/renderer/Viewport.java deleted file mode 100644 index dd60c01..0000000 --- a/app/src/main/java/com/winlator/renderer/Viewport.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.winlator.renderer; - -public class Viewport { - public int x; - public int y; - public int width; - public int height; - public float aspect; - - public void update(int outerWidth, int outerHeight, int innerWidth, int innerHeight) { - aspect = Math.min((float)outerWidth / innerWidth, (float)outerHeight / innerHeight); - width = (int)Math.ceil(innerWidth * aspect); - height = (int)Math.ceil(innerHeight * aspect); - x = (int)((outerWidth - innerWidth * aspect) * 0.5f); - y = (int)((outerHeight - innerHeight * aspect) * 0.5f); - } -} diff --git a/app/src/main/java/com/winlator/widget/CPUListView.java b/app/src/main/java/com/winlator/widget/CPUListView.java index 1c00e5e..78dd8f4 100644 --- a/app/src/main/java/com/winlator/widget/CPUListView.java +++ b/app/src/main/java/com/winlator/widget/CPUListView.java @@ -43,7 +43,7 @@ public class CPUListView extends LinearLayout { String tag = "CPU"+i; CheckBox checkBox = itemView.findViewById(R.id.CheckBox); checkBox.setTag(tag); - checkBox.setChecked(checkedCPUList != null ? checkedCPUList.contains(String.valueOf(i)) : i > 0); + checkBox.setChecked(checkedCPUList == null || checkedCPUList.contains(String.valueOf(i))); ((TextView)itemView.findViewById(R.id.TextView)).setText(tag); addView(itemView); @@ -55,6 +55,12 @@ public class CPUListView extends LinearLayout { refreshContent(); } + public void setCheckedCPUList(int from, int to) { + checkedCPUList.clear(); + for (int i = from; i < to; i++) checkedCPUList.add(String.valueOf(i)); + refreshContent(); + } + public String getCheckedCPUListAsString() { String cpuList = ""; @@ -73,4 +79,8 @@ public class CPUListView extends LinearLayout { } return cpuList; } + + public byte getNumProcessors() { + return numProcessors; + } } diff --git a/app/src/main/java/com/winlator/widget/EnvVarsView.java b/app/src/main/java/com/winlator/widget/EnvVarsView.java new file mode 100644 index 0000000..6aeac87 --- /dev/null +++ b/app/src/main/java/com/winlator/widget/EnvVarsView.java @@ -0,0 +1,160 @@ +package com.winlator.widget; + +import android.content.Context; +import android.text.InputType; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.ToggleButton; + +import androidx.annotation.Nullable; + +import com.winlator.R; +import com.winlator.core.AppUtils; +import com.winlator.core.EnvVars; +import com.winlator.core.UnitUtils; + +import java.util.Arrays; + +public class EnvVarsView extends FrameLayout { + public static final String[][] knownEnvVars = { + {"ZINK_DESCRIPTORS", "SELECT", "auto", "lazy", "cached", "notemplates"}, + {"ZINK_DEBUG", "SELECT_MULTIPLE", "nir", "spirv", "tgsi", "validation", "sync", "compact", "noreorder"}, + {"MESA_SHADER_CACHE_DISABLE", "CHECKBOX", "false", "true"}, + {"mesa_glthread", "CHECKBOX", "false", "true"}, + {"WINEESYNC", "CHECKBOX", "0", "1"}, + {"TU_DEBUG", "SELECT_MULTIPLE", "startup", "nir", "nobin", "sysmem", "gmem", "forcebin", "layout", "noubwc", "nomultipos", "nolrz", "nolrzfc", "perf", "perfc", "flushall", "syncdraw", "push_consts_per_stage", "rast_order", "unaligned_store", "log_skip_gmem_ops", "dynamic", "bos", "3d_load", "fdm", "noconform", "rd"}, + {"DXVK_HUD", "SELECT_MULTIPLE", "devinfo", "fps", "frametimes", "submissions", "drawcalls", "pipelines", "descriptors", "memory", "gpuload", "version", "api", "cs", "compiler", "samplers"}, + {"MESA_EXTENSION_MAX_YEAR", "NUMBER"}, + {"PULSE_LATENCY_MSEC", "NUMBER"}, + {"MESA_VK_WSI_PRESENT_MODE", "SELECT", "immediate", "mailbox", "fifo", "relaxed"} + }; + private final LinearLayout container; + private final TextView emptyTextView; + private final LayoutInflater inflater; + + private interface GetValueCallback { + String call(); + } + + public EnvVarsView(Context context) { + this(context, null); + } + + public EnvVarsView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public EnvVarsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public EnvVarsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + inflater = LayoutInflater.from(context); + container = new LinearLayout(context); + container.setOrientation(LinearLayout.VERTICAL); + container.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + addView(container); + + emptyTextView = new TextView(context); + emptyTextView.setText(R.string.no_items_to_display); + emptyTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + emptyTextView.setGravity(Gravity.CENTER); + int padding = (int)UnitUtils.dpToPx(16); + emptyTextView.setPadding(padding, padding, padding, padding); + addView(emptyTextView); + } + + private String[] findKnownEnvVar(String name) { + for (String[] values : knownEnvVars) if (values[0].equals(name)) return values; + return null; + } + + public String getEnvVars() { + EnvVars envVars = new EnvVars(); + for (int i = 0; i < container.getChildCount(); i++) { + View child = container.getChildAt(i); + GetValueCallback getValueCallback = (GetValueCallback)child.getTag(); + String name = ((TextView)child.findViewById(R.id.TextView)).getText().toString(); + String value = getValueCallback.call().trim().replace(" ", ""); + if (!value.isEmpty()) envVars.put(name, value); + } + return envVars.toString(); + } + + public boolean containsName(String name) { + for (int i = 0; i < container.getChildCount(); i++) { + View child = container.getChildAt(i); + String text = ((TextView)child.findViewById(R.id.TextView)).getText().toString(); + if (name.equals(text)) return true; + } + return false; + } + + public void add(String name, String value) { + final Context context = getContext(); + final View itemView = inflater.inflate(R.layout.env_vars_list_item, container, false); + ((TextView)itemView.findViewById(R.id.TextView)).setText(name); + + String[] knownEnvVar = findKnownEnvVar(name); + GetValueCallback getValueCallback; + + String type = knownEnvVar != null ? knownEnvVar[1] : "TEXT"; + + switch (type) { + case "CHECKBOX": + final ToggleButton toggleButton = itemView.findViewById(R.id.ToggleButton); + toggleButton.setVisibility(VISIBLE); + toggleButton.setChecked(value.equals("1") || value.equals("true")); + getValueCallback = () -> toggleButton.isChecked() ? knownEnvVar[3] : knownEnvVar[2]; + break; + case "SELECT": + String[] items = Arrays.copyOfRange(knownEnvVar, 2, knownEnvVar.length); + final Spinner spinner = itemView.findViewById(R.id.Spinner); + spinner.setAdapter(new ArrayAdapter<>(context, android.R.layout.simple_spinner_dropdown_item, items)); + AppUtils.setSpinnerSelectionFromValue(spinner, value); + spinner.setVisibility(VISIBLE); + getValueCallback = () -> spinner.getSelectedItem().toString(); + break; + case "SELECT_MULTIPLE": + final MultiSelectionComboBox comboBox = itemView.findViewById(R.id.MultiSelectionComboBox); + comboBox.setItems(Arrays.copyOfRange(knownEnvVar, 2, knownEnvVar.length)); + comboBox.setSelectedItems(value.split(",")); + comboBox.setVisibility(VISIBLE); + getValueCallback = comboBox::getSelectedItemsAsString; + break; + case "TEXT": + case "NUMBER": + default: + final EditText editText = itemView.findViewById(R.id.EditText); + editText.setVisibility(VISIBLE); + editText.setText(value); + if (type.equals("NUMBER")) editText.setInputType(InputType.TYPE_CLASS_NUMBER); + getValueCallback = () -> editText.getText().toString(); + break; + } + + itemView.setTag(getValueCallback); + itemView.findViewById(R.id.BTRemove).setOnClickListener((v) -> { + container.removeView(itemView); + if (container.getChildCount() == 0) emptyTextView.setVisibility(View.VISIBLE); + }); + container.addView(itemView); + emptyTextView.setVisibility(View.GONE); + } + + public void setEnvVars(EnvVars envVars) { + container.removeAllViews(); + for (String name : envVars) add(name, envVars.get(name)); + } +} diff --git a/app/src/main/java/com/winlator/widget/FrameRating.java b/app/src/main/java/com/winlator/widget/FrameRating.java new file mode 100644 index 0000000..53455a0 --- /dev/null +++ b/app/src/main/java/com/winlator/widget/FrameRating.java @@ -0,0 +1,55 @@ +package com.winlator.widget; + +import android.content.Context; +import android.os.SystemClock; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.TextView; + +import com.winlator.R; + +import java.util.Locale; + +public class FrameRating extends FrameLayout implements Runnable { + private long lastTime = 0; + private int frameCount = 0; + private float lastFPS = 0; + private final TextView textView; + + public FrameRating(Context context) { + this(context, null); + } + + public FrameRating(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public FrameRating(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + + View view = LayoutInflater.from(context).inflate(R.layout.frame_rating, this, false); + textView = view.findViewById(R.id.TVFPS); + addView(view); + } + + public void update() { + if (lastTime == 0) lastTime = SystemClock.elapsedRealtime(); + long time = SystemClock.elapsedRealtime(); + if (time >= lastTime + 500) { + lastFPS = ((float)(frameCount * 1000) / (time - lastTime)); + post(this); + lastTime = time; + frameCount = 0; + } + + frameCount++; + } + + @Override + public void run() { + if (getVisibility() == GONE) setVisibility(View.VISIBLE); + textView.setText(String.format(Locale.ENGLISH, "%.1f", lastFPS)); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/winlator/widget/InputControlsView.java b/app/src/main/java/com/winlator/widget/InputControlsView.java index a0cd595..b64d3e8 100644 --- a/app/src/main/java/com/winlator/widget/InputControlsView.java +++ b/app/src/main/java/com/winlator/widget/InputControlsView.java @@ -12,7 +12,6 @@ import android.graphics.Point; import android.graphics.PointF; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; -import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; @@ -26,7 +25,6 @@ import com.winlator.inputcontrols.ExternalController; import com.winlator.inputcontrols.ExternalControllerBinding; import com.winlator.inputcontrols.GamepadState; import com.winlator.math.Mathf; -import com.winlator.math.XForm; import com.winlator.winhandler.WinHandler; import com.winlator.xserver.Pointer; import com.winlator.xserver.XServer; @@ -239,6 +237,10 @@ public class InputControlsView extends View { return colorFilter; } + public TouchpadView getTouchpadView() { + return touchpadView; + } + public void setTouchpadView(TouchpadView touchpadView) { this.touchpadView = touchpadView; } @@ -426,7 +428,6 @@ public class InputControlsView extends View { int buttonIdx = binding.ordinal() - Binding.GAMEPAD_BUTTON_A.ordinal(); if (buttonIdx <= 11) { state.setPressed(buttonIdx, isActionDown); - if (winHandler != null) winHandler.saveGamepadState(state); } else if (binding == Binding.GAMEPAD_LEFT_THUMB_UP || binding == Binding.GAMEPAD_LEFT_THUMB_DOWN) { state.thumbLY = isActionDown ? offset : 0; @@ -448,6 +449,7 @@ public class InputControlsView extends View { if (winHandler != null) { ExternalController controller = winHandler.getCurrentController(); if (controller != null) controller.state.copy(state); + winHandler.sendGamepadState(); } } else { diff --git a/app/src/main/java/com/winlator/widget/LogView.java b/app/src/main/java/com/winlator/widget/LogView.java new file mode 100644 index 0000000..9e04bd5 --- /dev/null +++ b/app/src/main/java/com/winlator/widget/LogView.java @@ -0,0 +1,243 @@ +package com.winlator.widget; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PointF; +import android.os.Environment; +import android.text.format.DateFormat; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; + +import androidx.annotation.Nullable; + +import com.winlator.R; +import com.winlator.core.AppUtils; +import com.winlator.core.FileUtils; +import com.winlator.core.UnitUtils; +import com.winlator.math.Mathf; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; + +public class LogView extends View { + private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + private final ArrayList lines = new ArrayList<>(); + private final float rowHeight = UnitUtils.dpToPx(30); + private final float defaultTextSize = UnitUtils.dpToPx(16); + private final float minScrollThumbSize = UnitUtils.dpToPx(6); + private final PointF lastPoint = new PointF(); + private final PointF scrollPosition = new PointF(); + private final PointF scrollSize = new PointF(); + private boolean isActionDown = false; + private boolean scrollingHorizontally = false; + private boolean scrollingVertically = false; + private final Object lock = new Object(); + + public LogView(Context context) { + this(context, null); + } + + public LogView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public LogView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public LogView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + FileUtils.delete(getLogFile()); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + computeScrollSize(); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + int width = getWidth(); + int height = getHeight(); + + if (width == 0 || height == 0) return; + + synchronized (lock) { + paint.setStyle(Paint.Style.FILL); + + if (lines.isEmpty()) { + paint.setTextSize(UnitUtils.dpToPx(20)); + paint.setColor(0xffbdbdbd); + String text = getContext().getString(R.string.no_items_to_display); + float centerX = (width - paint.measureText(text)) * 0.5f; + float centerY = (height - paint.getFontSpacing()) * 0.5f - paint.ascent(); + canvas.drawText(text, centerX, centerY, paint); + return; + } + + paint.setTextSize(defaultTextSize); + float textHeight = paint.getFontSpacing(); + + float rowY = -scrollPosition.y; + for (int i = 0, count = lines.size(); i < count; i++) { + if ((rowY + rowHeight) < 0 || rowY >= height) { + rowY += rowHeight; + continue; + } + + paint.setColor((i % 2) != 0 ? 0xffe1f5fe : 0xffffffff); + canvas.drawRect(-scrollPosition.x, rowY, width, rowY + rowHeight, paint); + + paint.setColor(0xff212121); + float centerY = (rowY - paint.ascent()) + (rowHeight - textHeight) * 0.5f; + canvas.drawText(lines.get(i), -scrollPosition.x, centerY, paint); + rowY += rowHeight; + } + + drawScrollThumbs(canvas); + } + } + + private void drawScrollThumbs(Canvas canvas) { + float scrollThumbX = getScrollThumbX(); + float scrollThumbY = getScrollThumbY(); + float scrollThumbWidth = getScrollThumbWidth(); + float scrollThumbHeight = getScrollThumbHeight(); + + paint.setColor(0x33000000); + float radius = minScrollThumbSize * 0.5f; + + canvas.drawRoundRect(scrollThumbX, getHeight() - minScrollThumbSize, scrollThumbX + scrollThumbWidth, getHeight(), radius, radius, paint); + canvas.drawRoundRect(getWidth() - minScrollThumbSize, scrollThumbY, getWidth(), scrollThumbY + scrollThumbHeight, radius, radius, paint); + } + + public float getScrollMaxLeft() { + return Math.max(0, scrollSize.x - getWidth()); + } + + public float getScrollMaxTop() { + return Math.max(0, scrollSize.y - getHeight()); + } + + public float getScrollThumbX() { + float width = getWidth(); + if (scrollSize.x > 0 && scrollSize.x > width) return scrollPosition.x * (width / scrollSize.x); + return -Float.MAX_VALUE; + } + + public float getScrollThumbY() { + float height = getHeight(); + if (scrollSize.y > 0 && scrollSize.y > height) return scrollPosition.y * (height / scrollSize.y); + return -Float.MAX_VALUE; + } + + public float getScrollThumbWidth() { + float width = getWidth(); + if (scrollSize.x > 0 && scrollSize.x > width) { + return Math.max(width - width * (getScrollMaxLeft() / scrollSize.x), minScrollThumbSize); + } + return 0; + } + + public float getScrollThumbHeight() { + float height = getHeight(); + if (scrollSize.y > 0 && scrollSize.y > height) { + return Math.max(height - height * (getScrollMaxTop() / scrollSize.y), minScrollThumbSize); + } + return 0; + } + + private void computeScrollSize() { + int width = getWidth(); + int height = getHeight(); + if (width == 0 || height == 0) return; + + float maxWidth = 0; + paint.setTextSize(defaultTextSize); + for (int i = 0, count = lines.size(); i < count; i++) maxWidth = Math.max(paint.measureText(lines.get(i)), maxWidth); + scrollSize.x = Math.max(maxWidth, width); + scrollSize.y = Math.max(rowHeight * lines.size(), height); + scrollPosition.set(0, getScrollMaxTop()); + } + + public void clear() { + synchronized (lock) { + lines.clear(); + } + postInvalidate(); + } + + public void append(String line) { + synchronized (lock) { + lines.add("["+DateFormat.format("HH:mm:ss", System.currentTimeMillis())+"] "+line.replace("\n", "")); + computeScrollSize(); + } + postInvalidate(); + } + + private static File getLogFile() { + File winlatorDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "Winlator"); + winlatorDir.mkdirs(); + return new File(winlatorDir, "logs.txt"); + } + + public void exportToFile() { + final File logFile = getLogFile(); + if (logFile.isFile()) logFile.delete(); + try (BufferedWriter writer = new BufferedWriter(new FileWriter(logFile))) { + synchronized (lock) { + for (String line : lines) writer.write(line+"\n"); + } + + String path = logFile.getPath().substring(logFile.getPath().indexOf(Environment.DIRECTORY_DOWNLOADS)); + Context context = getContext(); + AppUtils.showToast(context, context.getString(R.string.logs_exported_to)+" "+path); + } + catch (IOException e) {} + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + lastPoint.set(event.getX(), event.getY()); + isActionDown = true; + scrollingHorizontally = false; + scrollingVertically = false; + break; + case MotionEvent.ACTION_MOVE: + if (isActionDown) { + float dx = event.getX() - lastPoint.x; + float dy = event.getY() - lastPoint.y; + + if (Math.abs(dx) > 10) scrollingHorizontally = true; + if (Math.abs(dy) > 10) scrollingVertically = true; + + if (scrollingHorizontally) { + scrollPosition.x = Mathf.clamp(scrollPosition.x - dx, 0, getScrollMaxLeft()); + lastPoint.set(event.getX(), event.getY()); + invalidate(); + } + + if (scrollingVertically) { + scrollPosition.y = Mathf.clamp(scrollPosition.y - dy, 0, getScrollMaxTop()); + lastPoint.set(event.getX(), event.getY()); + invalidate(); + } + } + break; + case MotionEvent.ACTION_UP: + isActionDown = false; + break; + } + + return true; + } +} diff --git a/app/src/main/java/com/winlator/widget/MultiSelectionComboBox.java b/app/src/main/java/com/winlator/widget/MultiSelectionComboBox.java new file mode 100644 index 0000000..9ccd7bc --- /dev/null +++ b/app/src/main/java/com/winlator/widget/MultiSelectionComboBox.java @@ -0,0 +1,87 @@ +package com.winlator.widget; + +import android.content.Context; +import android.util.ArraySet; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.CheckedTextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatTextView; +import androidx.appcompat.widget.ListPopupWindow; + +import com.winlator.core.UnitUtils; + +import java.util.Collections; + +public class MultiSelectionComboBox extends AppCompatTextView { + private String[] items; + private final ArraySet selectedItemSet = new ArraySet<>(); + + public MultiSelectionComboBox(@NonNull Context context) { + this(context, null); + } + + public MultiSelectionComboBox(@NonNull Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public MultiSelectionComboBox(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public String[] getItems() { + return items; + } + + public void setItems(String[] items) { + this.items = items; + setText(getSelectedItemsAsString()); + } + + public void setSelectedItems(String[] selectedItems) { + Collections.addAll(selectedItemSet, selectedItems); + setText(getSelectedItemsAsString()); + } + + public String getSelectedItemsAsString() { + String result = ""; + for (String item : items) if (selectedItemSet.contains(item)) result += (!result.isEmpty() ? "," : "")+item; + return result; + } + + @Override + public boolean performClick() { + if (items == null || items.length == 0) return true; + final ArrayAdapter adapter = new ArrayAdapter(getContext(), android.R.layout.simple_list_item_multiple_choice, items) { + @NonNull + @Override + public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { + CheckedTextView checkedTextView = (CheckedTextView)super.getView(position, convertView, parent); + checkedTextView.setChecked(selectedItemSet.contains(items[position])); + setText(getSelectedItemsAsString()); + return checkedTextView; + } + }; + + ListPopupWindow popupWindow = new ListPopupWindow(getContext()); + popupWindow.setAdapter(adapter); + popupWindow.setAnchorView(this); + popupWindow.setWidth((int)UnitUtils.dpToPx(260)); + + popupWindow.setOnItemClickListener((parent, view, position, id) -> { + String item = items[position]; + if (selectedItemSet.contains(item)) { + selectedItemSet.remove(item); + } + else selectedItemSet.add(item); + adapter.notifyDataSetChanged(); + }); + + popupWindow.show(); + return true; + } +} diff --git a/app/src/main/java/com/winlator/widget/TouchpadView.java b/app/src/main/java/com/winlator/widget/TouchpadView.java index 096223f..ce77a42 100644 --- a/app/src/main/java/com/winlator/widget/TouchpadView.java +++ b/app/src/main/java/com/winlator/widget/TouchpadView.java @@ -8,9 +8,9 @@ import android.view.ViewGroup; import android.widget.FrameLayout; import com.winlator.core.AppUtils; -import com.winlator.core.CursorLocker; +import com.winlator.math.Mathf; import com.winlator.math.XForm; -import com.winlator.renderer.Viewport; +import com.winlator.renderer.ViewTransformation; import com.winlator.winhandler.MouseEventFlags; import com.winlator.winhandler.WinHandler; import com.winlator.xserver.Pointer; @@ -19,7 +19,10 @@ import com.winlator.xserver.XServer; public class TouchpadView extends View { private static final byte MAX_FINGERS = 4; private static final short MAX_TWO_FINGERS_SCROLL_DISTANCE = 350; - private static final byte MAX_TAP_TRAVEL_DISTANCE = 10; + public static final byte MAX_TAP_TRAVEL_DISTANCE = 10; + public static final short MAX_TAP_MILLISECONDS = 200; + public static final float CURSOR_ACCELERATION = 1.25f; + public static final byte CURSOR_ACCELERATION_THRESHOLD = 6; private final Finger[] fingers = new Finger[MAX_FINGERS]; private byte numFingers = 0; private float sensitivity = 1.0f; @@ -50,30 +53,30 @@ public class TouchpadView extends View { } private void updateXform(int outerWidth, int outerHeight, int innerWidth, int innerHeight) { - Viewport viewport = new Viewport(); - viewport.update(outerWidth, outerHeight, innerWidth, innerHeight); + ViewTransformation viewTransformation = new ViewTransformation(); + viewTransformation.update(outerWidth, outerHeight, innerWidth, innerHeight); - float invAspect = 1.0f / viewport.aspect; + float invAspect = 1.0f / viewTransformation.aspect; if (!xServer.getRenderer().isFullscreen()) { - XForm.makeTranslation(xform, -viewport.x, -viewport.y); + XForm.makeTranslation(xform, -viewTransformation.viewOffsetX, -viewTransformation.viewOffsetY); XForm.scale(xform, invAspect, invAspect); } else XForm.makeScale(xform, invAspect, invAspect); } private class Finger { - private float x; - private float y; - private final float startX; - private final float startY; - private float lastX; - private float lastY; + private int x; + private int y; + private final int startX; + private final int startY; + private int lastX; + private int lastY; private final long touchTime; public Finger(float x, float y) { float[] transformedPoint = XForm.transformPoint(xform, x, y); - this.x = this.startX = this.lastX = transformedPoint[0]; - this.y = this.startY = this.lastY = transformedPoint[1]; + this.x = this.startX = this.lastX = (int)transformedPoint[0]; + this.y = this.startY = this.lastY = (int)transformedPoint[1]; touchTime = System.currentTimeMillis(); } @@ -81,22 +84,24 @@ public class TouchpadView extends View { lastX = this.x; lastY = this.y; float[] transformedPoint = XForm.transformPoint(xform, x, y); - this.x = transformedPoint[0]; - this.y = transformedPoint[1]; + this.x = (int)transformedPoint[0]; + this.y = (int)transformedPoint[1]; } - private int deltaX(float sensitivity) { + private int deltaX() { float dx = (x - lastX) * sensitivity; - return (int)(x <= lastX ? Math.floor(dx) : Math.ceil(dx)); + if (Math.abs(dx) > CURSOR_ACCELERATION_THRESHOLD) dx *= CURSOR_ACCELERATION; + return Mathf.roundPoint(dx); } - private int deltaY(float sensitivity) { + private int deltaY() { float dy = (y - lastY) * sensitivity; - return (int)(y <= lastY ? Math.floor(dy) : Math.ceil(dy)); + if (Math.abs(dy) > CURSOR_ACCELERATION_THRESHOLD) dy *= CURSOR_ACCELERATION; + return Mathf.roundPoint(dy); } private boolean isTap() { - return (System.currentTimeMillis() - touchTime) < 200 && travelDistance() < MAX_TAP_TRAVEL_DISTANCE; + return (System.currentTimeMillis() - touchTime) < MAX_TAP_MILLISECONDS && travelDistance() < MAX_TAP_TRAVEL_DISTANCE; } private float travelDistance() { @@ -214,12 +219,10 @@ public class TouchpadView extends View { } if (!scrolling && numFingers <= 2 && !skipPointerMove) { - float distance = (float)Math.hypot(finger1.x - finger1.lastX, finger1.y - finger1.lastY); - float sensitivity = this.sensitivity * Math.min(distance, 1.0f); - int dx = finger1.deltaX(sensitivity); - int dy = finger1.deltaY(sensitivity); + int dx = finger1.deltaX(); + int dy = finger1.deltaY(); - if (xServer.cursorLocker.getState() == CursorLocker.State.LOCKED) { + if (xServer.isRelativeMouseMovement()) { WinHandler winHandler = xServer.getWinHandler(); winHandler.mouseEvent(MouseEventFlags.MOVE, dx, dy, 0); } @@ -334,4 +337,20 @@ public class TouchpadView extends View { } return handled; } + + public float[] computeDeltaPoint(float lastX, float lastY, float x, float y) { + final float[] result = {0, 0}; + + XForm.transformPoint(xform, lastX, lastY, result); + lastX = result[0]; + lastY = result[1]; + + XForm.transformPoint(xform, x, y, result); + x = result[0]; + y = result[1]; + + result[0] = x - lastX; + result[1] = y - lastY; + return result; + } } diff --git a/app/src/main/java/com/winlator/winhandler/ProcessInfo.java b/app/src/main/java/com/winlator/winhandler/ProcessInfo.java index 95c4e6a..6b28526 100644 --- a/app/src/main/java/com/winlator/winhandler/ProcessInfo.java +++ b/app/src/main/java/com/winlator/winhandler/ProcessInfo.java @@ -9,12 +9,14 @@ public class ProcessInfo { public final String name; public final long memoryUsage; public final int affinityMask; + public final boolean wow64Process; - public ProcessInfo(int pid, String name, long memoryUsage, int affinityMask) { + public ProcessInfo(int pid, String name, long memoryUsage, int affinityMask, boolean wow64Process) { this.pid = pid; this.name = name; this.memoryUsage = memoryUsage; this.affinityMask = affinityMask; + this.wow64Process = wow64Process; } public String getFormattedMemoryUsage() { diff --git a/app/src/main/java/com/winlator/winhandler/RequestCodes.java b/app/src/main/java/com/winlator/winhandler/RequestCodes.java index ee981a5..042f81c 100644 --- a/app/src/main/java/com/winlator/winhandler/RequestCodes.java +++ b/app/src/main/java/com/winlator/winhandler/RequestCodes.java @@ -14,4 +14,5 @@ abstract class RequestCodes { public static final byte RELEASE_GAMEPAD = 10; public static final byte KEYBOARD_EVENT = 11; public static final byte BRING_TO_FRONT = 12; + public static final byte CURSOR_POS_FEEDBACK = 13; } \ No newline at end of file diff --git a/app/src/main/java/com/winlator/winhandler/TaskManagerDialog.java b/app/src/main/java/com/winlator/winhandler/TaskManagerDialog.java index 45dcd25..42e69de 100644 --- a/app/src/main/java/com/winlator/winhandler/TaskManagerDialog.java +++ b/app/src/main/java/com/winlator/winhandler/TaskManagerDialog.java @@ -2,11 +2,13 @@ package com.winlator.winhandler; import android.app.ActivityManager; import android.content.Context; +import android.graphics.Bitmap; import android.os.Build; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; +import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.PopupMenu; import android.widget.TextView; @@ -15,10 +17,16 @@ import com.winlator.R; import com.winlator.XServerDisplayActivity; import com.winlator.contentdialog.ContentDialog; import com.winlator.core.CPUStatus; +import com.winlator.core.FileUtils; import com.winlator.core.ProcessHelper; import com.winlator.core.StringUtils; import com.winlator.widget.CPUListView; +import com.winlator.xenvironment.ImageFs; +import com.winlator.xserver.Window; +import com.winlator.xserver.XLock; +import com.winlator.xserver.XServer; +import java.io.File; import java.util.Timer; import java.util.TimerTask; @@ -51,6 +59,7 @@ public class TaskManagerDialog extends ContentDialog implements OnGetProcessInfo activity.getWinHandler().setOnGetProcessInfoListener(null); }); + FileUtils.clear(getIconDir(activity)); inflater = LayoutInflater.from(activity); } @@ -105,6 +114,12 @@ public class TaskManagerDialog extends ContentDialog implements OnGetProcessInfo dialog.show(); } + public static File getIconDir(Context context) { + File iconDir = new File(ImageFs.find(context).getRootDir(), "home/xuser/.local/share/icons/taskmgr"); + if (!iconDir.isDirectory()) iconDir.mkdirs(); + return iconDir; + } + @Override public void show() { update(); @@ -137,10 +152,25 @@ public class TaskManagerDialog extends ContentDialog implements OnGetProcessInfo int childCount = container.getChildCount(); View itemView = index < childCount ? container.getChildAt(index) : inflater.inflate(R.layout.process_info_list_item, container, false); - ((TextView)itemView.findViewById(R.id.TVName)).setText(processInfo.name); + ((TextView)itemView.findViewById(R.id.TVName)).setText(processInfo.name+(processInfo.wow64Process ? " *32" : "")); ((TextView)itemView.findViewById(R.id.TVPID)).setText(String.valueOf(processInfo.pid)); ((TextView)itemView.findViewById(R.id.TVMemoryUsage)).setText(processInfo.getFormattedMemoryUsage()); itemView.findViewById(R.id.BTMenu).setOnClickListener((v) -> showListItemMenu(v, processInfo)); + + XServer xServer = activity.getXServer(); + Window window; + + try (XLock xlock = xServer.lock(XServer.Lockable.WINDOW_MANAGER)) { + window = xServer.windowManager.findWindowWithProcessId(processInfo.pid); + } + + ImageView ivIcon = itemView.findViewById(R.id.IVIcon); + ivIcon.setImageResource(R.drawable.taskmgr_process); + if (window != null) { + Bitmap icon = xServer.pixmapManager.getWindowIcon(window); + if (icon != null) ivIcon.setImageBitmap(icon); + } + if (index >= childCount) container.addView(itemView); if (index == numProcesses-1 && childCount > numProcesses) { diff --git a/app/src/main/java/com/winlator/winhandler/WinHandler.java b/app/src/main/java/com/winlator/winhandler/WinHandler.java index de5ec73..840ca82 100644 --- a/app/src/main/java/com/winlator/winhandler/WinHandler.java +++ b/app/src/main/java/com/winlator/winhandler/WinHandler.java @@ -7,16 +7,19 @@ import com.winlator.XServerDisplayActivity; import com.winlator.core.StringUtils; import com.winlator.inputcontrols.ControlsProfile; import com.winlator.inputcontrols.ExternalController; -import com.winlator.inputcontrols.GamepadState; +import com.winlator.xserver.XServer; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; +import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayDeque; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executors; public class WinHandler { @@ -34,10 +37,10 @@ public class WinHandler { private boolean running = false; private OnGetProcessInfoListener onGetProcessInfoListener; private ExternalController currentController; - private final ArrayDeque gamepadStateQueue = new ArrayDeque<>(); private InetAddress localhost; private byte dinputMapperType = DINPUT_MAPPER_TYPE_XINPUT; private final XServerDisplayActivity activity; + private final List gamepadClients = new CopyOnWriteArrayList<>(); public WinHandler(XServerDisplayActivity activity) { this.activity = activity; @@ -102,13 +105,28 @@ public class WinHandler { }); } + public void setProcessAffinity(final String processName, final int affinityMask) { + addAction(() -> { + byte[] bytes = processName.getBytes(); + sendData.rewind(); + sendData.put(RequestCodes.SET_PROCESS_AFFINITY); + sendData.putInt(9 + bytes.length); + sendData.putInt(0); + sendData.putInt(affinityMask); + sendData.put((byte)bytes.length); + sendData.put(bytes); + sendPacket(CLIENT_PORT); + }); + } + public void setProcessAffinity(final int pid, final int affinityMask) { addAction(() -> { sendData.rewind(); sendData.put(RequestCodes.SET_PROCESS_AFFINITY); - sendData.putInt(8); + sendData.putInt(9); sendData.putInt(pid); sendData.putInt(affinityMask); + sendData.put((byte)0); sendPacket(CLIENT_PORT); }); } @@ -123,6 +141,7 @@ public class WinHandler { sendData.putShort((short)dx); sendData.putShort((short)dy); sendData.putShort((short)wheelDelta); + sendData.put((byte)((flags & MouseEventFlags.MOVE) != 0 ? 1 : 0)); // cursor pos feedback sendPacket(CLIENT_PORT); }); } @@ -139,17 +158,17 @@ public class WinHandler { } public void bringToFront(final String processName) { - bringToFront(processName, false); + bringToFront(processName, 0); } - public void bringToFront(final String processName, final boolean reverse) { + public void bringToFront(final String processName, final long handle) { addAction(() -> { sendData.rewind(); sendData.put(RequestCodes.BRING_TO_FRONT); byte[] bytes = processName.getBytes(); sendData.putInt(bytes.length); sendData.put(bytes); - sendData.put((byte)(reverse ? 1 : 0)); + sendData.putLong(handle); sendPacket(CLIENT_PORT); }); } @@ -216,29 +235,37 @@ public class WinHandler { int pid = receiveData.getInt(); long memoryUsage = receiveData.getLong(); int affinityMask = receiveData.getInt(); + boolean wow64Process = receiveData.get() == 1; byte[] bytes = new byte[32]; receiveData.get(bytes); String name = StringUtils.fromANSIString(bytes); - onGetProcessInfoListener.onGetProcessInfo(index, numProcesses, new ProcessInfo(pid, name, memoryUsage, affinityMask)); + onGetProcessInfoListener.onGetProcessInfo(index, numProcesses, new ProcessInfo(pid, name, memoryUsage, affinityMask, wow64Process)); break; } case RequestCodes.GET_GAMEPAD: { boolean isXInput = receiveData.get() == 1; + boolean notify = receiveData.get() == 1; final ControlsProfile profile = activity.getInputControlsView().getProfile(); boolean useVirtualGamepad = profile != null && profile.isVirtualGamepad(); if (!useVirtualGamepad && (currentController == null || !currentController.isConnected())) { - releaseCurrentController(); currentController = ExternalController.getController(0); } + final boolean enabled = currentController != null || useVirtualGamepad; + + if (enabled && notify) { + if (!gamepadClients.contains(port)) gamepadClients.add(port); + } + else gamepadClients.remove(Integer.valueOf(port)); + addAction(() -> { sendData.rewind(); sendData.put(RequestCodes.GET_GAMEPAD); - if (currentController != null || useVirtualGamepad) { + if (enabled) { sendData.putInt(!useVirtualGamepad ? currentController.getDeviceId() : profile.id); sendData.put(dinputMapperType); byte[] bytes = (useVirtualGamepad ? profile.getName() : currentController.getName()).getBytes(); @@ -255,35 +282,41 @@ public class WinHandler { int gamepadId = receiveData.getInt(); final ControlsProfile profile = activity.getInputControlsView().getProfile(); boolean useVirtualGamepad = profile != null && profile.isVirtualGamepad(); + final boolean enabled = currentController != null || useVirtualGamepad; if (currentController != null && currentController.getDeviceId() != gamepadId) currentController = null; addAction(() -> { sendData.rewind(); sendData.put(RequestCodes.GET_GAMEPAD_STATE); - sendData.put((byte)(currentController != null || useVirtualGamepad ? 1 : 0)); + sendData.put((byte)(enabled ? 1 : 0)); - if (currentController != null || useVirtualGamepad) { + if (enabled) { sendData.putInt(gamepadId); - - synchronized (gamepadStateQueue) { - if (gamepadStateQueue.isEmpty()) { - if (useVirtualGamepad) { - profile.getGamepadState().writeTo(sendData); - } - else currentController.state.writeTo(sendData); - } - else sendData.put(gamepadStateQueue.poll()); + if (useVirtualGamepad) { + profile.getGamepadState().writeTo(sendData); } + else currentController.state.writeTo(sendData); } sendPacket(port); }); break; } - case RequestCodes.RELEASE_GAMEPAD: - releaseCurrentController(); + case RequestCodes.RELEASE_GAMEPAD: { + currentController = null; + gamepadClients.clear(); break; + } + case RequestCodes.CURSOR_POS_FEEDBACK: { + short x = receiveData.getShort(); + short y = receiveData.getShort(); + XServer xServer = activity.getXServer(); + xServer.pointer.setX(x); + xServer.pointer.setY(y); + activity.getXServerView().requestRender(); + break; + } } } @@ -302,7 +335,9 @@ public class WinHandler { startSendThread(); Executors.newSingleThreadExecutor().execute(() -> { try { - socket = new DatagramSocket(SERVER_PORT); + socket = new DatagramSocket(null); + socket.setReuseAddress(true); + socket.bind(new InetSocketAddress((InetAddress)null, SERVER_PORT)); while (running) { socket.receive(receivePacket); @@ -318,17 +353,28 @@ public class WinHandler { }); } - public void saveGamepadState(GamepadState state) { - synchronized (gamepadStateQueue) { - if (gamepadStateQueue.size() > 20) gamepadStateQueue.removeLast(); - gamepadStateQueue.add(state.toByteArray()); - } - } + public void sendGamepadState() { + if (!initReceived || gamepadClients.isEmpty()) return; + final ControlsProfile profile = activity.getInputControlsView().getProfile(); + final boolean useVirtualGamepad = profile != null && profile.isVirtualGamepad(); + final boolean enabled = currentController != null || useVirtualGamepad; - private void releaseCurrentController() { - currentController = null; - synchronized (gamepadStateQueue) { - gamepadStateQueue.clear(); + for (final int port : gamepadClients) { + addAction(() -> { + sendData.rewind(); + sendData.put(RequestCodes.GET_GAMEPAD_STATE); + sendData.put((byte)(enabled ? 1 : 0)); + + if (enabled) { + sendData.putInt(!useVirtualGamepad ? currentController.getDeviceId() : profile.id); + if (useVirtualGamepad) { + profile.getGamepadState().writeTo(sendData); + } + else currentController.state.writeTo(sendData); + } + + sendPacket(port); + }); } } @@ -336,6 +382,7 @@ public class WinHandler { boolean handled = false; if (currentController != null && currentController.getDeviceId() == event.getDeviceId()) { handled = currentController.updateStateFromMotionEvent(event); + if (handled) sendGamepadState(); } return handled; } @@ -352,7 +399,7 @@ public class WinHandler { handled = currentController.updateStateFromKeyEvent(event); } - if (handled) saveGamepadState(currentController.state); + if (handled) sendGamepadState(); } return handled; } diff --git a/app/src/main/java/com/winlator/xenvironment/ImageFs.java b/app/src/main/java/com/winlator/xenvironment/ImageFs.java index b46c7e5..5a4109e 100644 --- a/app/src/main/java/com/winlator/xenvironment/ImageFs.java +++ b/app/src/main/java/com/winlator/xenvironment/ImageFs.java @@ -80,6 +80,14 @@ public class ImageFs { return new File(rootDir, "/tmp"); } + public File getLib32Dir() { + return new File(rootDir, "/usr/lib/arm-linux-gnueabihf"); + } + + public File getLib64Dir() { + return new File(rootDir, "/usr/lib/aarch64-linux-gnu"); + } + @NonNull @Override public String toString() { diff --git a/app/src/main/java/com/winlator/xenvironment/ImageFsInstaller.java b/app/src/main/java/com/winlator/xenvironment/ImageFsInstaller.java index 98c035f..5af84dc 100644 --- a/app/src/main/java/com/winlator/xenvironment/ImageFsInstaller.java +++ b/app/src/main/java/com/winlator/xenvironment/ImageFsInstaller.java @@ -14,7 +14,7 @@ import com.winlator.core.DownloadProgressDialog; import com.winlator.core.FileUtils; import com.winlator.core.PreloaderDialog; import com.winlator.core.TarCompressorUtils; -import com.winlator.xenvironment.ImageFs; +import com.winlator.core.WineInfo; import org.json.JSONArray; import org.json.JSONException; @@ -26,11 +26,17 @@ import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicLong; public abstract class ImageFsInstaller { - public static final byte LATEST_VERSION = 5; + public static final byte LATEST_VERSION = 8; private static void resetContainerImgVersions(Context context) { ContainerManager manager = new ContainerManager(context); for (Container container : manager.getContainers()) { + String imgVersion = container.getExtra("imgVersion"); + String wineVersion = container.getWineVersion(); + if (!imgVersion.isEmpty() && WineInfo.isMainWineVersion(wineVersion) && Short.parseShort(imgVersion) <= 5) { + container.putExtra("wineprefixNeedsUpdate", "t"); + } + container.putExtra("imgVersion", null); container.saveData(); } @@ -105,6 +111,7 @@ public abstract class ImageFsInstaller { } public static void generateCompactContainerPattern(final AppCompatActivity activity) { + AppUtils.keepScreenOn(activity); PreloaderDialog preloaderDialog = new PreloaderDialog(activity); preloaderDialog.show(R.string.loading); Executors.newSingleThreadExecutor().execute(() -> { diff --git a/app/src/main/java/com/winlator/xenvironment/components/GuestProgramLauncherComponent.java b/app/src/main/java/com/winlator/xenvironment/components/GuestProgramLauncherComponent.java index 4ab2e31..00f1ee2 100644 --- a/app/src/main/java/com/winlator/xenvironment/components/GuestProgramLauncherComponent.java +++ b/app/src/main/java/com/winlator/xenvironment/components/GuestProgramLauncherComponent.java @@ -6,14 +6,13 @@ import android.os.Process; import androidx.preference.PreferenceManager; -import com.winlator.MainActivity; import com.winlator.box86_64.Box86_64Preset; import com.winlator.box86_64.Box86_64PresetManager; import com.winlator.core.Callback; +import com.winlator.core.DefaultVersion; import com.winlator.core.EnvVars; import com.winlator.core.ProcessHelper; import com.winlator.core.TarCompressorUtils; -import com.winlator.core.DefaultVersion; import com.winlator.xconnector.UnixSocketConfig; import com.winlator.xenvironment.EnvironmentComponent; import com.winlator.xenvironment.ImageFs; @@ -29,6 +28,7 @@ public class GuestProgramLauncherComponent extends EnvironmentComponent { private String box64Preset = Box86_64Preset.COMPATIBILITY; private Callback terminationCallback; private static final Object lock = new Object(); + private boolean wow64Mode = true; @Override public void start() { @@ -65,6 +65,14 @@ public class GuestProgramLauncherComponent extends EnvironmentComponent { this.guestExecutable = guestExecutable; } + public boolean isWoW64Mode() { + return wow64Mode; + } + + public void setWoW64Mode(boolean wow64Mode) { + this.wow64Mode = wow64Mode; + } + public String[] getBindingPaths() { return bindingPaths; } @@ -104,9 +112,12 @@ public class GuestProgramLauncherComponent extends EnvironmentComponent { File tmpDir = environment.getTmpDir(); String nativeLibraryDir = context.getApplicationInfo().nativeLibraryDir; + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); + boolean enableBox86_64Logs = preferences.getBoolean("enable_box86_64_logs", false); + EnvVars envVars = new EnvVars(); - addBox86EnvVars(envVars); - addBox64EnvVars(envVars); + if (!wow64Mode) addBox86EnvVars(envVars, enableBox86_64Logs); + addBox64EnvVars(envVars, enableBox86_64Logs); envVars.put("HOME", ImageFs.HOME_PATH); envVars.put("USER", ImageFs.USER); envVars.put("TMPDIR", "/tmp"); @@ -114,8 +125,10 @@ public class GuestProgramLauncherComponent extends EnvironmentComponent { envVars.put("DISPLAY", ":0"); envVars.put("PATH", imageFs.getWinePath()+"/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"); envVars.put("LD_LIBRARY_PATH", "/usr/lib/aarch64-linux-gnu:/usr/lib/arm-linux-gnueabihf"); - envVars.put("LD_PRELOAD", "libandroid-sysvshm.so"); envVars.put("ANDROID_SYSVSHM_SERVER", UnixSocketConfig.SYSVSHM_SERVER_PATH); + + if ((new File(imageFs.getLib64Dir(), "libandroid-sysvshm.so")).exists() || + (new File(imageFs.getLib32Dir(), "libandroid-sysvshm.so")).exists()) envVars.put("LD_PRELOAD", "libandroid-sysvshm.so"); if (this.envVars != null) envVars.putAll(this.envVars); boolean bindSHM = envVars.get("WINEESYNC").equals("1"); @@ -144,9 +157,8 @@ public class GuestProgramLauncherComponent extends EnvironmentComponent { envVars.clear(); envVars.put("PROOT_TMP_DIR", tmpDir); envVars.put("PROOT_LOADER", nativeLibraryDir+"/libproot-loader.so"); - envVars.put("PROOT_LOADER_32", nativeLibraryDir+"/libproot-loader32.so"); + if (!wow64Mode) envVars.put("PROOT_LOADER_32", nativeLibraryDir+"/libproot-loader32.so"); - if (MainActivity.DEBUG_LEVEL >= 1) ProcessHelper.debugMode = true; return ProcessHelper.exec(command, envVars.toStringArray(), rootDir, (status) -> { synchronized (lock) { pid = -1; @@ -165,7 +177,14 @@ public class GuestProgramLauncherComponent extends EnvironmentComponent { String currentBox64Version = preferences.getString("current_box64_version", ""); File rootDir = imageFs.getRootDir(); - if (!box86Version.equals(currentBox86Version)) { + if (wow64Mode) { + File box86File = new File(rootDir, "/usr/local/bin/box86"); + if (box86File.isFile()) { + box86File.delete(); + preferences.edit().putString("current_box86_version", "").apply(); + } + } + else if (!box86Version.equals(currentBox86Version)) { TarCompressorUtils.extract(TarCompressorUtils.Type.ZSTD, context, "box86_64/box86-"+box86Version+".tzst", rootDir); preferences.edit().putString("current_box86_version", box86Version).apply(); } @@ -176,22 +195,30 @@ public class GuestProgramLauncherComponent extends EnvironmentComponent { } } - private void addBox86EnvVars(EnvVars envVars) { - envVars.put("BOX86_NOBANNER", MainActivity.DEBUG_LEVEL == 1 ? "0" : "1"); + private void addBox86EnvVars(EnvVars envVars, boolean enableLogs) { + envVars.put("BOX86_NOBANNER", ProcessHelper.PRINT_DEBUG && enableLogs ? "0" : "1"); envVars.put("BOX86_DYNAREC", "1"); - if (MainActivity.DEBUG_LEVEL >= 3) envVars.put("BOX86_LOG", MainActivity.DEBUG_LEVEL == 3 ? "1" : "2"); + if (enableLogs) { + envVars.put("BOX86_LOG", "1"); + envVars.put("BOX86_DYNAREC_MISSING", "1"); + } envVars.putAll(Box86_64PresetManager.getEnvVars("box86", environment.getContext(), box86Preset)); envVars.put("BOX86_X11GLX", "1"); envVars.put("BOX86_NORCFILES", "1"); } - private void addBox64EnvVars(EnvVars envVars) { - envVars.put("BOX64_NOBANNER", MainActivity.DEBUG_LEVEL == 1 ? "0" : "1"); + private void addBox64EnvVars(EnvVars envVars, boolean enableLogs) { + envVars.put("BOX64_NOBANNER", ProcessHelper.PRINT_DEBUG && enableLogs ? "0" : "1"); envVars.put("BOX64_DYNAREC", "1"); + if (wow64Mode) envVars.put("BOX64_MMAP32", "1"); + envVars.put("BOX64_AVX", "1"); - if (MainActivity.DEBUG_LEVEL >= 3) envVars.put("BOX64_LOG", MainActivity.DEBUG_LEVEL == 3 ? "1" : "2"); + if (enableLogs) { + envVars.put("BOX64_LOG", "1"); + envVars.put("BOX64_DYNAREC_MISSING", "1"); + } envVars.putAll(Box86_64PresetManager.getEnvVars("box64", environment.getContext(), box64Preset)); envVars.put("BOX64_X11GLX", "1"); diff --git a/app/src/main/java/com/winlator/xenvironment/components/EtcHostsFileUpdateComponent.java b/app/src/main/java/com/winlator/xenvironment/components/NetworkInfoUpdateComponent.java similarity index 59% rename from app/src/main/java/com/winlator/xenvironment/components/EtcHostsFileUpdateComponent.java rename to app/src/main/java/com/winlator/xenvironment/components/NetworkInfoUpdateComponent.java index bf02058..fa1e4ef 100644 --- a/app/src/main/java/com/winlator/xenvironment/components/EtcHostsFileUpdateComponent.java +++ b/app/src/main/java/com/winlator/xenvironment/components/NetworkInfoUpdateComponent.java @@ -1,39 +1,44 @@ package com.winlator.xenvironment.components; -import android.annotation.SuppressLint; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.NetworkInfo; -import android.net.wifi.WifiManager; -import com.winlator.xenvironment.EnvironmentComponent; import com.winlator.core.FileUtils; +import com.winlator.core.NetworkHelper; +import com.winlator.xenvironment.EnvironmentComponent; import java.io.File; -public class EtcHostsFileUpdateComponent extends EnvironmentComponent { +public class NetworkInfoUpdateComponent extends EnvironmentComponent { private BroadcastReceiver broadcastReceiver; - @SuppressLint("WifiManagerLeak") @Override public void start() { Context context = environment.getContext(); final ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); - final WifiManager wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE); + final NetworkHelper networkHelper = new NetworkHelper(context); + updateAdapterInfoFile(0, 0, 0); broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - String ip = "127.0.0.1"; + int ipAddress = 0; + int netmask = 0; + int gateway = 0; + NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); if (networkInfo != null && networkInfo.isAvailable() && networkInfo.isConnected() && networkInfo.getType() == ConnectivityManager.TYPE_WIFI) { - int ipAddress = wifiManager.getConnectionInfo().getIpAddress(); - if (ipAddress != 0) ip = (ipAddress & 255)+"."+((ipAddress >> 8) & 255)+"."+((ipAddress >> 16) & 255)+"."+((ipAddress >> 24) & 255); + ipAddress = networkHelper.getIpAddress(); + netmask = networkHelper.getNetmask(); + gateway = networkHelper.getGateway(); } - updateEtcHostsFile(ip); + + updateAdapterInfoFile(ipAddress, netmask, gateway); + updateEtcHostsFile(ipAddress); } }; @@ -50,7 +55,13 @@ public class EtcHostsFileUpdateComponent extends EnvironmentComponent { } } - private void updateEtcHostsFile(String ip) { + private void updateAdapterInfoFile(int ipAddress, int netmask, int gateway) { + File file = new File(environment.getImageFs().getTmpDir(), "adapterinfo"); + FileUtils.writeString(file, "Android Wi-Fi Adapter,"+NetworkHelper.formatIpAddress(ipAddress)+","+NetworkHelper.formatNetmask(netmask)+","+NetworkHelper.formatIpAddress(gateway)); + } + + private void updateEtcHostsFile(int ipAddress) { + String ip = ipAddress != 0 ? NetworkHelper.formatIpAddress(ipAddress) : "127.0.0.1"; File file = new File(environment.getImageFs().getRootDir(), "etc/hosts"); FileUtils.writeString(file, ip+"\tlocalhost\n"); } diff --git a/app/src/main/java/com/winlator/xenvironment/components/VirGLRendererComponent.java b/app/src/main/java/com/winlator/xenvironment/components/VirGLRendererComponent.java index 493c433..8d04f4d 100644 --- a/app/src/main/java/com/winlator/xenvironment/components/VirGLRendererComponent.java +++ b/app/src/main/java/com/winlator/xenvironment/components/VirGLRendererComponent.java @@ -14,7 +14,6 @@ import com.winlator.xserver.Drawable; import com.winlator.xserver.XServer; import java.io.IOException; -import java.util.ArrayList; public class VirGLRendererComponent extends EnvironmentComponent implements ConnectionHandler, RequestHandler { private final XServer xServer; @@ -105,7 +104,8 @@ public class VirGLRendererComponent extends EnvironmentComponent implements Conn texture.copyFromFramebuffer(framebuffer, drawable.width, drawable.height); } - xServer.getRenderer().xServerView.requestRender(); + Runnable onDrawListener = drawable.getOnDrawListener(); + if (onDrawListener != null) onDrawListener.run(); } private native long handleNewConnection(int fd); diff --git a/app/src/main/java/com/winlator/xserver/DesktopHelper.java b/app/src/main/java/com/winlator/xserver/DesktopHelper.java index 2d66d18..7dea702 100644 --- a/app/src/main/java/com/winlator/xserver/DesktopHelper.java +++ b/app/src/main/java/com/winlator/xserver/DesktopHelper.java @@ -26,7 +26,7 @@ public abstract class DesktopHelper { private static void updateFocusedWindow(XServer xServer) { try (XLock lock = xServer.lock(XServer.Lockable.WINDOW_MANAGER, XServer.Lockable.INPUT_DEVICE)) { Window focusedWindow = xServer.windowManager.getFocusedWindow(); - Window child = xServer.windowManager.rootWindow.getChildByCoords(xServer.pointer.getClampedX(), xServer.pointer.getClampedY()); + Window child = xServer.windowManager.findPointWindow(xServer.pointer.getClampedX(), xServer.pointer.getClampedY()); if (child == null && focusedWindow != xServer.windowManager.rootWindow) { xServer.windowManager.setFocus(xServer.windowManager.rootWindow, WindowManager.FocusRevertTo.NONE); } @@ -37,8 +37,11 @@ public abstract class DesktopHelper { } private static void setFocusedWindow(XServer xServer, Window window) { - boolean parentIsRoot = window.getParent() == xServer.windowManager.rootWindow; - xServer.windowManager.setFocus(window, parentIsRoot ? WindowManager.FocusRevertTo.POINTER_ROOT : WindowManager.FocusRevertTo.PARENT); + if (window.isApplicationWindow()) { + boolean parentIsRoot = window.getParent() == xServer.windowManager.rootWindow; + xServer.windowManager.setFocus(window, parentIsRoot ? WindowManager.FocusRevertTo.POINTER_ROOT : WindowManager.FocusRevertTo.PARENT); + xServer.getWinHandler().bringToFront(window.getClassName(), window.getHandle()); + } } private static void setupXResources(XServer xServer) { diff --git a/app/src/main/java/com/winlator/xserver/InputDeviceManager.java b/app/src/main/java/com/winlator/xserver/InputDeviceManager.java index 973edac..a169a68 100644 --- a/app/src/main/java/com/winlator/xserver/InputDeviceManager.java +++ b/app/src/main/java/com/winlator/xserver/InputDeviceManager.java @@ -1,6 +1,5 @@ package com.winlator.xserver; -import com.winlator.core.CursorLocker; import com.winlator.winhandler.MouseEventFlags; import com.winlator.winhandler.WinHandler; import com.winlator.xserver.events.ButtonPress; @@ -59,9 +58,8 @@ public class InputDeviceManager implements Pointer.OnPointerMotionListener, Keyb } private void updatePointWindow() { - Window pointWindow = xServer.windowManager.findPointWindow(xServer); - sendEnterLeaveNotify(this.pointWindow, pointWindow, PointerWindowEvent.Mode.NORMAL); - this.pointWindow = pointWindow; + Window pointWindow = xServer.windowManager.findPointWindow(xServer.pointer.getClampedX(), xServer.pointer.getClampedY()); + this.pointWindow = pointWindow != null ? pointWindow : xServer.windowManager.rootWindow; } public Window getPointWindow() { @@ -128,7 +126,7 @@ public class InputDeviceManager implements Pointer.OnPointerMotionListener, Keyb @Override public void onPointerButtonPress(Pointer.Button button) { - if (xServer.cursorLocker.getState() == CursorLocker.State.LOCKED) { + if (xServer.isRelativeMouseMovement()) { WinHandler winHandler = xServer.getWinHandler(); int wheelDelta = button == Pointer.Button.BUTTON_SCROLL_UP ? MOUSE_WHEEL_DELTA : (button == Pointer.Button.BUTTON_SCROLL_DOWN ? -MOUSE_WHEEL_DELTA : 0); winHandler.mouseEvent(MouseEventFlags.getFlagFor(button, true), 0, 0, wheelDelta); @@ -156,7 +154,7 @@ public class InputDeviceManager implements Pointer.OnPointerMotionListener, Keyb @Override public void onPointerButtonRelease(Pointer.Button button) { - if (xServer.cursorLocker.getState() == CursorLocker.State.LOCKED) { + if (xServer.isRelativeMouseMovement()) { WinHandler winHandler = xServer.getWinHandler(); winHandler.mouseEvent(MouseEventFlags.getFlagFor(button, false), 0, 0, 0); } diff --git a/app/src/main/java/com/winlator/xserver/Keyboard.java b/app/src/main/java/com/winlator/xserver/Keyboard.java index a021991..8016ab3 100644 --- a/app/src/main/java/com/winlator/xserver/Keyboard.java +++ b/app/src/main/java/com/winlator/xserver/Keyboard.java @@ -105,7 +105,7 @@ public class Keyboard { if (action == KeyEvent.ACTION_DOWN) { boolean shiftPressed = event.isShiftPressed() || keyCode == KeyEvent.KEYCODE_AT || keyCode == KeyEvent.KEYCODE_STAR || keyCode == KeyEvent.KEYCODE_POUND || keyCode == KeyEvent.KEYCODE_PLUS; if (shiftPressed) xServer.injectKeyPress(XKeycode.KEY_SHIFT_L); - xServer.injectKeyPress(xKeycode, event.getUnicodeChar()); + xServer.injectKeyPress(xKeycode, xKeycode != XKeycode.KEY_ENTER ? event.getUnicodeChar() : 0); } else if (action == KeyEvent.ACTION_UP) { xServer.injectKeyRelease(XKeycode.KEY_SHIFT_L); diff --git a/app/src/main/java/com/winlator/xserver/Pixmap.java b/app/src/main/java/com/winlator/xserver/Pixmap.java index ec7b0c6..36034e5 100644 --- a/app/src/main/java/com/winlator/xserver/Pixmap.java +++ b/app/src/main/java/com/winlator/xserver/Pixmap.java @@ -1,5 +1,9 @@ package com.winlator.xserver; +import android.graphics.Bitmap; + +import java.nio.ByteBuffer; + public class Pixmap extends XResource { public final Drawable drawable; @@ -7,4 +11,13 @@ public class Pixmap extends XResource { super(drawable.id); this.drawable = drawable; } + + public Bitmap toBitmap(Pixmap maskPixmap) { + ByteBuffer maskData = maskPixmap != null ? maskPixmap.drawable.getData() : null; + Bitmap bitmap = Bitmap.createBitmap(drawable.width, drawable.height, Bitmap.Config.ARGB_8888); + toBitmap(drawable.getData(), maskData, bitmap); + return bitmap; + } + + private static native void toBitmap(ByteBuffer colorData, ByteBuffer maskData, Bitmap bitmap); } diff --git a/app/src/main/java/com/winlator/xserver/PixmapManager.java b/app/src/main/java/com/winlator/xserver/PixmapManager.java index b3a0509..0f5a928 100644 --- a/app/src/main/java/com/winlator/xserver/PixmapManager.java +++ b/app/src/main/java/com/winlator/xserver/PixmapManager.java @@ -1,5 +1,6 @@ package com.winlator.xserver; +import android.graphics.Bitmap; import android.util.SparseArray; public class PixmapManager extends XResourceManager { @@ -51,4 +52,12 @@ public class PixmapManager extends XResourceManager { } return null; } + + public Bitmap getWindowIcon(Window window) { + int colorPixmapId = window.getWMHintsValue(Window.WMHints.ICON_PIXMAP); + int maskPixmapId = window.getWMHintsValue(Window.WMHints.ICON_MASK); + Pixmap colorPixmap = colorPixmapId != 0 ? getPixmap(colorPixmapId) : null; + Pixmap maskPixmap = maskPixmapId != 0 ? getPixmap(maskPixmapId) : null; + return colorPixmap != null ? colorPixmap.toBitmap(maskPixmap) : null; + } } diff --git a/app/src/main/java/com/winlator/xserver/Pointer.java b/app/src/main/java/com/winlator/xserver/Pointer.java index 7bf958d..e717b32 100644 --- a/app/src/main/java/com/winlator/xserver/Pointer.java +++ b/app/src/main/java/com/winlator/xserver/Pointer.java @@ -57,7 +57,7 @@ public class Pointer { return (short)Mathf.clamp(y, 0, xServer.screenInfo.height -1); } - public void moveTo(int x, int y) { + public void setPosition(int x, int y) { setX(x); setY(y); triggerOnPointerMove(this.x, this.y); diff --git a/app/src/main/java/com/winlator/xserver/Property.java b/app/src/main/java/com/winlator/xserver/Property.java index f14107b..49ee52f 100644 --- a/app/src/main/java/com/winlator/xserver/Property.java +++ b/app/src/main/java/com/winlator/xserver/Property.java @@ -31,7 +31,7 @@ public class Property { public final int name; public final int type; public final Format format; - private byte[] data; + public ByteBuffer data; public Property(int name, int type, Format format, byte[] data) { this.name = name; @@ -40,51 +40,60 @@ public class Property { replace(data); } - public byte[] data() { - return data; - } - public void replace(byte[] data) { - this.data = data != null ? data : new byte[0]; + this.data = ByteBuffer.wrap(data != null ? data : new byte[0]).order(ByteOrder.LITTLE_ENDIAN); } public void prepend(byte[] values) { - this.data = ArrayUtils.concat(values, this.data); + replace(ArrayUtils.concat(values, this.data.array())); } public void append(byte[] values) { - this.data = ArrayUtils.concat(this.data, values); + replace(ArrayUtils.concat(this.data.array(), values)); } @NonNull @Override public String toString() { String type = Atom.getName(this.type); + data.rewind(); switch (type) { case "UTF8_STRING": - return StringUtils.fromANSIString(data, StandardCharsets.UTF_8); + return StringUtils.fromANSIString(data.array(), StandardCharsets.UTF_8); case "STRING": - return StringUtils.fromANSIString(data, XServer.LATIN1_CHARSET); + return StringUtils.fromANSIString(data.array(), XServer.LATIN1_CHARSET); case "ATOM": - return Atom.getName(ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN).getInt()); + return Atom.getName(data.getInt(0)); default: StringBuilder sb = new StringBuilder(); - ByteBuffer buffer = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN); - for (int i = 0, size = data.length / (format.value >> 3); i < size; i++) { + for (int i = 0, size = data.capacity() / (format.value >> 3); i < size; i++) { if (i > 0) sb.append(","); switch (format) { case BYTE_ARRAY: - sb.append(buffer.get()); + sb.append(data.get()); break; case SHORT_ARRAY: - sb.append(buffer.getShort()); + sb.append(data.getShort()); break; case INT_ARRAY: - sb.append(buffer.getInt()); + sb.append(data.getInt()); break; } } + data.rewind(); return sb.toString(); } } + + public int getInt(int index) { + return data.getInt(index * 4); + } + + public long getLong(int index) { + return data.getLong(index * 8); + } + + public String nameAsString() { + return Atom.getName(name); + } } diff --git a/app/src/main/java/com/winlator/xserver/SHMSegmentManager.java b/app/src/main/java/com/winlator/xserver/SHMSegmentManager.java index 377288b..cbd5d51 100644 --- a/app/src/main/java/com/winlator/xserver/SHMSegmentManager.java +++ b/app/src/main/java/com/winlator/xserver/SHMSegmentManager.java @@ -3,8 +3,6 @@ package com.winlator.xserver; import android.util.SparseArray; import com.winlator.sysvshm.SysVSharedMemory; -import com.winlator.xserver.errors.BadAccess; -import com.winlator.xserver.errors.BadSHMSegment; import java.nio.ByteBuffer; @@ -16,18 +14,18 @@ public class SHMSegmentManager { this.sysVSharedMemory = sysVSharedMemory; } - public void attach(int xid, int shmid) throws BadAccess, BadSHMSegment { + public void attach(int xid, int shmid) { if (shmSegments.indexOfKey(xid) >= 0) detach(xid); ByteBuffer data = sysVSharedMemory.attach(shmid); - if (data == null) throw new BadAccess(); - shmSegments.put(xid, data); + if (data != null) shmSegments.put(xid, data); } - public void detach(int xid) throws BadSHMSegment { + public void detach(int xid) { ByteBuffer data = shmSegments.get(xid); - if (data == null) throw new BadSHMSegment(xid); - sysVSharedMemory.detach(data); - shmSegments.remove(xid); + if (data != null) { + sysVSharedMemory.detach(data); + shmSegments.remove(xid); + } } public ByteBuffer getData(int xid) { diff --git a/app/src/main/java/com/winlator/xserver/Window.java b/app/src/main/java/com/winlator/xserver/Window.java index 10b97a0..26eeeef 100644 --- a/app/src/main/java/com/winlator/xserver/Window.java +++ b/app/src/main/java/com/winlator/xserver/Window.java @@ -2,8 +2,6 @@ package com.winlator.xserver; import android.util.SparseArray; -import androidx.annotation.NonNull; - import com.winlator.xserver.events.Event; import com.winlator.xserver.events.PropertyNotify; @@ -22,6 +20,7 @@ public class Window extends XResource { public static final int FLAG_STACK_MODE = 1<<6; public enum StackMode {ABOVE, BELOW, TOP_IF, BOTTOM_IF, OPPOSITE} public enum MapState {UNMAPPED, UNVIEWABLE, VIEWABLE} + public enum WMHints {FLAGS, INPUT, INITIAL_STATE, ICON_PIXMAP, ICON_WINDOW, ICON_X, ICON_Y, ICON_MASK, WINDOW_GROUP} private Drawable content; private short x; private short y; @@ -106,12 +105,6 @@ public class Window extends XResource { return properties.get(id); } - @NonNull - public String getPropertyValue(String name) { - Property property = getProperty(Atom.getId(name)); - return property != null ? property.toString() : ""; - } - public void addProperty(Property property) { properties.put(property.name, property); } @@ -121,11 +114,11 @@ public class Window extends XResource { sendEvent(Event.PROPERTY_CHANGE, new PropertyNotify(this, id, true)); } - public boolean modifyProperty(int atom, int type, Property.Format format, Property.Mode mode, byte[] data) { + public Property modifyProperty(int atom, int type, Property.Format format, Property.Mode mode, byte[] data) { Property property = getProperty(atom); boolean modified = false; if (property == null) { - addProperty(new Property(atom, type, format, data)); + addProperty((property = new Property(atom, type, format, data))); modified = true; } else if (mode == Property.Mode.REPLACE) { @@ -145,16 +138,46 @@ public class Window extends XResource { modified = true; } - if (modified) sendEvent(Event.PROPERTY_CHANGE, new PropertyNotify(this, atom, false)); - return modified; + if (modified) { + sendEvent(Event.PROPERTY_CHANGE, new PropertyNotify(this, atom, false)); + return property; + } + else return null; } public String getName() { - return getPropertyValue("WM_NAME"); + Property property = getProperty(Atom.getId("WM_NAME")); + return property != null ? property.toString() : ""; } public String getClassName() { - return getPropertyValue("WM_CLASS"); + Property property = getProperty(Atom.getId("WM_CLASS")); + return property != null ? property.toString() : ""; + } + + public int getWMHintsValue(WMHints wmHints) { + Property property = getProperty(Atom.getId("WM_HINTS")); + return property != null ? property.getInt(wmHints.ordinal()) : 0; + } + + public int getProcessId() { + Property property = getProperty(Atom.getId("_NET_WM_PID")); + return property != null ? property.getInt(0) : 0; + } + + public boolean isWoW64() { + Property property = getProperty(Atom.getId("_NET_WM_WOW64")); + return property != null && property.data.get(0) == 1; + } + + public long getHandle() { + Property property = getProperty(Atom.getId("_NET_WM_HWND")); + return property != null ? property.getLong(0) : 0; + } + + public boolean isApplicationWindow() { + int windowGroup = getWMHintsValue(WMHints.WINDOW_GROUP); + return attributes.isMapped() && !getName().isEmpty() && windowGroup == id && width > 1 && height > 1; } public boolean isInputOutput() { @@ -382,4 +405,13 @@ public class Window extends XResource { stack.addAll(window.children); } } + + public String serializeProperties() { + String result = ""; + for (int i = 0; i < properties.size(); i++) { + Property property = properties.valueAt(i); + result += property.nameAsString()+"="+property+"\n"; + } + return result; + } } diff --git a/app/src/main/java/com/winlator/xserver/WindowManager.java b/app/src/main/java/com/winlator/xserver/WindowManager.java index 9c5effa..1bba1be 100644 --- a/app/src/main/java/com/winlator/xserver/WindowManager.java +++ b/app/src/main/java/com/winlator/xserver/WindowManager.java @@ -40,6 +40,8 @@ public class WindowManager extends XResourceManager { default void onUpdateWindowGeometry(Window window, boolean resized) {} default void onUpdateWindowAttributes(Window window, Bitmask mask) {} + + default void onModifyWindowProperty(Window window, Property property) {} } public WindowManager(ScreenInfo screenInfo, DrawableManager drawableManager) { @@ -55,6 +57,14 @@ public class WindowManager extends XResourceManager { return windows.get(id); } + public Window findWindowWithProcessId(int processId) { + for (int i = 0; i < windows.size(); i++) { + Window window = windows.valueAt(i); + if (window != null && window.getProcessId() == processId) return window; + } + return null; + } + public void destroyWindow(int id) { Window window = getWindow(id); if (window != null && rootWindow.id != id) { @@ -268,9 +278,8 @@ public class WindowManager extends XResourceManager { newParent.addChild(window); } - public Window findPointWindow(XServer xServer) { - Window pointWindow = findPointWindow(rootWindow, xServer.pointer.getClampedX(), xServer.pointer.getClampedY()); - return pointWindow != null ? pointWindow : rootWindow; + public Window findPointWindow(short rootX, short rootY) { + return findPointWindow(rootWindow, rootX, rootY); } private Window findPointWindow(Window window, short rootX, short rootY) { @@ -322,4 +331,10 @@ public class WindowManager extends XResourceManager { onWindowModificationListeners.get(i).onUpdateWindowAttributes(window, mask); } } + + public void triggerOnModifyWindowProperty(Window window, Property property) { + for (int i = onWindowModificationListeners.size()-1; i >= 0; i--) { + onWindowModificationListeners.get(i).onModifyWindowProperty(window, property); + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/winlator/xserver/XServer.java b/app/src/main/java/com/winlator/xserver/XServer.java index 13490e0..349d020 100644 --- a/app/src/main/java/com/winlator/xserver/XServer.java +++ b/app/src/main/java/com/winlator/xserver/XServer.java @@ -39,6 +39,7 @@ public class XServer { private GLRenderer renderer; private WinHandler winHandler; private final EnumMap locks = new EnumMap<>(Lockable.class); + private boolean relativeMouseMovement = false; public XServer(ScreenInfo screenInfo) { this.screenInfo = screenInfo; @@ -57,6 +58,15 @@ public class XServer { setupExtensions(); } + public boolean isRelativeMouseMovement() { + return relativeMouseMovement; + } + + public void setRelativeMouseMovement(boolean relativeMouseMovement) { + cursorLocker.setEnabled(!relativeMouseMovement); + this.relativeMouseMovement = relativeMouseMovement; + } + public GLRenderer getRenderer() { return renderer; } @@ -133,13 +143,13 @@ public class XServer { public void injectPointerMove(int x, int y) { try (XLock lock = lock(Lockable.WINDOW_MANAGER, Lockable.INPUT_DEVICE)) { - pointer.moveTo(x, y); + pointer.setPosition(x, y); } } public void injectPointerMoveDelta(int dx, int dy) { try (XLock lock = lock(Lockable.WINDOW_MANAGER, Lockable.INPUT_DEVICE)) { - pointer.moveTo(pointer.getX() + dx, pointer.getY() + dy); + pointer.setPosition(pointer.getX() + dx, pointer.getY() + dy); } } diff --git a/app/src/main/java/com/winlator/xserver/requests/GrabRequests.java b/app/src/main/java/com/winlator/xserver/requests/GrabRequests.java index a0b834d..8c444a7 100644 --- a/app/src/main/java/com/winlator/xserver/requests/GrabRequests.java +++ b/app/src/main/java/com/winlator/xserver/requests/GrabRequests.java @@ -18,7 +18,7 @@ public abstract class GrabRequests { private enum Status {SUCCESS, ALREADY_GRABBED, INVALID_TIME, NOT_VIEWABLE, FROZEN} public static void grabPointer(XClient client, XInputStream inputStream, XOutputStream outputStream) throws IOException, XRequestError { - if (client.xServer.cursorLocker.getState() == CursorLocker.State.LOCKED) { + if (client.xServer.isRelativeMouseMovement()) { client.skipRequest(); try (XStreamLock lock = outputStream.lock()) { outputStream.writeByte(RESPONSE_CODE_SUCCESS); diff --git a/app/src/main/java/com/winlator/xserver/requests/WindowRequests.java b/app/src/main/java/com/winlator/xserver/requests/WindowRequests.java index 6c1d808..3957313 100644 --- a/app/src/main/java/com/winlator/xserver/requests/WindowRequests.java +++ b/app/src/main/java/com/winlator/xserver/requests/WindowRequests.java @@ -159,7 +159,10 @@ public abstract class WindowRequests { inputStream.skip(-totalSize & 3); } - if (!window.modifyProperty(atom, type, Property.Format.valueOf(format), mode, data)) throw new BadMatch(); + Property property = window.modifyProperty(atom, type, Property.Format.valueOf(format), mode, data); + if (property == null) throw new BadMatch(); + + client.xServer.windowManager.triggerOnModifyWindowProperty(window, property); } public static void deleteProperty(XClient client, XInputStream inputStream, XOutputStream outputStream) throws XRequestError { @@ -205,7 +208,7 @@ public abstract class WindowRequests { outputStream.writePad(12); } else { - byte[] data = property.data(); + byte[] data = property.data.array(); int offset = longOffset * 4; int length = Math.min(data.length - offset, longLength * 4); if (length < 0) throw new BadValue(longOffset); @@ -240,7 +243,7 @@ public abstract class WindowRequests { try (XStreamLock lock = outputStream.lock()) { outputStream.writeByte(RESPONSE_CODE_SUCCESS); - outputStream.writeByte((byte)(client.xServer.cursorLocker.getState() != CursorLocker.State.LOCKED ? 1 : 0)); + outputStream.writeByte((byte)(!client.xServer.isRelativeMouseMovement() ? 1 : 0)); outputStream.writeShort(client.getSequenceNumber()); outputStream.writeInt(0); outputStream.writeInt(client.xServer.windowManager.rootWindow.id); @@ -283,7 +286,7 @@ public abstract class WindowRequests { } public static void warpPointer(XClient client, XInputStream inputStream, XOutputStream outputStream) throws IOException, XRequestError { - if (client.xServer.cursorLocker.getState() == CursorLocker.State.LOCKED) { + if (client.xServer.isRelativeMouseMovement()) { client.skipRequest(); return; } @@ -307,11 +310,13 @@ public abstract class WindowRequests { } if (dstWindow == null) { - client.xServer.pointer.moveTo(client.xServer.pointer.getX() + dstX, client.xServer.pointer.getY() + dstY); + client.xServer.pointer.setX(client.xServer.pointer.getX() + dstX); + client.xServer.pointer.setY(client.xServer.pointer.getY() + dstY); } else { short[] localPoint = dstWindow.localPointToRoot(dstX, dstY); - client.xServer.pointer.moveTo(localPoint[0], localPoint[1]); + client.xServer.pointer.setX(localPoint[0]); + client.xServer.pointer.setY(localPoint[1]); } } diff --git a/app/src/main/res/drawable-hdpi/icon_debug.png b/app/src/main/res/drawable-hdpi/icon_debug.png new file mode 100644 index 0000000..a9d72a6 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/icon_debug.png differ diff --git a/app/src/main/res/drawable-hdpi/icon_export.png b/app/src/main/res/drawable-hdpi/icon_export.png new file mode 100644 index 0000000..75bdf49 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/icon_export.png differ diff --git a/app/src/main/res/drawable-hdpi/icon_pause.png b/app/src/main/res/drawable-hdpi/icon_pause.png new file mode 100644 index 0000000..8a4c65e Binary files /dev/null and b/app/src/main/res/drawable-hdpi/icon_pause.png differ diff --git a/app/src/main/res/drawable-hdpi/icon_play.png b/app/src/main/res/drawable-hdpi/icon_play.png new file mode 100644 index 0000000..189c5fc Binary files /dev/null and b/app/src/main/res/drawable-hdpi/icon_play.png differ diff --git a/app/src/main/res/drawable-hdpi/icon_remove2.png b/app/src/main/res/drawable-hdpi/icon_remove2.png new file mode 100644 index 0000000..cf25b16 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/icon_remove2.png differ diff --git a/app/src/main/res/drawable-hdpi/icon_reset.png b/app/src/main/res/drawable-hdpi/icon_reset.png new file mode 100644 index 0000000..202301c Binary files /dev/null and b/app/src/main/res/drawable-hdpi/icon_reset.png differ diff --git a/app/src/main/res/drawable-hdpi/taskmgr_process.png b/app/src/main/res/drawable-hdpi/taskmgr_process.png new file mode 100644 index 0000000..c117a01 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/taskmgr_process.png differ diff --git a/app/src/main/res/drawable/element_left_box.xml b/app/src/main/res/drawable/element_left_box.xml new file mode 100644 index 0000000..f47991d --- /dev/null +++ b/app/src/main/res/drawable/element_left_box.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/element_right_box.xml b/app/src/main/res/drawable/element_right_box.xml new file mode 100644 index 0000000..0b56eaa --- /dev/null +++ b/app/src/main/res/drawable/element_right_box.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/add_env_var_dialog.xml b/app/src/main/res/layout/add_env_var_dialog.xml index 2318757..108e905 100644 --- a/app/src/main/res/layout/add_env_var_dialog.xml +++ b/app/src/main/res/layout/add_env_var_dialog.xml @@ -9,10 +9,23 @@ android:layout_height="wrap_content" android:text="@string/name" /> - + android:layout_height="wrap_content" + android:orientation="horizontal" + android:gravity="center_vertical"> + + + + + - - - - - - + android:id="@+id/SGraphicsDriver" + android:entries="@array/graphics_driver_entries" /> - - - - + android:visibility="gone"> + + + + + + + + + + + + + + + - - -