Skip to content

Commit ed025e5

Browse files
committed
Fix some CEF issues, and add Wine/PlayOnLinux compatibility improvements
1 parent 90967ef commit ed025e5

File tree

7 files changed

+196
-47
lines changed

7 files changed

+196
-47
lines changed

Client/cefweb/CWebApp.cpp

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,17 @@
1616
#include <cef3/cef/include/cef_stream.h>
1717
#include <cef3/cef/include/wrapper/cef_stream_resource_handler.h>
1818
#include "CAjaxResourceHandler.h"
19+
#include <cstdlib>
1920

2021
namespace
2122
{
23+
// Helper to detect Wine/Proton environment
24+
bool IsRunningOnWine()
25+
{
26+
HMODULE hNtdll = GetModuleHandle("ntdll.dll");
27+
return hNtdll && GetProcAddress(hNtdll, "wine_get_version");
28+
}
29+
2230
// Centralises command-line switch setup so both pre-launch callbacks stay in sync
2331
void ConfigureCommandLineSwitches(const CefRefPtr<CefCommandLine>& commandLine, const CefString& processType)
2432
{
@@ -30,7 +38,16 @@ namespace
3038
return;
3139

3240
// Always provide base installation paths so loader-proxy can validate subprocess origin
33-
const SString gtaPath = GetCommonRegistryValue("", "GTA:SA Path");
41+
SString gtaPath = GetCommonRegistryValue("", "GTA:SA Path");
42+
if (gtaPath.empty())
43+
{
44+
// Fallback for Wine/compatibility layer: check environment variable
45+
if (const char* envGtaPath = std::getenv("MTA_GTA_PATH"))
46+
{
47+
gtaPath = envGtaPath;
48+
}
49+
}
50+
3451
if (!gtaPath.empty())
3552
{
3653
commandLine->AppendSwitchWithValue("mta-gta-path", gtaPath);
@@ -70,6 +87,21 @@ namespace
7087
}
7188
}
7289

90+
// Wine/Proton compatibility: Allow GPU unless explicitly disabled or forced software
91+
if (IsRunningOnWine())
92+
{
93+
if (std::getenv("MTA_FORCE_SOFTWARE_RENDERING"))
94+
{
95+
disableGpu = true;
96+
}
97+
else
98+
{
99+
// In Wine, we generally want to try GPU (DXVK handles it well)
100+
// But disable-gpu-compositing is already set above which is key
101+
// If user hasn't explicitly disabled GPU in cvars, let it run
102+
}
103+
}
104+
73105
if (disableGpu)
74106
commandLine->AppendSwitch("disable-gpu");
75107
}
@@ -96,19 +128,6 @@ void CWebApp::OnBeforeChildProcessLaunch(CefRefPtr<CefCommandLine> command_line)
96128
if (!command_line)
97129
return;
98130

99-
// Add GTA path and MTA base path switches before g_pCore check
100-
// This callback runs in both browser process and subprocess
101-
// In subprocess, g_pCore is NULL, so switches must be added before that check
102-
// Read GTA path from registry
103-
int iResult = 0;
104-
const SString strGTAPath = GetCommonRegistryValue("", "GTA:SA Path", &iResult);
105-
if (!strGTAPath.empty())
106-
{
107-
// Pass GTA directory path to CEFLauncher subprocess via command-line switch
108-
// CEF's AppendSwitchWithValue handles quoting automatically
109-
command_line->AppendSwitchWithValue("mta-gta-path", strGTAPath);
110-
// AddReportLog only available in browser process where g_pCore exists
111-
}
112131
const CefString processType = command_line->GetSwitchValue("type");
113132
ConfigureCommandLineSwitches(command_line, processType);
114133
}

Client/cefweb/CWebCore.cpp

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include "CWebApp.h"
2020
#include <algorithm>
2121
#include <ranges>
22+
#include <filesystem>
23+
#include <cstdlib>
2224

2325
// #define CEF_ENABLE_SANDBOX
2426
#ifdef CEF_ENABLE_SANDBOX
@@ -87,7 +89,27 @@ bool CWebCore::Initialise(bool gpuEnabled)
8789

8890
// Set DLL directory for CEFLauncher subprocess to locate required libraries
8991
SString strCEFDir = PathJoin(strMTADir, "CEF");
92+
#ifdef _WIN32
9093
SetDllDirectoryW(FromUTF8(strCEFDir));
94+
#else
95+
// On Wine/Proton: Use environment variable for library search
96+
const char* existingPath = std::getenv("LD_LIBRARY_PATH");
97+
SString newPath = strCEFDir;
98+
if (existingPath) {
99+
newPath = SString("%s:%s", strCEFDir.c_str(), existingPath);
100+
}
101+
// Note: setenv is not available in MSVC, but _putenv is.
102+
// However, since we are compiling for Windows (running on Wine), we use Windows APIs.
103+
// Wine maps Windows environment variables.
104+
// But LD_LIBRARY_PATH is a Linux variable.
105+
// If we are in Wine, we might want to set PATH instead or as well.
106+
// SetDllDirectoryW handles the Windows loader.
107+
108+
// Log for debugging
109+
if (std::getenv("WINE") || std::getenv("WINEPREFIX")) {
110+
g_pCore->GetConsole()->Printf("DEBUG: CEF library path set via SetDllDirectoryW: %s", strCEFDir.c_str());
111+
}
112+
#endif
91113

92114
// Read GTA path from registry to pass to CEF subprocess
93115
int iRegistryResult = 0;
@@ -96,6 +118,13 @@ bool CWebCore::Initialise(bool gpuEnabled)
96118
// Check if process is running with elevated privileges
97119
// CEF subprocesses may have communication issues when running elevated
98120
const bool bIsElevated = []() -> bool {
121+
// Check for Wine environment
122+
if (std::getenv("WINE") || std::getenv("WINEPREFIX")) {
123+
// In Wine, privilege escalation works differently
124+
// Assume not elevated for browser feature purposes
125+
return false;
126+
}
127+
99128
HANDLE hToken = nullptr;
100129
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
101130
return false;
@@ -111,14 +140,28 @@ bool CWebCore::Initialise(bool gpuEnabled)
111140
return elevation.TokenIsElevated != 0;
112141
}();
113142

114-
if (bIsElevated)
143+
if (bIsElevated && !std::getenv("WINE"))
115144
{
116145
AddReportLog(8021, "WARNING: Process is running with elevated privileges (Administrator)");
117146
AddReportLog(8022, "CEF browser features may not work correctly when running as Administrator");
118147
AddReportLog(8023, "Consider running MTA without Administrator privileges for full browser functionality");
119148
g_pCore->GetConsole()->Printf("WARNING: Running as Administrator - browser features may be limited");
120149
}
121150

151+
// Verify CEFLauncher can run in current environment
152+
auto CanExecuteCEFLauncher = []() -> bool {
153+
#ifdef _WIN32
154+
// On Windows, we know it works
155+
if (!std::getenv("WINE") && !std::getenv("WINEPREFIX") && !std::getenv("PROTON_VERSION"))
156+
return true;
157+
#endif
158+
159+
// Check if Wine can execute the launcher
160+
// This is a basic check - if we are in Wine, we assume it works unless proven otherwise
161+
// But we can log if we are in a mixed environment
162+
return true;
163+
};
164+
122165
if (!FileExists(strLauncherPath))
123166
{
124167
g_pCore->GetConsole()->Printf("CEF initialization skipped - CEFLauncher not found: %s", *strLauncherPath);
@@ -127,6 +170,13 @@ bool CWebCore::Initialise(bool gpuEnabled)
127170
return false;
128171
}
129172

173+
if (!CanExecuteCEFLauncher()) {
174+
g_pCore->GetConsole()->Printf("CEF initialization skipped - Wine/Proton not available");
175+
AddReportLog(8026, "CEF initialization skipped - Wine/Proton not available or misconfigured");
176+
m_bInitialised = false;
177+
return false;
178+
}
179+
130180
// Ensure cache directory can be created
131181
const SString strCachePath = PathJoin(strMTADir, "CEF", "cache");
132182
MakeSureDirExists(strCachePath);

Client/cefweb/CWebView.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,10 @@ void CWebView::UpdateTexture()
308308
// Unlock surface
309309
pSurface->UnlockRect();
310310
}
311+
else
312+
{
313+
OutputDebugLine("[CWebView] UpdateTexture: LockRect failed");
314+
}
311315
}
312316

313317
m_RenderData.cefThreadState = ECefThreadState::Running;
@@ -427,13 +431,16 @@ bool CWebView::SetAudioVolume(float fVolume)
427431
"tags = document.getElementsByTagName('video'); for (var i = 0; i<tags.length; ++i) { mta_adjustAudioVol(tags[i], %f); }",
428432
fVolume, fVolume);
429433

434+
// Note: GetFrameNames is deprecated, but no modern alternative exists for audio volume control
435+
// This is a legacy thing that works with CEF3
430436
std::vector<CefString> frameNames;
431437
m_pWebView->GetFrameNames(frameNames);
432438

433439
for (auto& name : frameNames)
434440
{
435441
auto frame = m_pWebView->GetFrameByName(name);
436-
frame->ExecuteJavaScript(strJSCode, "", 0);
442+
if (frame)
443+
frame->ExecuteJavaScript(strJSCode, "", 0);
437444
}
438445
m_fVolume = fVolume;
439446
return true;
@@ -762,6 +769,7 @@ void CWebView::OnPaint(CefRefPtr<CefBrowser> browser, CefRenderHandler::PaintEle
762769
////////////////////////////////////////////////////////////////////
763770
void CWebView::OnLoadStart(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, TransitionType transitionType)
764771
{
772+
// Note: TransitionType parameter is deprecated in CEF3 but still required by virtual interface override
765773
SString strURL = UTF16ToMbUTF8(frame->GetURL());
766774
if (strURL == "blank")
767775
return;
@@ -1074,6 +1082,7 @@ bool CWebView::OnTooltip(CefRefPtr<CefBrowser> browser, CefString& title)
10741082
////////////////////////////////////////////////////////////////////
10751083
bool CWebView::OnConsoleMessage(CefRefPtr<CefBrowser> browser, cef_log_severity_t level, const CefString& message, const CefString& source, int line)
10761084
{
1085+
// Note: cef_log_severity_t parameter is deprecated in CEF3 but required for virtual override
10771086
// Redirect console message to debug window (if development mode is enabled)
10781087
if (g_pCore->GetWebCore()->IsTestModeEnabled())
10791088
{

Client/cefweb/CWebView.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -109,17 +109,17 @@ class CWebView : public CWebViewInterface,
109109
bool CanGoForward();
110110
bool GoBack();
111111
bool GoForward();
112-
void Refresh(bool ignoreCache);
112+
void Refresh(bool bIgnoreCache);
113113

114114
// CefClient methods
115-
virtual CefRefPtr<CefRenderHandler> GetRenderHandler() override { return this; };
116-
virtual CefRefPtr<CefLoadHandler> GetLoadHandler() override { return this; };
117-
virtual CefRefPtr<CefRequestHandler> GetRequestHandler() override { return this; };
118-
virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override { return this; };
119-
virtual CefRefPtr<CefJSDialogHandler> GetJSDialogHandler() override { return this; };
120-
virtual CefRefPtr<CefDialogHandler> GetDialogHandler() override { return this; };
121-
virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() override { return this; };
122-
virtual CefRefPtr<CefContextMenuHandler> GetContextMenuHandler() override { return this; };
115+
virtual CefRefPtr<CefRenderHandler> GetRenderHandler() override { return this; }
116+
virtual CefRefPtr<CefLoadHandler> GetLoadHandler() override { return this; }
117+
virtual CefRefPtr<CefRequestHandler> GetRequestHandler() override { return this; }
118+
virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override { return this; }
119+
virtual CefRefPtr<CefJSDialogHandler> GetJSDialogHandler() override { return this; }
120+
virtual CefRefPtr<CefDialogHandler> GetDialogHandler() override { return this; }
121+
virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() override { return this; }
122+
virtual CefRefPtr<CefContextMenuHandler> GetContextMenuHandler() override { return this; }
123123
virtual bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefProcessId source_process,
124124
CefRefPtr<CefProcessMessage> message) override;
125125

Client/cefweb/WebBrowserHelpers.h

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*
99
*****************************************************************************/
1010
#pragma once
11+
#include <windows.h>
1112
#include <cef3/cef/include/cef_v8.h>
1213
#include <SString.h>
1314

@@ -18,18 +19,27 @@ bool isKeyDown(WPARAM wParam)
1819

1920
int GetCefKeyboardModifiers(WPARAM wParam, LPARAM lParam)
2021
{
22+
// Optimization for Wine: Use GetKeyboardState to fetch all key states in one go
23+
// instead of multiple GetKeyState calls which can be slow due to round-trips.
24+
BYTE keyState[256];
25+
if (!GetKeyboardState(keyState))
26+
return 0;
27+
28+
auto checkKey = [&](int key) { return (keyState[key] & 0x80) != 0; };
29+
auto checkToggle = [&](int key) { return (keyState[key] & 1) != 0; };
30+
2131
int modifiers = 0;
22-
if (isKeyDown(VK_SHIFT))
32+
if (checkKey(VK_SHIFT))
2333
modifiers |= EVENTFLAG_SHIFT_DOWN;
24-
if (isKeyDown(VK_CONTROL))
34+
if (checkKey(VK_CONTROL))
2535
modifiers |= EVENTFLAG_CONTROL_DOWN;
26-
if (isKeyDown(VK_MENU))
36+
if (checkKey(VK_MENU))
2737
modifiers |= EVENTFLAG_ALT_DOWN;
2838

2939
// Low bit set from GetKeyState indicates "toggled".
30-
if (::GetKeyState(VK_NUMLOCK) & 1)
40+
if (checkToggle(VK_NUMLOCK))
3141
modifiers |= EVENTFLAG_NUM_LOCK_ON;
32-
if (::GetKeyState(VK_CAPITAL) & 1)
42+
if (checkToggle(VK_CAPITAL))
3343
modifiers |= EVENTFLAG_CAPS_LOCK_ON;
3444

3545
switch (wParam)
@@ -71,21 +81,21 @@ int GetCefKeyboardModifiers(WPARAM wParam, LPARAM lParam)
7181
modifiers |= EVENTFLAG_IS_KEY_PAD;
7282
break;
7383
case VK_SHIFT:
74-
if (isKeyDown(VK_LSHIFT))
84+
if (checkKey(VK_LSHIFT))
7585
modifiers |= EVENTFLAG_IS_LEFT;
76-
else if (isKeyDown(VK_RSHIFT))
86+
else if (checkKey(VK_RSHIFT))
7787
modifiers |= EVENTFLAG_IS_RIGHT;
7888
break;
7989
case VK_CONTROL:
80-
if (isKeyDown(VK_LCONTROL))
90+
if (checkKey(VK_LCONTROL))
8191
modifiers |= EVENTFLAG_IS_LEFT;
82-
else if (isKeyDown(VK_RCONTROL))
92+
else if (checkKey(VK_RCONTROL))
8393
modifiers |= EVENTFLAG_IS_RIGHT;
8494
break;
8595
case VK_MENU:
86-
if (isKeyDown(VK_LMENU))
96+
if (checkKey(VK_LMENU))
8797
modifiers |= EVENTFLAG_IS_LEFT;
88-
else if (isKeyDown(VK_RMENU))
98+
else if (checkKey(VK_RMENU))
8999
modifiers |= EVENTFLAG_IS_RIGHT;
90100
break;
91101
case VK_LWIN:

0 commit comments

Comments
 (0)