diff --git a/Makefile.common b/Makefile.common index 2d5748f8de07..c6376e74f7cf 100644 --- a/Makefile.common +++ b/Makefile.common @@ -1281,6 +1281,7 @@ endif ifeq ($(HAVE_WAYLAND), 1) OBJ += gfx/drivers_context/wayland_ctx.o \ + gfx/display_servers/dispserv_wl.o \ input/common/wayland_common.o \ input/drivers/wayland_input.o \ gfx/common/wayland_common.o \ @@ -2460,34 +2461,10 @@ ifeq ($(HAVE_NETWORKING), 1) endif ifeq ($(HAVE_DISCORD), 1) - NEED_CXX_LINKER = 1 HAVE_PRESENCE = 1 DEFINES += -DHAVE_DISCORD - INCLUDE_DIRS += -Ideps/discord-rpc/include - - ifneq ($(HAVE_THREADS), 1) - DEFINES += -DDISCORD_DISABLE_IO_THREAD - endif - - OBJ += deps/discord-rpc/src/discord_rpc.o \ - deps/discord-rpc/src/rpc_connection.o \ - deps/discord-rpc/src/serialization.o OBJ += network/discord.o - - ifneq ($(findstring Win32,$(OS)),) - OBJ += deps/discord-rpc/src/discord_register_win.o \ - deps/discord-rpc/src/connection_win.o - LIBS += -lpsapi -ladvapi32 - endif - ifneq ($(findstring Linux,$(OS)),) - OBJ += deps/discord-rpc/src/discord_register_linux.o \ - deps/discord-rpc/src/connection_unix.o - endif - ifneq ($(findstring Darwin,$(OS)),) - OBJ += deps/discord-rpc/src/discord_register_osx.o \ - deps/discord-rpc/src/connection_unix.o - endif endif ifeq ($(HAVE_TRANSLATE), 1) diff --git a/deps/discord-rpc/LICENSE b/deps/discord-rpc/LICENSE deleted file mode 100644 index 17fca3d50f9f..000000000000 --- a/deps/discord-rpc/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright 2017 Discord, Inc. - -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. diff --git a/deps/discord-rpc/include/discord_register.h b/deps/discord-rpc/include/discord_register.h deleted file mode 100644 index 53750b236817..000000000000 --- a/deps/discord-rpc/include/discord_register.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -#if defined(__cplusplus) && !defined(CXX_BUILD) -extern "C" { -#endif - -int get_process_id(void); -void Discord_Register(const char* applicationId, const char* command); -void Discord_RegisterSteamGame(const char* applicationId, const char* steamId); - -#if defined(__cplusplus) && !defined(CXX_BUILD) -} -#endif diff --git a/deps/discord-rpc/include/discord_rpc.h b/deps/discord-rpc/include/discord_rpc.h deleted file mode 100644 index cc23e30828d3..000000000000 --- a/deps/discord-rpc/include/discord_rpc.h +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct DiscordRichPresence -{ - const char* state; /* max 128 bytes */ - const char* details; /* max 128 bytes */ - int64_t startTimestamp; - int64_t endTimestamp; - const char* largeImageKey; /* max 32 bytes */ - const char* largeImageText; /* max 128 bytes */ - const char* smallImageKey; /* max 32 bytes */ - const char* smallImageText; /* max 128 bytes */ - const char* partyId; /* max 128 bytes */ - int partySize; - int partyMax; - const char* matchSecret; /* max 128 bytes */ - const char* joinSecret; /* max 128 bytes */ - const char* spectateSecret; /* max 128 bytes */ - int8_t instance; -} DiscordRichPresence; - -typedef struct DiscordUser -{ - const char* userId; - const char* username; - const char* discriminator; - const char* avatar; -} DiscordUser; - -typedef struct DiscordEventHandlers -{ - void (*ready)(const DiscordUser* request); - void (*disconnected)(int errorCode, const char* message); - void (*errored)(int errorCode, const char* message); - void (*joinGame)(const char* joinSecret); - void (*spectateGame)(const char* spectateSecret); - void (*joinRequest)(const DiscordUser* request); -} DiscordEventHandlers; - -#define DISCORD_REPLY_NO 0 -#define DISCORD_REPLY_YES 1 -#define DISCORD_REPLY_IGNORE 2 - -void Discord_Initialize(const char* applicationId, - DiscordEventHandlers* handlers, - int autoRegister, - const char* optionalSteamId); -void Discord_Shutdown(void); - -/* checks for incoming messages, dispatches callbacks */ -void Discord_RunCallbacks(void); - -/* If you disable the lib starting its own I/O thread, - * you'll need to call this from your own */ -#ifdef DISCORD_DISABLE_IO_THREAD -void Discord_UpdateConnection(void); -#endif - -void Discord_UpdatePresence(const DiscordRichPresence* presence); -void Discord_ClearPresence(void); - -void Discord_Respond(const char* userid, - /* DISCORD_REPLY_ */ int reply); - -void Discord_UpdateHandlers(DiscordEventHandlers* handlers); - -#ifdef __cplusplus -} /* extern "C" */ -#endif diff --git a/deps/discord-rpc/src/backoff.h b/deps/discord-rpc/src/backoff.h deleted file mode 100644 index 0b2a55916095..000000000000 --- a/deps/discord-rpc/src/backoff.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -struct Backoff -{ - int64_t minAmount; - int64_t maxAmount; - int64_t current; - std::mt19937_64 randGenerator; - std::uniform_real_distribution<> randDistribution; - - Backoff(int64_t min, int64_t max) - : minAmount(min) - , maxAmount(max) - , current(min) - , randGenerator((uint64_t)time(0)) - { - } - - void reset() - { - current = minAmount; - } - - int64_t nextDelay() - { - int64_t delay = (int64_t)((double)current * 2.0 * - randDistribution(randGenerator)); - current = std::min(current + delay, maxAmount); - return current; - } -}; diff --git a/deps/discord-rpc/src/connection.h b/deps/discord-rpc/src/connection.h deleted file mode 100644 index befcbcec7c80..000000000000 --- a/deps/discord-rpc/src/connection.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -/* This is to wrap the platform specific kinds of connect/read/write. */ - -#include -#include - -struct BaseConnection -{ - static BaseConnection* Create(); - static void Destroy(BaseConnection*&); - bool isOpen{false}; - bool Open(); - bool Close(); - bool Write(const void* data, size_t length); - bool Read(void* data, size_t length); -}; diff --git a/deps/discord-rpc/src/connection_unix.cpp b/deps/discord-rpc/src/connection_unix.cpp deleted file mode 100644 index 67fa5083d8cf..000000000000 --- a/deps/discord-rpc/src/connection_unix.cpp +++ /dev/null @@ -1,130 +0,0 @@ -#include "connection.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(OSX) -extern "C" void CFTemporaryDirectory(char *s, size_t len); -#endif - -struct BaseConnectionUnix : public BaseConnection { - int sock{-1}; -}; - -static BaseConnectionUnix ConnectionUnix; -static sockaddr_un PipeAddr{}; -#ifdef MSG_NOSIGNAL -static int MsgFlags = MSG_NOSIGNAL; -#else -static int MsgFlags = 0; -#endif - -static const char* GetTempPath(void) -{ -#if defined(OSX) - static char temp[1024]; - CFTemporaryDirectory(temp, 1024); - return temp; -#else - const char* temp = getenv("XDG_RUNTIME_DIR"); - temp = temp ? temp : getenv("TMPDIR"); - temp = temp ? temp : getenv("TMP"); - temp = temp ? temp : getenv("TEMP"); - temp = temp ? temp : "/tmp"; - return temp; -#endif -} - -/*static*/ BaseConnection* BaseConnection::Create() -{ - PipeAddr.sun_family = AF_UNIX; - return &ConnectionUnix; -} - -/*static*/ void BaseConnection::Destroy(BaseConnection*& c) -{ - auto self = reinterpret_cast(c); - self->Close(); - c = nullptr; -} - -bool BaseConnection::Open() -{ -#ifdef SO_NOSIGPIPE - int optval = 1; -#endif - const char* tempPath = GetTempPath(); - auto self = reinterpret_cast(this); - - self->sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (self->sock == -1) - return false; - fcntl(self->sock, F_SETFL, O_NONBLOCK); - -#ifdef SO_NOSIGPIPE - setsockopt(self->sock, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)); -#endif - - for (int pipeNum = 0; pipeNum < 10; ++pipeNum) - { - snprintf( - PipeAddr.sun_path, sizeof(PipeAddr.sun_path), "%s/discord-ipc-%d", tempPath, pipeNum); - int err = connect(self->sock, (const sockaddr*)&PipeAddr, sizeof(PipeAddr)); - if (err == 0) - { - self->isOpen = true; - return true; - } - } - self->Close(); - return false; -} - -bool BaseConnection::Close() -{ - auto self = reinterpret_cast(this); - if (self->sock == -1) - return false; - close(self->sock); - self->sock = -1; - self->isOpen = false; - return true; -} - -bool BaseConnection::Write(const void* data, size_t length) -{ - ssize_t sentBytes; - auto self = reinterpret_cast(this); - - if (self->sock == -1) - return false; - - sentBytes = send(self->sock, data, length, MsgFlags); - if (sentBytes < 0) - Close(); - return sentBytes == (ssize_t)length; -} - -bool BaseConnection::Read(void* data, size_t length) -{ - int res; - auto self = reinterpret_cast(this); - - if (self->sock == -1) - return false; - - res = (int)recv(self->sock, data, length, MsgFlags); - if (res < 0) - { - if (errno == EAGAIN) - return false; - Close(); - } - return res == (int)length; -} diff --git a/deps/discord-rpc/src/connection_win.cpp b/deps/discord-rpc/src/connection_win.cpp deleted file mode 100644 index 63adf999338e..000000000000 --- a/deps/discord-rpc/src/connection_win.cpp +++ /dev/null @@ -1,119 +0,0 @@ -#include "connection.h" - -#define WIN32_LEAN_AND_MEAN -#define NOMCX -#define NOSERVICE -#define NOIME -#include - -struct BaseConnectionWin : public BaseConnection -{ - HANDLE pipe{INVALID_HANDLE_VALUE}; -}; - -static BaseConnectionWin Connection; - -/*static*/ BaseConnection* BaseConnection::Create() -{ - return &Connection; -} - -/*static*/ void BaseConnection::Destroy(BaseConnection*& c) -{ - auto self = reinterpret_cast(c); - self->Close(); - c = nullptr; -} - -bool BaseConnection::Open() -{ - wchar_t pipeName[]{L"\\\\?\\pipe\\discord-ipc-0"}; - const size_t pipeDigit = sizeof(pipeName) / sizeof(wchar_t) - 2; - pipeName[pipeDigit] = L'0'; - auto self = reinterpret_cast(this); - for (;;) - { - self->pipe = ::CreateFileW( - pipeName, GENERIC_READ | GENERIC_WRITE, 0, - nullptr, OPEN_EXISTING, 0, nullptr); - if (self->pipe != INVALID_HANDLE_VALUE) - { - self->isOpen = true; - return true; - } - - DWORD lastError = GetLastError(); - if (lastError == ERROR_FILE_NOT_FOUND) - { - if (pipeName[pipeDigit] < L'9') - { - pipeName[pipeDigit]++; - continue; - } - } - else if (lastError == ERROR_PIPE_BUSY) - { - if (!WaitNamedPipeW(pipeName, 10000)) - return false; - continue; - } - return false; - } -} - -bool BaseConnection::Close() -{ - auto self = reinterpret_cast(this); - ::CloseHandle(self->pipe); - self->pipe = INVALID_HANDLE_VALUE; - self->isOpen = false; - return true; -} - -bool BaseConnection::Write(const void* data, size_t length) -{ - DWORD bytesWritten = 0; - const DWORD bytesLength = (DWORD)length; - if (length == 0) - return true; - auto self = reinterpret_cast(this); - if (!self) - return false; - if (self->pipe == INVALID_HANDLE_VALUE) - return false; - if (!data) - return false; - return ::WriteFile(self->pipe, data, bytesLength, - &bytesWritten, nullptr) == TRUE && - bytesWritten == bytesLength; -} - -bool BaseConnection::Read(void* data, size_t length) -{ - DWORD bytesAvailable = 0; - if (!data) - return false; - auto self = reinterpret_cast(this); - if (!self) - return false; - if (self->pipe == INVALID_HANDLE_VALUE) - return false; - - if (::PeekNamedPipe(self->pipe, nullptr, 0, nullptr, - &bytesAvailable, nullptr)) - { - if (bytesAvailable >= length) - { - DWORD bytesToRead = (DWORD)length; - DWORD bytesRead = 0; - if (::ReadFile(self->pipe, data, bytesToRead, - &bytesRead, nullptr) == TRUE) - return true; - - Close(); - } - } - else - Close(); - return false; -} diff --git a/deps/discord-rpc/src/discord_register_linux.c b/deps/discord-rpc/src/discord_register_linux.c deleted file mode 100644 index dbb52a512e9d..000000000000 --- a/deps/discord-rpc/src/discord_register_linux.c +++ /dev/null @@ -1,118 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -int get_process_id(void) -{ - return getpid(); -} - -/* we want to register games so we can run them from - * Discord client as discord-:// */ -void Discord_Register(const char *applicationId, const char *command) -{ - size_t _len; - FILE* fp; - int fileLen; - char xdgMimeCommand[1024]; - char desktopFilename[256]; - char desktopFilePath[1024]; - char desktopFile[2048]; - /* Add a desktop file and update some MIME handlers - * so that xdg-open does the right thing. */ - char exePath[1024]; - const char* home = getenv("HOME"); - if (!home) - return; - - if (!command || !command[0]) - { - ssize_t size = readlink("/proc/self/exe", exePath, sizeof(exePath)); - if (size <= 0 || size >= (ssize_t)sizeof(exePath)) - return; - exePath[size] = '\0'; - command = exePath; - } - - { - const char* desktopFileFormat = "[Desktop Entry]\n" - "Name=Game %s\n" - "Exec=%s\n" /* note: it really wants that %u in there */ - "Type=Application\n" - "NoDisplay=true\n" - "Categories=Discord;Games;\n" - "MimeType=x-scheme-handler/discord-%s;\n"; - fileLen = snprintf( - desktopFile, sizeof(desktopFile), desktopFileFormat, applicationId, command, applicationId); - if (fileLen <= 0) - return; - } - - _len = strlcpy(desktopFilename, - "/discord-", - sizeof(desktopFilename)); - _len += strlcpy(desktopFilename + _len, - applicationId, - sizeof(desktopFilename) - _len); - _len += strlcpy(desktopFilename + _len, - ".desktop", - sizeof(desktopFilename) - _len); - - _len = strlcpy(desktopFilePath, - home, - sizeof(desktopFilePath)); - _len += strlcpy(desktopFilePath + _len, - "/.local", - sizeof(desktopFilePath) - _len); - if (!path_mkdir(desktopFilePath)) - return; - _len += strlcpy(desktopFilePath + _len, - "/share", - sizeof(desktopFilePath) - _len); - if (!path_mkdir(desktopFilePath)) - return; - _len += strlcpy(desktopFilePath + _len, - "/applications", - sizeof(desktopFilePath) - _len); - if (!path_mkdir(desktopFilePath)) - return; - _len += strlcpy(desktopFilePath + _len, - desktopFilename, - sizeof(desktopFilePath) - _len); - - if (!(fp = fopen(desktopFilePath, "w"))) - return; - - fwrite(desktopFile, 1, fileLen, fp); - fclose(fp); - - snprintf(xdgMimeCommand, - sizeof(xdgMimeCommand), - "xdg-mime default discord-%s.desktop x-scheme-handler/discord-%s", - applicationId, - applicationId); - if (system(xdgMimeCommand) < 0) - fprintf(stderr, "Failed to register mime handler\n"); -} - -void Discord_RegisterSteamGame(const char *applicationId, const char *steamId) -{ - char command[256]; - size_t _len = strlcpy(command, "xdg-open steam://rungameid/", sizeof(command)); - strlcpy(command + _len, steamId, sizeof(command) - _len); - Discord_Register(applicationId, command); -} diff --git a/deps/discord-rpc/src/discord_register_osx.m b/deps/discord-rpc/src/discord_register_osx.m deleted file mode 100644 index 7a87044d07f0..000000000000 --- a/deps/discord-rpc/src/discord_register_osx.m +++ /dev/null @@ -1,85 +0,0 @@ -#include -#include - -#import - -int get_process_id(void) -{ - return getpid(); -} - -static void RegisterCommand(const char* applicationId, const char* command) -{ - /* There does not appear to be a way to register arbitrary commands on OSX, so instead we'll save the command - * to a file in the Discord config path, and when it is needed, Discord can try to load the file there, open - * the command therein (will pass to js's window.open, so requires a url-like thing) - */ - - /* Note: will not work for sandboxed apps */ - NSString *home = NSHomeDirectory(); - if (!home) - return; - - NSString *path = [[[[[[home stringByAppendingPathComponent:@"Library"] - stringByAppendingPathComponent:@"Application Support"] - stringByAppendingPathComponent:@"discord"] - stringByAppendingPathComponent:@"games"] - stringByAppendingPathComponent:[NSString stringWithUTF8String:applicationId]] - stringByAppendingPathExtension:@"json"]; - [[NSFileManager defaultManager] createDirectoryAtPath:[path stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil]; - - NSString *jsonBuffer = [NSString stringWithFormat:@"{\"command\": \"%s\"}", command]; - [jsonBuffer writeToFile:path atomically:NO encoding:NSUTF8StringEncoding error:nil]; -} - -static void RegisterURL(const char* applicationId) -{ - char url[256]; - snprintf(url, sizeof(url), "discord-%s", applicationId); - CFStringRef cfURL = CFStringCreateWithCString(NULL, url, kCFStringEncodingUTF8); - NSString* myBundleId = [[NSBundle mainBundle] bundleIdentifier]; - - if (!myBundleId) - { - fprintf(stderr, "No bundle id found\n"); - return; - } - - NSURL* myURL = [[NSBundle mainBundle] bundleURL]; - if (!myURL) - { - fprintf(stderr, "No bundle url found\n"); - return; - } - - OSStatus status = LSSetDefaultHandlerForURLScheme(cfURL, (__bridge CFStringRef)myBundleId); - if (status != noErr) - { - fprintf(stderr, "Error in LSSetDefaultHandlerForURLScheme: %d\n", (int)status); - return; - } - - status = LSRegisterURL((__bridge CFURLRef)myURL, true); - if (status != noErr) - fprintf(stderr, "Error in LSRegisterURL: %d\n", (int)status); -} - -void Discord_Register(const char* applicationId, const char* command) -{ - if (command) - RegisterCommand(applicationId, command); - else - { - /* RAII Lite */ - @autoreleasepool { - RegisterURL(applicationId); - } - } -} - -void Discord_RegisterSteamGame(const char* applicationId, const char* steamId) -{ - char command[256]; - snprintf(command, sizeof(command), "steam://rungameid/%s", steamId); - Discord_Register(applicationId, command); -} diff --git a/deps/discord-rpc/src/discord_register_win.c b/deps/discord-rpc/src/discord_register_win.c deleted file mode 100644 index 345b74c51e6a..000000000000 --- a/deps/discord-rpc/src/discord_register_win.c +++ /dev/null @@ -1,195 +0,0 @@ -#include "discord_rpc.h" - -#define WIN32_LEAN_AND_MEAN -#define NOMCX -#define NOSERVICE -#define NOIME -#include -#include -#include -#include - -int get_process_id(void) -{ - return (int)GetCurrentProcessId(); -} - -/** - * Updated fixes for MinGW and WinXP - * This block is written the way it does not involve changing the rest of the code - * Checked to be compiling - * 1) strsafe.h belongs to Windows SDK and cannot be added to MinGW - * #include guarded, functions redirected to substitutes - * 2) RegSetKeyValueW and LSTATUS are not declared in - * The entire function is rewritten - */ -#ifdef __MINGW32__ -/* strsafe.h fixes */ -static HRESULT StringCbPrintfW(LPWSTR pszDest, - size_t cbDest, LPCWSTR pszFormat, ...) -{ - HRESULT ret; - va_list va; - va_start(va, pszFormat); - cbDest /= 2; /* Size is divided by 2 to convert from bytes to wide characters - causes segfault */ - /* othervise */ - ret = vsnwprintf(pszDest, cbDest, pszFormat, va); - pszDest[cbDest - 1] = 0; /* Terminate the string in case a buffer overflow; -1 will be returned */ - va_end(va); - return ret; -} -#else -#include -#endif /* __MINGW32__ */ - -/* winreg.h fixes */ -#ifndef LSTATUS -#define LSTATUS LONG -#endif -#ifdef RegSetKeyValueW -#undefine RegSetKeyValueW -#endif -#define RegSetKeyValueW regset -static LSTATUS regset(HKEY hkey, - LPCWSTR subkey, - LPCWSTR name, - DWORD type, - const void* data, - DWORD len) -{ - LSTATUS ret; - HKEY htkey = hkey, hsubkey = NULL; - if (subkey && subkey[0]) - { - if ((ret = RegCreateKeyExW(hkey, subkey, 0, 0, 0, KEY_ALL_ACCESS, 0, &hsubkey, 0)) != - ERROR_SUCCESS) - return ret; - htkey = hsubkey; - } - ret = RegSetValueExW(htkey, name, 0, type, (const BYTE*)data, len); - if (hsubkey && hsubkey != hkey) - RegCloseKey(hsubkey); - return ret; -} - -static void Discord_RegisterW( - const wchar_t* applicationId, const wchar_t* command) -{ - /* https://msdn.microsoft.com/en-us/library/aa767914(v=vs.85).aspx - * we want to register games so we can run them as discord-:// - * Update the HKEY_CURRENT_USER, because it doesn't seem to require special permissions. */ - - DWORD len; - LSTATUS result; - wchar_t urlProtocol = 0; - wchar_t keyName[256]; - wchar_t protocolName[64]; - wchar_t protocolDescription[128]; - wchar_t exeFilePath[MAX_PATH]; - DWORD exeLen = GetModuleFileNameW(NULL, exeFilePath, MAX_PATH); - wchar_t openCommand[1024]; - - if (command && command[0]) - StringCbPrintfW(openCommand, sizeof(openCommand), L"%S", command); - else - StringCbPrintfW(openCommand, sizeof(openCommand), L"%S", exeFilePath); - - StringCbPrintfW(protocolName, sizeof(protocolName), - L"discord-%S", applicationId); - StringCbPrintfW( - protocolDescription, sizeof(protocolDescription), - L"URL:Run game %S protocol", applicationId); - StringCbPrintfW(keyName, sizeof(keyName), L"Software\\Classes\\%S", protocolName); - HKEY key; - LSTATUS status = - RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, NULL, 0, KEY_WRITE, NULL, &key, NULL); - if (status != ERROR_SUCCESS) - { - fprintf(stderr, "Error creating key\n"); - return; - } - len = (DWORD)lstrlenW(protocolDescription) + 1; - result = - RegSetKeyValueW(key, NULL, NULL, REG_SZ, protocolDescription, len * sizeof(wchar_t)); - if (FAILED(result)) - fprintf(stderr, "Error writing description\n"); - - result = RegSetKeyValueW(key, NULL, L"URL Protocol", REG_SZ, &urlProtocol, sizeof(wchar_t)); - if (FAILED(result)) - fprintf(stderr, "Error writing description\n"); - - result = RegSetKeyValueW( - key, L"DefaultIcon", NULL, REG_SZ, exeFilePath, (exeLen + 1) * sizeof(wchar_t)); - if (FAILED(result)) - fprintf(stderr, "Error writing icon\n"); - - len = (DWORD)lstrlenW(openCommand) + 1; - result = RegSetKeyValueW( - key, L"shell\\open\\command", NULL, REG_SZ, openCommand, len * sizeof(wchar_t)); - if (FAILED(result)) - fprintf(stderr, "Error writing command\n"); - RegCloseKey(key); -} - -void Discord_Register(const char* applicationId, const char* command) -{ - wchar_t appId[32]; - wchar_t openCommand[1024]; - const wchar_t* wcommand = NULL; - - MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32); - - if (command && command[0]) - { - const int commandBufferLen = - sizeof(openCommand) / sizeof(*openCommand); - MultiByteToWideChar(CP_UTF8, 0, command, -1, - openCommand, commandBufferLen); - wcommand = openCommand; - } - - Discord_RegisterW(appId, wcommand); -} - -void Discord_RegisterSteamGame( - const char* applicationId, - const char* steamId) -{ - DWORD pathChars, pathBytes, i; - HKEY key; - wchar_t steamPath[MAX_PATH]; - wchar_t command[1024]; - wchar_t appId[32]; - wchar_t wSteamId[32]; - MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32); - MultiByteToWideChar(CP_UTF8, 0, steamId, -1, wSteamId, 32); - LSTATUS status = RegOpenKeyExW(HKEY_CURRENT_USER, - L"Software\\Valve\\Steam", 0, KEY_READ, &key); - if (status != ERROR_SUCCESS) - { - fprintf(stderr, "Error opening Steam key\n"); - return; - } - - pathBytes = sizeof(steamPath); - status = RegQueryValueExW(key, - L"SteamExe", NULL, NULL, (BYTE*)steamPath, &pathBytes); - RegCloseKey(key); - if (status != ERROR_SUCCESS || pathBytes < 1) - { - fprintf(stderr, "Error reading SteamExe key\n"); - return; - } - - pathChars = pathBytes / sizeof(wchar_t); - for (i = 0; i < pathChars; ++i) - { - if (steamPath[i] == L'/') - steamPath[i] = L'\\'; - } - - StringCbPrintfW(command, sizeof(command), - L"\"%s\" steam://rungameid/%s", steamPath, wSteamId); - - Discord_RegisterW(appId, command); -} diff --git a/deps/discord-rpc/src/discord_rpc.cpp b/deps/discord-rpc/src/discord_rpc.cpp deleted file mode 100644 index afe567627939..000000000000 --- a/deps/discord-rpc/src/discord_rpc.cpp +++ /dev/null @@ -1,578 +0,0 @@ -#include "discord_rpc.h" -#include "discord_register.h" - -#include "backoff.h" -#include "msg_queue.h" -#include "rpc_connection.h" -#include "serialization.h" - -#include -#include -#include - -#ifndef DISCORD_DISABLE_IO_THREAD -#include -#include -#endif - -struct QueuedMessage -{ - size_t length; - char buffer[16384]; - - void Copy(const QueuedMessage& other) - { - length = other.length; - if (length) - memcpy(buffer, other.buffer, length); - } -}; - -struct User -{ - /* snowflake (64bit int), turned into a ASCII decimal string, - * at most 20 chars +1 null - * terminator = 21 */ - char userId[32]; - /* 32 unicode glyphs is max name size => 4 bytes per glyph - * in the worst case, +1 for null - * terminator = 129 */ - char username[344]; - /* 4 decimal digits + 1 null terminator = 5 */ - char discriminator[8]; - /* optional 'a_' + md5 hex digest (32 bytes) + null terminator = 35 */ - char avatar[128]; - /* Rounded way up because I'm paranoid about games breaking - * from future changes in these sizes */ -}; - -static int Pid{0}; -static int Nonce{1}; -static int LastErrorCode{0}; -static int LastDisconnectErrorCode{0}; - -static char JoinGameSecret[256]; -static char SpectateGameSecret[256]; -static char LastErrorMessage[256]; -static char LastDisconnectErrorMessage[256]; - -static RpcConnection* Connection{nullptr}; - -static DiscordEventHandlers QueuedHandlers{}; -static DiscordEventHandlers Handlers{}; - -static std::atomic_bool WasJustConnected{false}; -static std::atomic_bool WasJustDisconnected{false}; -static std::atomic_bool GotErrorMessage{false}; -static std::atomic_bool WasJoinGame{false}; -static std::atomic_bool WasSpectateGame{false}; - -static std::mutex PresenceMutex; -static std::mutex HandlerMutex; -static QueuedMessage QueuedPresence{}; -static MsgQueue SendQueue; -static MsgQueue JoinAskQueue; -static User connectedUser; - -/* We want to auto connect, and retry on failure, - * but not as fast as possible. This does exponential - * backoff from 0.5 seconds to 1 minute */ -static Backoff ReconnectTimeMs(500, 60 * 1000); -static auto NextConnect = std::chrono::system_clock::now(); - -#ifndef DISCORD_DISABLE_IO_THREAD -static void Discord_UpdateConnection(void); -class IoThreadHolder -{ - private: - std::atomic_bool keepRunning{true}; - std::mutex waitForIOMutex; - std::condition_variable waitForIOActivity; - std::thread ioThread; - - public: - void Start() - { - keepRunning.store(true); - ioThread = std::thread([&]() { - const std::chrono::duration maxWait{500LL}; - Discord_UpdateConnection(); - while (keepRunning.load()) { - std::unique_lock lock(waitForIOMutex); - waitForIOActivity.wait_for(lock, maxWait); - Discord_UpdateConnection(); - } - }); - } - - void Notify() { waitForIOActivity.notify_all(); } - - void Stop() - { - keepRunning.exchange(false); - Notify(); - if (ioThread.joinable()) - ioThread.join(); - } - - ~IoThreadHolder() { Stop(); } -}; -#else -class IoThreadHolder -{ - public: - void Start() {} - void Stop() {} - void Notify() {} -}; -#endif /* DISCORD_DISABLE_IO_THREAD */ - -static IoThreadHolder* IoThread{nullptr}; - -static void UpdateReconnectTime(void) -{ - NextConnect = std::chrono::system_clock::now() + - std::chrono::duration{ReconnectTimeMs.nextDelay()}; -} - -#ifdef DISCORD_DISABLE_IO_THREAD -extern "C" void Discord_UpdateConnection(void) -#else -static void Discord_UpdateConnection(void) -#endif -{ - if (!Connection) - return; - - if (!Connection->IsOpen()) - { - if (std::chrono::system_clock::now() >= NextConnect) - { - UpdateReconnectTime(); - Connection->Open(); - } - } - else - { - /* reads */ - - for (;;) - { - JsonDocument message; - - if (!Connection->Read(message)) - break; - - char *evtName = NULL; - char *nonce = NULL; - char *secret = NULL; - char *userId = NULL; - char *username = NULL; - char *avatar = NULL; - char *discriminator = NULL; - char *error_message = NULL; - int error_code = 0; - - bool in_data = false, in_user = false; - for (JsonReader r(message); r.NextKey();) - { - if (r.depth == 1) - { - in_data = in_user = false; - if (!strcmp(r.key, "evt" )) r.NextStrDup(&evtName); - else if (!strcmp(r.key, "nonce")) r.NextStrDup(&nonce); - else if (!strcmp(r.key, "data" )) in_data = true; - } - else if (r.depth == 2 && in_data) - { - in_user = false; - if (!strcmp(r.key, "code" )) r.NextInt(&error_code); - else if (!strcmp(r.key, "message")) r.NextStrDup(&error_message); - else if (!strcmp(r.key, "secret" )) r.NextStrDup(&secret); - else if (!strcmp(r.key, "secret" )) r.NextStrDup(&secret); - else if (!strcmp(r.key, "user" )) in_user = true; - } - else if (r.depth == 3 && in_user) - { - if (!strcmp(r.key, "id" )) r.NextStrDup(&userId); - else if (!strcmp(r.key, "username" )) r.NextStrDup(&username); - else if (!strcmp(r.key, "avatar" )) r.NextStrDup(&avatar); - else if (!strcmp(r.key, "discriminator")) r.NextStrDup(&discriminator); - } - } - - if (nonce) - { - /* in responses only -- - * should use to match up response when needed. */ - - if (evtName && !strcmp(evtName, "ERROR")) - { - LastErrorCode = error_code; - StringCopy(LastErrorMessage, error_message); - GotErrorMessage.store(true); - } - } - else - { - /* should have evt == name of event, optional data */ - if (!evtName) - continue; - - if (!strcmp(evtName, "ACTIVITY_JOIN")) - { - if (secret) - { - StringCopy(JoinGameSecret, secret); - WasJoinGame.store(true); - } - } - else if (!strcmp(evtName, "ACTIVITY_SPECTATE")) - { - if (secret) - { - StringCopy(SpectateGameSecret, secret); - WasSpectateGame.store(true); - } - } - else if (!strcmp(evtName, "ACTIVITY_JOIN_REQUEST")) - { - auto joinReq = JoinAskQueue.GetNextAddMessage(); - - if (userId && username && joinReq) - { - StringCopy(joinReq->userId, userId); - StringCopy(joinReq->username, username); - if (discriminator) - StringCopy(joinReq->discriminator, discriminator); - if (avatar) - StringCopy(joinReq->avatar, avatar); - else - joinReq->avatar[0] = 0; - JoinAskQueue.CommitAdd(); - } - } - } - - if (evtName ) free(evtName ); - if (nonce ) free(nonce ); - if (secret ) free(secret ); - if (userId ) free(userId ); - if (username ) free(username ); - if (avatar ) free(avatar ); - if (discriminator) free(discriminator); - if (error_message) free(error_message); - } - - /* writes */ - if (QueuedPresence.length) - { - QueuedMessage local; - { - std::lock_guard guard(PresenceMutex); - local.Copy(QueuedPresence); - QueuedPresence.length = 0; - } - if (!Connection->Write(local.buffer, local.length)) - { - /* if we fail to send, requeue */ - std::lock_guard guard(PresenceMutex); - QueuedPresence.Copy(local); - } - } - - while (SendQueue.HavePendingSends()) - { - auto qmessage = SendQueue.GetNextSendMessage(); - Connection->Write(qmessage->buffer, qmessage->length); - SendQueue.CommitSend(); - } - } -} - -static bool RegisterForEvent(const char* evtName) -{ - auto qmessage = SendQueue.GetNextAddMessage(); - if (qmessage) - { - qmessage->length = - JsonWriteSubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName); - SendQueue.CommitAdd(); - if (IoThread) - IoThread->Notify(); - return true; - } - return false; -} - -static bool DeregisterForEvent(const char* evtName) -{ - auto qmessage = SendQueue.GetNextAddMessage(); - if (qmessage) - { - qmessage->length = - JsonWriteUnsubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName); - SendQueue.CommitAdd(); - if (IoThread) - IoThread->Notify(); - return true; - } - return false; -} - -extern "C" void Discord_Initialize( - const char* applicationId, - DiscordEventHandlers* handlers, - int autoRegister, - const char* optionalSteamId) -{ - IoThread = new (std::nothrow) IoThreadHolder(); - if (!IoThread) - return; - - if (autoRegister) - { - if (optionalSteamId && optionalSteamId[0]) - Discord_RegisterSteamGame(applicationId, optionalSteamId); - else - Discord_Register(applicationId, nullptr); - } - - Pid = get_process_id(); - - { - std::lock_guard guard(HandlerMutex); - - if (handlers) - QueuedHandlers = *handlers; - else - QueuedHandlers = {}; - - Handlers = {}; - } - - if (Connection) - return; - - Connection = RpcConnection::Create(applicationId); - Connection->onConnect = [](JsonDocument& readyMessage) - { - Discord_UpdateHandlers(&QueuedHandlers); - char *userId = NULL; - char *username = NULL; - char *avatar = NULL; - char *discriminator = NULL; - - bool in_data = false, in_user = false; - for (JsonReader r(readyMessage); r.NextKey();) - { - if (r.depth == 1) - { - in_data = !strcmp(r.key,"data"); - in_user = false; - } - else if (r.depth == 2 && in_data) - { - in_user = !strcmp(r.key, "user"); - } - else if (r.depth == 3 && in_user) - { - if (!strcmp(r.key, "id" )) r.NextStrDup(&userId); - else if (!strcmp(r.key, "username" )) r.NextStrDup(&username); - else if (!strcmp(r.key, "avatar" )) r.NextStrDup(&avatar); - else if (!strcmp(r.key, "discriminator")) r.NextStrDup(&discriminator); - } - } - - if (userId && username) - { - StringCopy(connectedUser.userId, userId); - StringCopy(connectedUser.username, username); - if (discriminator) - StringCopy(connectedUser.discriminator, discriminator); - if (avatar) - StringCopy(connectedUser.avatar, avatar); - else - connectedUser.avatar[0] = 0; - } - WasJustConnected.exchange(true); - ReconnectTimeMs.reset(); - - if (userId ) free(userId ); - if (username ) free(username ); - if (avatar ) free(avatar ); - if (discriminator) free(discriminator); - }; - Connection->onDisconnect = [](int err, const char* message) - { - LastDisconnectErrorCode = err; - StringCopy(LastDisconnectErrorMessage, message); - { - std::lock_guard guard(HandlerMutex); - Handlers = {}; - } - WasJustDisconnected.exchange(true); - UpdateReconnectTime(); - }; - - IoThread->Start(); -} - -extern "C" void Discord_Shutdown(void) -{ - if (!Connection) - return; - Connection->onConnect = nullptr; - Connection->onDisconnect = nullptr; - Handlers = {}; - if (IoThread) - { - IoThread->Stop(); - delete IoThread; - IoThread = nullptr; - } - - RpcConnection::Destroy(Connection); -} - -extern "C" void Discord_UpdatePresence(const DiscordRichPresence* presence) -{ - { - std::lock_guard guard(PresenceMutex); - QueuedPresence.length = JsonWriteRichPresenceObj( - QueuedPresence.buffer, sizeof(QueuedPresence.buffer), Nonce++, Pid, presence); - } - if (IoThread) - IoThread->Notify(); -} - -extern "C" void Discord_ClearPresence(void) -{ - Discord_UpdatePresence(nullptr); -} - -extern "C" void Discord_Respond(const char* userId, /* DISCORD_REPLY_ */ int reply) -{ - /* if we are not connected, let's not batch up stale messages for later */ - if (!Connection || !Connection->IsOpen()) - return; - auto qmessage = SendQueue.GetNextAddMessage(); - if (qmessage) - { - qmessage->length = - JsonWriteJoinReply(qmessage->buffer, sizeof(qmessage->buffer), userId, reply, Nonce++); - SendQueue.CommitAdd(); - if (IoThread) - IoThread->Notify(); - } -} - -extern "C" void Discord_RunCallbacks(void) -{ - /* Note on some weirdness: internally we might connect, get other signals, disconnect any number - * of times inbetween calls here. Externally, we want the sequence to seem sane, so any other - * signals are book-ended by calls to ready and disconnect. - */ - - if (!Connection) - return; - - bool wasDisconnected = WasJustDisconnected.exchange(false); - bool isConnected = Connection->IsOpen(); - - if (isConnected) - { - /* if we are connected, disconnect cb first */ - std::lock_guard guard(HandlerMutex); - if (wasDisconnected && Handlers.disconnected) - Handlers.disconnected(LastDisconnectErrorCode, LastDisconnectErrorMessage); - } - - if (WasJustConnected.exchange(false)) - { - std::lock_guard guard(HandlerMutex); - if (Handlers.ready) - { - DiscordUser du{connectedUser.userId, - connectedUser.username, - connectedUser.discriminator, - connectedUser.avatar}; - Handlers.ready(&du); - } - } - - if (GotErrorMessage.exchange(false)) - { - std::lock_guard guard(HandlerMutex); - if (Handlers.errored) - Handlers.errored(LastErrorCode, LastErrorMessage); - } - - if (WasJoinGame.exchange(false)) - { - std::lock_guard guard(HandlerMutex); - if (Handlers.joinGame) - Handlers.joinGame(JoinGameSecret); - } - - if (WasSpectateGame.exchange(false)) - { - std::lock_guard guard(HandlerMutex); - if (Handlers.spectateGame) - Handlers.spectateGame(SpectateGameSecret); - } - - /* Right now this batches up any requests and sends them all in a burst; I could imagine a world - * where the implementer would rather sequentially accept/reject each one before the next invite - * is sent. I left it this way because I could also imagine wanting to process these all and - * maybe show them in one common dialog and/or start fetching the avatars in parallel, and if - * not it should be trivial for the implementer to make a queue themselves. - */ - while (JoinAskQueue.HavePendingSends()) - { - auto req = JoinAskQueue.GetNextSendMessage(); - { - std::lock_guard guard(HandlerMutex); - if (Handlers.joinRequest) - { - DiscordUser du{req->userId, req->username, req->discriminator, req->avatar}; - Handlers.joinRequest(&du); - } - } - JoinAskQueue.CommitSend(); - } - - if (!isConnected) - { - /* if we are not connected, disconnect message last */ - std::lock_guard guard(HandlerMutex); - if (wasDisconnected && Handlers.disconnected) - Handlers.disconnected(LastDisconnectErrorCode, LastDisconnectErrorMessage); - } -} - -#ifndef HANDLE_EVENT_REGISTRATION -#define HANDLE_EVENT_REGISTRATION(handler_name, event) \ - if (!Handlers.handler_name && newHandlers->handler_name) \ - RegisterForEvent(event); \ - else if (Handlers.handler_name && !newHandlers->handler_name) \ - DeregisterForEvent(event) -#endif - -extern "C" void Discord_UpdateHandlers(DiscordEventHandlers* newHandlers) -{ - if (newHandlers) - { - std::lock_guard guard(HandlerMutex); - HANDLE_EVENT_REGISTRATION(joinGame, "ACTIVITY_JOIN"); - HANDLE_EVENT_REGISTRATION(spectateGame, "ACTIVITY_SPECTATE"); - HANDLE_EVENT_REGISTRATION(joinRequest, "ACTIVITY_JOIN_REQUEST"); - - Handlers = *newHandlers; - } - else - { - std::lock_guard guard(HandlerMutex); - Handlers = {}; - } -} diff --git a/deps/discord-rpc/src/msg_queue.h b/deps/discord-rpc/src/msg_queue.h deleted file mode 100644 index f8df267a2afa..000000000000 --- a/deps/discord-rpc/src/msg_queue.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include - -/* A simple queue. No locks, but only works with a single thread as producer and a single thread as - * a consumer. Mutex up as needed. */ - -template -class MsgQueue { - ElementType queue_[QueueSize]; - std::atomic_uint nextAdd_{0}; - std::atomic_uint nextSend_{0}; - std::atomic_uint pendingSends_{0}; - -public: - MsgQueue() {} - - ElementType* GetNextAddMessage() - { - /* if we are falling behind, bail */ - if (pendingSends_.load() >= QueueSize) - return nullptr; - auto index = (nextAdd_++) % QueueSize; - return &queue_[index]; - } - void CommitAdd() { ++pendingSends_; } - - bool HavePendingSends() const { return pendingSends_.load() != 0; } - ElementType* GetNextSendMessage() - { - auto index = (nextSend_++) % QueueSize; - return &queue_[index]; - } - void CommitSend() { --pendingSends_; } -}; diff --git a/deps/discord-rpc/src/rpc_connection.cpp b/deps/discord-rpc/src/rpc_connection.cpp deleted file mode 100644 index bb20023d08fd..000000000000 --- a/deps/discord-rpc/src/rpc_connection.cpp +++ /dev/null @@ -1,164 +0,0 @@ -#include "rpc_connection.h" -#include "serialization.h" - -#include - -#define RPC_VERSION 1 - -static RpcConnection Instance; - -/*static*/ RpcConnection* RpcConnection::Create(const char* applicationId) -{ - Instance.connection = BaseConnection::Create(); - StringCopy(Instance.appId, applicationId); - return &Instance; -} - -/*static*/ void RpcConnection::Destroy(RpcConnection*& c) -{ - c->Close(); - BaseConnection::Destroy(c->connection); - c = nullptr; -} - -void RpcConnection::Open() -{ - if (state == State::Connected) - return; - - if (state == State::Disconnected) - { - if (!connection->Open()) - return; - } - - if (state == State::SentHandshake) - { - JsonDocument message; - if (Read(message)) - { - bool cmdDispatch = false; - bool evtReady = false; - - for (JsonReader r(message); r.NextKey();) - { - if (r.depth == 1 && !strcmp(r.key, "cmd")) - cmdDispatch = !strcmp(r.NextString(""), "DISPATCH"); - else if (r.depth == 1 && !strcmp(r.key, "evt")) - evtReady = !strcmp(r.NextString(""), "READY"); - } - - if (cmdDispatch && evtReady) - { - state = State::Connected; - if (onConnect) - onConnect(message); - } - } - } - else - { - sendFrame.opcode = Opcode::Handshake; - sendFrame.length = (uint32_t)JsonWriteHandshakeObj( - sendFrame.message, sizeof(sendFrame.message), RPC_VERSION, appId); - - if (connection->Write(&sendFrame, - sizeof(MessageFrameHeader) + sendFrame.length)) - state = State::SentHandshake; - else - Close(); - } -} - -void RpcConnection::Close() -{ - if (onDisconnect && (state == State::Connected || state == State::SentHandshake)) - onDisconnect(lastErrorCode, lastErrorMessage); - connection->Close(); - state = State::Disconnected; -} - -bool RpcConnection::Write(const void* data, size_t length) -{ - sendFrame.opcode = Opcode::Frame; - memcpy(sendFrame.message, data, length); - sendFrame.length = (uint32_t)length; - if (!connection->Write(&sendFrame, sizeof(MessageFrameHeader) + length)) - { - Close(); - return false; - } - return true; -} - -bool RpcConnection::Read(JsonDocument& message) -{ - MessageFrame readFrame; - - if (state != State::Connected && state != State::SentHandshake) - return false; - - for (;;) - { - bool didRead = connection->Read( - &readFrame, sizeof(MessageFrameHeader)); - - if (!didRead) - { - if (!connection->isOpen) - { - lastErrorCode = (int)ErrorCode::PipeClosed; - StringCopy(lastErrorMessage, "Pipe closed"); - Close(); - } - return false; - } - - if (readFrame.length > 0) - { - didRead = connection->Read(readFrame.message, readFrame.length); - if (!didRead) - { - lastErrorCode = (int)ErrorCode::ReadCorrupt; - StringCopy(lastErrorMessage, "Partial data in frame"); - Close(); - return false; - } - readFrame.message[readFrame.length] = 0; - } - - switch (readFrame.opcode) - { - case Opcode::Close: - message.ParseInsitu(readFrame.message); - lastErrorCode = 0; - lastErrorMessage[0] = '\0'; - for (JsonReader r(message); r.NextKey();) - { - if (r.depth == 1 && !strcmp(r.key, "code")) - r.NextInt(&lastErrorCode); - else if (r.depth == 1 && !strcmp(r.key, "message")) - StringCopy(lastErrorMessage, r.NextString("")); - } - Close(); - return false; - case Opcode::Frame: - message.ParseInsitu(readFrame.message); - return true; - case Opcode::Ping: - readFrame.opcode = Opcode::Pong; - if (!connection->Write(&readFrame, sizeof(MessageFrameHeader) + readFrame.length)) - Close(); - break; - case Opcode::Pong: - break; - case Opcode::Handshake: - default: - /* something bad happened */ - lastErrorCode = (int)ErrorCode::ReadCorrupt; - StringCopy(lastErrorMessage, "Bad ipc frame"); - Close(); - return false; - } - } -} diff --git a/deps/discord-rpc/src/rpc_connection.h b/deps/discord-rpc/src/rpc_connection.h deleted file mode 100644 index 6fb69c9ee0db..000000000000 --- a/deps/discord-rpc/src/rpc_connection.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include "connection.h" -#include "serialization.h" - -/* I took this from the buffer size libuv uses for named pipes; - * I suspect ours would usually be much smaller. */ -#define MAX_RPC_FRAMESIZE 65536 - -struct RpcConnection -{ - enum class ErrorCode : int - { - Success = 0, - PipeClosed = 1, - ReadCorrupt = 2, - }; - - enum class Opcode : uint32_t - { - Handshake = 0, - Frame = 1, - Close = 2, - Ping = 3, - Pong = 4, - }; - - struct MessageFrameHeader - { - Opcode opcode; - uint32_t length; - }; - - struct MessageFrame : public MessageFrameHeader - { - char message[MAX_RPC_FRAMESIZE - sizeof(MessageFrameHeader)]; - }; - - enum class State : uint32_t - { - Disconnected, - SentHandshake, - AwaitingResponse, - Connected, - }; - - BaseConnection* connection{nullptr}; - State state{State::Disconnected}; - void (*onConnect)(JsonDocument& message){nullptr}; - void (*onDisconnect)(int errorCode, const char* message){nullptr}; - char appId[64]{}; - int lastErrorCode{0}; - char lastErrorMessage[256]{}; - RpcConnection::MessageFrame sendFrame; - - static RpcConnection* Create(const char* applicationId); - static void Destroy(RpcConnection*&); - - inline bool IsOpen() const { return state == State::Connected; } - - void Open(); - void Close(); - bool Write(const void* data, size_t length); - bool Read(JsonDocument& message); -}; diff --git a/deps/discord-rpc/src/serialization.cpp b/deps/discord-rpc/src/serialization.cpp deleted file mode 100644 index d0ce45f44022..000000000000 --- a/deps/discord-rpc/src/serialization.cpp +++ /dev/null @@ -1,248 +0,0 @@ -#include "serialization.h" -#include "connection.h" -#include "discord_rpc.h" - -template -void NumberToString(char* dest, T number) -{ - char temp[32]; - int place = 0; - - if (!number) - { - *dest++ = '0'; - *dest++ = 0; - return; - } - - if (number < 0) - { - *dest++ = '-'; - number = -number; - } - - while (number) - { - auto digit = number % 10; - number = number / 10; - temp[place++] = '0' + (char)digit; - } - for (--place; place >= 0; --place) - *dest++ = temp[place]; - *dest = 0; -} - -struct WriteObject { - JsonWriter& writer; - WriteObject(JsonWriter& w) - : writer(w) - { - writer.StartObject(); - } - WriteObject(JsonWriter& w, const char* name) - : writer(w) - { - writer.Key(name); - writer.StartObject(); - } - ~WriteObject() { writer.EndObject(); } -}; - -struct WriteArray { - JsonWriter& writer; - WriteArray(JsonWriter& w, const char* name) - : writer(w) - { - writer.Key(name); - writer.StartArray(); - } - ~WriteArray() { writer.EndArray(); } -}; - -void WriteOptionalString(JsonWriter& w, const char* k, const char* value) -{ - if (value && value[0]) - { - w.Key(k); - w.String(value); - } -} - -static void JsonWriteNonce(JsonWriter& writer, int nonce) -{ - char nonceBuffer[32]; - writer.Key("nonce"); - NumberToString(nonceBuffer, nonce); - writer.String(nonceBuffer); -} - -size_t JsonWriteRichPresenceObj(char* dest, - size_t maxLen, - int nonce, - int pid, - const DiscordRichPresence* presence) -{ - JsonWriter writer(dest, maxLen); - - { - WriteObject top(writer); - - JsonWriteNonce(writer, nonce); - - writer.Key("cmd"); - writer.String("SET_ACTIVITY"); - - { - WriteObject args(writer, "args"); - - writer.Key("pid"); - writer.Int(pid); - - if (presence) - { - WriteObject activity(writer, "activity"); - - WriteOptionalString(writer, "state", presence->state); - WriteOptionalString(writer, "details", presence->details); - - if (presence->startTimestamp || presence->endTimestamp) - { - WriteObject timestamps(writer, "timestamps"); - - if (presence->startTimestamp) - { - writer.Key("start"); - writer.Int64(presence->startTimestamp); - } - - if (presence->endTimestamp) - { - writer.Key("end"); - writer.Int64(presence->endTimestamp); - } - } - - if ((presence->largeImageKey && presence->largeImageKey[0]) || - (presence->largeImageText && presence->largeImageText[0]) || - (presence->smallImageKey && presence->smallImageKey[0]) || - (presence->smallImageText && presence->smallImageText[0])) { - WriteObject assets(writer, "assets"); - WriteOptionalString(writer, "large_image", presence->largeImageKey); - WriteOptionalString(writer, "large_text", presence->largeImageText); - WriteOptionalString(writer, "small_image", presence->smallImageKey); - WriteOptionalString(writer, "small_text", presence->smallImageText); - } - - if (( - presence->partyId && presence->partyId[0]) || - presence->partySize || - presence->partyMax) - { - WriteObject party(writer, "party"); - WriteOptionalString(writer, "id", presence->partyId); - if (presence->partySize && presence->partyMax) - { - WriteArray size(writer, "size"); - writer.Int(presence->partySize); - writer.Int(presence->partyMax); - } - } - - if ((presence->matchSecret && presence->matchSecret[0]) || - (presence->joinSecret && presence->joinSecret[0]) || - (presence->spectateSecret && presence->spectateSecret[0])) - { - WriteObject secrets(writer, "secrets"); - WriteOptionalString(writer, "match", presence->matchSecret); - WriteOptionalString(writer, "join", presence->joinSecret); - WriteOptionalString(writer, "spectate", presence->spectateSecret); - } - - writer.Key("instance"); - writer.Bool(presence->instance != 0); - } - } - } - - return writer.Size(); -} - -size_t JsonWriteHandshakeObj(char* dest, size_t maxLen, int version, const char* applicationId) -{ - JsonWriter writer(dest, maxLen); - - { - WriteObject obj(writer); - writer.Key("v"); - writer.Int(version); - writer.Key("client_id"); - writer.String(applicationId); - } - - return writer.Size(); -} - -size_t JsonWriteSubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName) -{ - JsonWriter writer(dest, maxLen); - - { - WriteObject obj(writer); - - JsonWriteNonce(writer, nonce); - - writer.Key("cmd"); - writer.String("SUBSCRIBE"); - - writer.Key("evt"); - writer.String(evtName); - } - - return writer.Size(); -} - -size_t JsonWriteUnsubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName) -{ - JsonWriter writer(dest, maxLen); - - { - WriteObject obj(writer); - - JsonWriteNonce(writer, nonce); - - writer.Key("cmd"); - writer.String("UNSUBSCRIBE"); - - writer.Key("evt"); - writer.String(evtName); - } - - return writer.Size(); -} - -size_t JsonWriteJoinReply(char* dest, size_t maxLen, const char* userId, int reply, int nonce) -{ - JsonWriter writer(dest, maxLen); - - { - WriteObject obj(writer); - - writer.Key("cmd"); - if (reply == DISCORD_REPLY_YES) - writer.String("SEND_ACTIVITY_JOIN_INVITE"); - else - writer.String("CLOSE_ACTIVITY_JOIN_REQUEST"); - - writer.Key("args"); - { - WriteObject args(writer); - - writer.Key("user_id"); - writer.String(userId); - } - - JsonWriteNonce(writer, nonce); - } - - return writer.Size(); -} diff --git a/deps/discord-rpc/src/serialization.h b/deps/discord-rpc/src/serialization.h deleted file mode 100644 index 57e08ab75bd3..000000000000 --- a/deps/discord-rpc/src/serialization.h +++ /dev/null @@ -1,250 +0,0 @@ -#pragma once - -#ifdef _MSC_VER -/* avoid deprecated warning about strdup */ -#define _CRT_NONSTDC_NO_DEPRECATE -#endif /* _MSC_VER */ - -#include -#include /* memcpy/strlen/strcmp/strdup */ -#include /* malloc/realloc/free */ - -#include - -/* if only there was a standard library function for this */ -template -inline size_t StringCopy(char (&dest)[Len], const char* src) -{ - size_t copied; - char* out = dest; - if (!src || !Len) - return 0; - for (copied = 1; *src && copied < Len; ++copied) - *out++ = *src++; - *out = 0; - return copied - 1; -} - -size_t JsonWriteHandshakeObj(char* dest, size_t maxLen, - int version, const char* applicationId); - -/* Commands */ -struct DiscordRichPresence; -size_t JsonWriteRichPresenceObj(char* dest, - size_t maxLen, - int nonce, - int pid, - const DiscordRichPresence* presence); -size_t JsonWriteSubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName); - -size_t JsonWriteUnsubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName); - -size_t JsonWriteJoinReply(char* dest, size_t maxLen, const char* userId, int reply, int nonce); - -class JsonWriter -{ - char* buf; - size_t buf_len; - size_t buf_cap; - - rjsonwriter_t* writer; - bool need_comma; - - static int writer_io(const void* inbuf, int inlen, void *user_data) - { - JsonWriter* self = (JsonWriter*)user_data; - size_t buf_remain = (self->buf_cap - self->buf_len); - if ((size_t)inlen > buf_remain) - inlen = (int)buf_remain; - memcpy(self->buf + self->buf_len, inbuf, inlen); - self->buf_len += inlen; - self->buf[self->buf_len - (self->buf_len == self->buf_cap ? 1 : 0)] = '\0'; - return inlen; - } - - public: - JsonWriter(char* dest, size_t maxLen) - : buf(dest), buf_len(0), buf_cap(maxLen), - need_comma(false) - { - writer = rjsonwriter_open_user(writer_io, this); - } - - ~JsonWriter() - { - rjsonwriter_free(writer); - } - - size_t Size() - { - rjsonwriter_flush(writer); - return buf_len; - } - - void WriteComma() - { - if (!need_comma) - return; - rjsonwriter_raw(writer, ",", 1); - need_comma = false; - } - - void StartObject() - { - WriteComma(); - rjsonwriter_raw(writer, "{", 1); - } - - void StartArray() - { - WriteComma(); - rjsonwriter_raw(writer, "[", 1); - } - - void EndObject() - { - rjsonwriter_raw(writer, "}", 1); - need_comma = true; - } - - void EndArray() - { - rjsonwriter_raw(writer, "]", 1); - need_comma = true; - } - - void Key(const char* key) - { - WriteComma(); - rjsonwriter_add_string(writer, key); - rjsonwriter_raw(writer, ":", 1); - } - - void String(const char* val) - { - WriteComma(); - rjsonwriter_add_string(writer, val); - need_comma = true; - } - - void Int(int value) - { - WriteComma(); - rjsonwriter_rawf(writer, "%d", value); - need_comma = true; - } - - void Int64(int64_t val) - { - WriteComma(); - char num[24], *pEnd = num + 24, *p = pEnd; - if (!val) - { - *(--p) = '0'; - } - else if (val < 0) - { - for (; val; val /= 10) - *(--p) = '0' - (char)(val % 10); - *(--p) = '-'; - } - else - { - for (; val; val /= 10) - *(--p) = '0' + (char)(val % 10); - } - rjsonwriter_raw(writer, p, (int)(pEnd - p)); - need_comma = true; - } - - void Bool(bool value) - { - WriteComma(); - rjsonwriter_raw(writer, (value ? "true" : "false"), (value ? 4 : 5)); - need_comma = true; - } -}; - -class JsonDocument -{ - size_t json_cap; - enum { kDefaultChunkCapacity = 32 * 1024 }; - - public: - size_t json_length; - char* json_data; - - JsonDocument() - : json_cap(kDefaultChunkCapacity), json_length(0), - json_data((char*)malloc(kDefaultChunkCapacity)) - { } - - ~JsonDocument() - { - free(json_data); - } - - void ParseInsitu(const char* input) - { - size_t input_len = strlen(input); - while (json_length + input_len >= json_cap) - { - json_cap += kDefaultChunkCapacity; - json_data = (char*)realloc(json_data, json_cap); - } - memcpy(json_data + json_length, input, input_len); - json_length += input_len; - json_data[json_length] = '\0'; - } -}; - -class JsonReader -{ - rjson_t* reader; - - public: - const char* key; - unsigned int depth; - - JsonReader(JsonDocument& doc) - : reader(rjson_open_buffer(doc.json_data, doc.json_length)) - { } - - ~JsonReader() - { - rjson_free(reader); - } - - bool NextKey() - { - for (;;) - { - enum rjson_type json_type = rjson_next(reader); - if (json_type == RJSON_DONE || json_type == RJSON_ERROR) return false; - if (json_type != RJSON_STRING) continue; - if (rjson_get_context_type(reader) != RJSON_OBJECT) continue; - if ((rjson_get_context_count(reader) & 1) != 1) continue; - depth = rjson_get_context_depth(reader); - key = rjson_get_string(reader, NULL); - return true; - } - } - - const char* NextString(const char* default_val) - { - return (rjson_next(reader) != RJSON_STRING ? default_val : - rjson_get_string(reader, NULL)); - } - - void NextStrDup(char** val) - { - if (rjson_next(reader) == RJSON_STRING) - *val = strdup(rjson_get_string(reader, NULL)); - } - - void NextInt(int* val) - { - if (rjson_next(reader) == RJSON_NUMBER) - *val = rjson_get_int(reader); - } -}; diff --git a/frontend/drivers/platform_darwin.m b/frontend/drivers/platform_darwin.m index 5ae85ceacf7d..4fd9c2d51efb 100644 --- a/frontend/drivers/platform_darwin.m +++ b/frontend/drivers/platform_darwin.m @@ -1063,6 +1063,11 @@ static void frontend_darwin_content_loaded(void) #endif } +static enum rarch_display_type frontend_darwin_get_display_type(void) +{ + return RARCH_DISPLAY_OSX; +} + frontend_ctx_driver_t frontend_ctx_darwin = { frontend_darwin_get_env, /* get_env */ NULL, /* init */ @@ -1096,7 +1101,7 @@ static void frontend_darwin_content_loaded(void) frontend_darwin_is_narrator_running, /* is_narrator_running */ frontend_darwin_accessibility_speak, /* accessibility_speak */ NULL, /* set_gamemode */ - NULL, /* get_display_type */ + frontend_darwin_get_display_type, "darwin", /* ident */ NULL /* get_video_driver */ }; diff --git a/frontend/drivers/platform_uwp.c b/frontend/drivers/platform_uwp.c index 4cc3f0314772..52cc844e2108 100644 --- a/frontend/drivers/platform_uwp.c +++ b/frontend/drivers/platform_uwp.c @@ -334,6 +334,11 @@ static uint64_t frontend_uwp_get_free_mem(void) return (mem_info.ullTotalPhys - mem_info.ullAvailPhys); } +static enum rarch_display_type frontend_uwp_get_display_type(void) +{ + return RARCH_DISPLAY_WIN32; +} + frontend_ctx_driver_t frontend_ctx_uwp = { frontend_uwp_env_get, /* env_get */ frontend_uwp_init, /* init */ @@ -367,7 +372,7 @@ frontend_ctx_driver_t frontend_ctx_uwp = { NULL, /* is_narrator_running */ NULL, /* accessibility_speak */ NULL, /* set_gamemode */ - NULL, /* get_display_type */ + frontend_uwp_get_display_type, "uwp", /* ident */ NULL /* get_video_driver */ }; diff --git a/gfx/common/wayland_common.c b/gfx/common/wayland_common.c index 269305707722..98b4a8f27bde 100644 --- a/gfx/common/wayland_common.c +++ b/gfx/common/wayland_common.c @@ -469,42 +469,6 @@ void gfx_ctx_wl_update_title_common(void *data) } } -bool gfx_ctx_wl_get_metrics_common(void *data, - enum display_metric_types type, float *value) -{ - display_output_t *od; - gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data; - output_info_t *oi = wl ? wl->current_output : NULL; - - if (!oi) - wl_list_for_each(od, &wl->all_outputs, link) - { - oi = od->output; - break; - }; - - switch (type) - { - case DISPLAY_METRIC_MM_WIDTH: - *value = (float)oi->physical_width; - break; - - case DISPLAY_METRIC_MM_HEIGHT: - *value = (float)oi->physical_height; - break; - - case DISPLAY_METRIC_DPI: - *value = (float)oi->width * 25.4f - / (float)oi->physical_width; - break; - - default: - *value = 0.0f; - return false; - } - - return true; -} static int create_shm_file(off_t size) { @@ -1135,13 +1099,6 @@ bool gfx_ctx_wl_suppress_screensaver(void *data, bool state) return true; } -float gfx_ctx_wl_get_refresh_rate(void *data) -{ - gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data; - if (!wl || !wl->current_output) - return false; - return (float)wl->current_output->refresh_rate / 1000.0f; -} bool gfx_ctx_wl_has_focus(void *data) { diff --git a/gfx/common/wayland_common.h b/gfx/common/wayland_common.h index 41f32a9e2e4d..4e4b0f157791 100644 --- a/gfx/common/wayland_common.h +++ b/gfx/common/wayland_common.h @@ -62,8 +62,6 @@ void gfx_ctx_wl_destroy_resources_common(gfx_ctx_wayland_data_t *wl); void gfx_ctx_wl_update_title_common(void *data); -bool gfx_ctx_wl_get_metrics_common(void *data, - enum display_metric_types type, float *value); bool gfx_ctx_wl_init_common( const toplevel_listener_t *toplevel_listener, @@ -81,7 +79,6 @@ bool gfx_ctx_wl_set_video_mode_common(gfx_ctx_wayland_data_t *wl, unsigned width, unsigned height, bool fullscreen); -float gfx_ctx_wl_get_refresh_rate(void *data); bool gfx_ctx_wl_has_focus(void *data); diff --git a/gfx/common/win32_common.c b/gfx/common/win32_common.c index 134d9ce3716c..5bdf9b2cb735 100644 --- a/gfx/common/win32_common.c +++ b/gfx/common/win32_common.c @@ -120,119 +120,6 @@ extern bool winraw_handle_message(UINT message, WPARAM wParam, LPARAM lParam); #endif -typedef struct DISPLAYCONFIG_RATIONAL_CUSTOM -{ - UINT32 Numerator; - UINT32 Denominator; -} DISPLAYCONFIG_RATIONAL_CUSTOM; - -typedef struct DISPLAYCONFIG_2DREGION_CUSTOM -{ - UINT32 cx; - UINT32 cy; -} DISPLAYCONFIG_2DREGION_CUSTOM; - -typedef struct DISPLAYCONFIG_VIDEO_SIGNAL_INFO_CUSTOM -{ - UINT64 pixelRate; - DISPLAYCONFIG_RATIONAL_CUSTOM hSyncFreq; - DISPLAYCONFIG_RATIONAL_CUSTOM vSyncFreq; - DISPLAYCONFIG_2DREGION_CUSTOM activeSize; - DISPLAYCONFIG_2DREGION_CUSTOM totalSize; - union - { - struct - { - UINT32 videoStandard :16; - UINT32 vSyncFreqDivider :6; - UINT32 reserved :10; - } AdditionalSignalInfo; - UINT32 videoStandard; - } dummyunionname; - UINT32 scanLineOrdering; -} DISPLAYCONFIG_VIDEO_SIGNAL_INFO_CUSTOM; - -typedef struct DISPLAYCONFIG_TARGET_MODE_CUSTOM -{ - DISPLAYCONFIG_VIDEO_SIGNAL_INFO_CUSTOM targetVideoSignalInfo; -} DISPLAYCONFIG_TARGET_MODE_CUSTOM; - -typedef struct DISPLAYCONFIG_PATH_SOURCE_INFO_CUSTOM -{ - LUID adapterId; - UINT32 id; - union - { - UINT32 modeInfoIdx; - struct - { - UINT32 cloneGroupId :16; - UINT32 sourceModeInfoIdx :16; - } dummystructname; - } dummyunionname; - UINT32 statusFlags; -} DISPLAYCONFIG_PATH_SOURCE_INFO_CUSTOM; - -typedef struct DISPLAYCONFIG_DESKTOP_IMAGE_INFO_CUSTOM -{ - POINTL PathSourceSize; - RECTL DesktopImageRegion; - RECTL DesktopImageClip; -} DISPLAYCONFIG_DESKTOP_IMAGE_INFO_CUSTOM; - -typedef struct DISPLAYCONFIG_SOURCE_MODE_CUSTOM -{ - UINT32 width; - UINT32 height; - UINT32 pixelFormat; - POINTL position; -} DISPLAYCONFIG_SOURCE_MODE_CUSTOM; - -typedef struct DISPLAYCONFIG_MODE_INFO_CUSTOM -{ - UINT32 infoType; - UINT32 id; - LUID adapterId; - union - { - DISPLAYCONFIG_TARGET_MODE_CUSTOM targetMode; - DISPLAYCONFIG_SOURCE_MODE_CUSTOM sourceMode; - DISPLAYCONFIG_DESKTOP_IMAGE_INFO_CUSTOM desktopImageInfo; - } dummyunionname; -} DISPLAYCONFIG_MODE_INFO_CUSTOM; - -typedef struct DISPLAYCONFIG_PATH_TARGET_INFO_CUSTOM -{ - LUID adapterId; - UINT32 id; - union - { - UINT32 modeInfoIdx; - struct - { - UINT32 desktopModeInfoIdx :16; - UINT32 targetModeInfoIdx :16; - } dummystructname; - } dummyunionname; - UINT32 outputTechnology; - UINT32 rotation; - UINT32 scaling; - DISPLAYCONFIG_RATIONAL_CUSTOM refreshRate; - UINT32 scanLineOrdering; - BOOL targetAvailable; - UINT32 statusFlags; -} DISPLAYCONFIG_PATH_TARGET_INFO_CUSTOM; - -typedef struct DISPLAYCONFIG_PATH_INFO_CUSTOM -{ - DISPLAYCONFIG_PATH_SOURCE_INFO_CUSTOM sourceInfo; - DISPLAYCONFIG_PATH_TARGET_INFO_CUSTOM targetInfo; - UINT32 flags; -} DISPLAYCONFIG_PATH_INFO_CUSTOM; - -typedef LONG (WINAPI *QUERYDISPLAYCONFIG)(UINT32, UINT32*, DISPLAYCONFIG_PATH_INFO_CUSTOM*, UINT32*, DISPLAYCONFIG_MODE_INFO_CUSTOM*, UINT32*); -typedef LONG (WINAPI *GETDISPLAYCONFIGBUFFERSIZES)(UINT32, UINT32*, UINT32*); - HACCEL window_accelerators; /* Power Request APIs */ @@ -1578,58 +1465,6 @@ static bool win32_window_create(void *data, unsigned style, #endif #if !defined(_XBOX) && !defined(__WINRT__) -bool win32_get_metrics(void *data, - enum display_metric_types type, float *value) -{ - HDC monitor; - bool ret = true; - - if (type == DISPLAY_METRIC_NONE) - { - *value = 0; - return false; - } - - monitor = GetDC(NULL); - if (!monitor) - { - *value = 0; - return false; - } - - switch (type) - { - case DISPLAY_METRIC_PIXEL_WIDTH: - *value = (float)GetDeviceCaps(monitor, HORZRES); - break; - case DISPLAY_METRIC_PIXEL_HEIGHT: - *value = (float)GetDeviceCaps(monitor, VERTRES); - break; - case DISPLAY_METRIC_MM_WIDTH: - *value = (float)GetDeviceCaps(monitor, HORZSIZE); - break; - case DISPLAY_METRIC_MM_HEIGHT: - *value = (float)GetDeviceCaps(monitor, VERTSIZE); - break; - case DISPLAY_METRIC_DPI: - /* 25.4 mm in an inch. */ - { - int pixels_x = GetDeviceCaps(monitor, HORZRES); - int physical_width = GetDeviceCaps(monitor, HORZSIZE); - *value = (physical_width > 0) - ? (float)(254 * pixels_x) / (float)(physical_width * 10) - : 0.0f; - } - break; - default: - *value = 0; - ret = false; - break; - } - - ReleaseDC(NULL, monitor); - return ret; -} #endif void win32_monitor_init(void) @@ -2086,179 +1921,6 @@ void win32_destroy_window(void) main_window.hwnd = NULL; } -void win32_get_video_output_prev( - unsigned *width, unsigned *height) -{ - DEVMODE dm; - unsigned i; - bool found = false; - unsigned prev_width = 0; - unsigned prev_height = 0; - unsigned curr_width = 0; - unsigned curr_height = 0; - - if (win32_get_video_output(&dm, -1)) - { - curr_width = dm.dmPelsWidth; - curr_height = dm.dmPelsHeight; - } - - for (i = 0; win32_get_video_output(&dm, i); i++) - { - if ( dm.dmPelsWidth == curr_width - && dm.dmPelsHeight == curr_height) - { - if ( prev_width != curr_width - && prev_height != curr_height) - { - found = true; - break; - } - } - - prev_width = dm.dmPelsWidth; - prev_height = dm.dmPelsHeight; - } - - if (found) - { - *width = prev_width; - *height = prev_height; - } -} - -float win32_get_refresh_rate(void *data) -{ -#if _WIN32_WINNT >= 0x0601 || _WIN32_WINDOWS >= 0x0601 /* Win 7 */ - UINT32 TopologyID; - float refresh_rate = 0.0f; - unsigned int NumPathArrayElements = 0; - unsigned int NumModeInfoArrayElements = 0; - DISPLAYCONFIG_PATH_INFO_CUSTOM *PathInfoArray = NULL; - DISPLAYCONFIG_MODE_INFO_CUSTOM *ModeInfoArray = NULL; -#ifdef HAVE_DYLIB - static QUERYDISPLAYCONFIG pQueryDisplayConfig; - static GETDISPLAYCONFIGBUFFERSIZES pGetDisplayConfigBufferSizes; - if (!pQueryDisplayConfig || !pGetDisplayConfigBufferSizes) - { - HMODULE user32 = GetModuleHandle("user32.dll"); - if (!pQueryDisplayConfig) - pQueryDisplayConfig = (QUERYDISPLAYCONFIG) - GetProcAddress(user32, "QueryDisplayConfig"); - if (!pGetDisplayConfigBufferSizes) - pGetDisplayConfigBufferSizes = (GETDISPLAYCONFIGBUFFERSIZES) - GetProcAddress(user32, "GetDisplayConfigBufferSizes"); - } -#else - static QUERYDISPLAYCONFIG pQueryDisplayConfig = QueryDisplayConfig; - static GETDISPLAYCONFIGBUFFERSIZES pGetDisplayConfigBufferSizes = GetDisplayConfigBufferSizes; -#endif - - /* Both function pointers must be valid before proceeding. */ - if (!pQueryDisplayConfig || !pGetDisplayConfigBufferSizes) - return 0.0f; - - if (pGetDisplayConfigBufferSizes( - QDC_DATABASE_CURRENT, - &NumPathArrayElements, - &NumModeInfoArrayElements) != ERROR_SUCCESS) - return 0.0f; - - PathInfoArray = (DISPLAYCONFIG_PATH_INFO_CUSTOM *) - malloc(sizeof(DISPLAYCONFIG_PATH_INFO_CUSTOM) * NumPathArrayElements); - if (!PathInfoArray) - return 0.0f; - ModeInfoArray = (DISPLAYCONFIG_MODE_INFO_CUSTOM *) - malloc(sizeof(DISPLAYCONFIG_MODE_INFO_CUSTOM) * NumModeInfoArrayElements); - if (!ModeInfoArray) - { - free(PathInfoArray); - return 0.0f; - } - - if (pQueryDisplayConfig(QDC_DATABASE_CURRENT, - &NumPathArrayElements, - PathInfoArray, - &NumModeInfoArrayElements, - ModeInfoArray, - &TopologyID) == ERROR_SUCCESS - && NumPathArrayElements >= 1 - && PathInfoArray[0].targetInfo.refreshRate.Denominator != 0) - refresh_rate = (float)PathInfoArray[0].targetInfo.refreshRate.Numerator - / PathInfoArray[0].targetInfo.refreshRate.Denominator; - - free(ModeInfoArray); - free(PathInfoArray); - return refresh_rate; -#else - return 0.0f; -#endif -} - -void win32_get_video_output_next( - unsigned *width, unsigned *height) -{ - DEVMODE dm; - int i; - bool found = false; - unsigned curr_width = 0; - unsigned curr_height = 0; - - if (win32_get_video_output(&dm, -1)) - { - curr_width = dm.dmPelsWidth; - curr_height = dm.dmPelsHeight; - } - - for (i = 0; win32_get_video_output(&dm, i); i++) - { - if (found) - { - *width = dm.dmPelsWidth; - *height = dm.dmPelsHeight; - break; - } - - if ( dm.dmPelsWidth == curr_width - && dm.dmPelsHeight == curr_height) - found = true; - } -} - -#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500 /* 2K */ -#define WIN32_GET_VIDEO_OUTPUT(devName, iModeNum, dm) EnumDisplaySettingsEx(devName, iModeNum, dm, EDS_ROTATEDMODE) -#else -#define WIN32_GET_VIDEO_OUTPUT(devName, iModeNum, dm) EnumDisplaySettings(devName, iModeNum, dm) -#endif - -bool win32_get_video_output(DEVMODE *dm, int mode) -{ - MONITORINFOEX current_mon; - HMONITOR hm_to_use = NULL; - unsigned mon_id = 0; - - memset(dm, 0, sizeof(DEVMODE)); - dm->dmSize = sizeof(DEVMODE); - - win32_monitor_info(¤t_mon, &hm_to_use, &mon_id); - - return WIN32_GET_VIDEO_OUTPUT( - current_mon.szDevice, - (mode == -1) ? ENUM_CURRENT_SETTINGS : (DWORD)mode, - dm) != 0; -} - -void win32_get_video_output_size(void *data, unsigned *width, - unsigned *height, char *desc, size_t len) -{ - DEVMODE dm; - if (win32_get_video_output(&dm, -1)) - { - *width = dm.dmPelsWidth; - *height = dm.dmPelsHeight; - } -} - void win32_setup_pixel_format(HDC hdc, bool supports_gl) { int pf; diff --git a/gfx/common/win32_common.h b/gfx/common/win32_common.h index 27b21532e5fb..c63254b8bfd3 100644 --- a/gfx/common/win32_common.h +++ b/gfx/common/win32_common.h @@ -89,8 +89,6 @@ void win32_monitor_info(void *data, void *hm_data, unsigned *mon_id); int win32_change_display_settings(const char *str, void *devmode_data, unsigned flags); -bool win32_get_video_output(DEVMODE *dm, int mode); - #if !defined(__WINRT__) bool win32_window_init(WNDCLASSEX *wndclass, bool fullscreen, const char *class_name); @@ -109,9 +107,6 @@ bool win32_set_video_mode(void *data, bool win32_suspend_screensaver(void *data, bool enable); -bool win32_get_metrics(void *data, - enum display_metric_types type, float *value); - void win32_show_cursor(void *data, bool state); HWND win32_get_window(void); @@ -133,23 +128,12 @@ void win32_check_window(void *data, void win32_set_window(unsigned *width, unsigned *height, bool fullscreen, bool windowed_full, void *rect_data); -void win32_get_video_output_size(void *data, - unsigned *width, unsigned *height, char *desc, size_t desc_len); - -void win32_get_video_output_prev( - unsigned *width, unsigned *height); - -void win32_get_video_output_next( - unsigned *width, unsigned *height); - void win32_window_reset(void); void win32_destroy_window(void); uint8_t win32_get_flags(void); -float win32_get_refresh_rate(void *data); - #if defined(HAVE_D3D8) || defined(HAVE_D3D9) || defined (HAVE_D3D10) || defined (HAVE_D3D11) || defined (HAVE_D3D12) LRESULT CALLBACK wnd_proc_d3d_dinput(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); diff --git a/gfx/common/x11_common.c b/gfx/common/x11_common.c index 863346606221..4f27f73db49b 100644 --- a/gfx/common/x11_common.c +++ b/gfx/common/x11_common.c @@ -484,48 +484,6 @@ static bool x11_create_input_context(Display *dpy, return true; } -bool x11_get_metrics(void *data, - enum display_metric_types type, float *value) -{ - unsigned screen_no = 0; - Display *dpy = NULL; - - switch (type) - { - case DISPLAY_METRIC_PIXEL_WIDTH: - dpy = (Display*)XOpenDisplay(NULL); - *value = (float)DisplayWidth(dpy, screen_no); - XCloseDisplay(dpy); - break; - case DISPLAY_METRIC_PIXEL_HEIGHT: - dpy = (Display*)XOpenDisplay(NULL); - *value = (float)DisplayHeight(dpy, screen_no); - XCloseDisplay(dpy); - break; - case DISPLAY_METRIC_MM_WIDTH: - dpy = (Display*)XOpenDisplay(NULL); - *value = (float)DisplayWidthMM(dpy, screen_no); - XCloseDisplay(dpy); - break; - case DISPLAY_METRIC_MM_HEIGHT: - dpy = (Display*)XOpenDisplay(NULL); - *value = (float)DisplayHeightMM(dpy, screen_no); - XCloseDisplay(dpy); - break; - case DISPLAY_METRIC_DPI: - dpy = (Display*)XOpenDisplay(NULL); - *value = ((((float)DisplayWidth (dpy, screen_no)) * 25.4) - / ( (float)DisplayWidthMM(dpy, screen_no))); - XCloseDisplay(dpy); - break; - case DISPLAY_METRIC_NONE: - default: - *value = 0; - return false; - } - - return true; -} static enum retro_key x11_translate_keysym_to_rk(unsigned sym) { diff --git a/gfx/common/x11_common.h b/gfx/common/x11_common.h index bcf1b27d4bb5..68a3a48d5786 100644 --- a/gfx/common/x11_common.h +++ b/gfx/common/x11_common.h @@ -39,8 +39,6 @@ void x11_move_window(Display *dpy, Window win, /* Set icon, class, default stuff. */ void x11_set_window_attr(Display *dpy, Window win); -bool x11_get_metrics(void *data, - enum display_metric_types type, float *value); #ifdef HAVE_XF86VM float x11_get_refresh_rate(void *data); diff --git a/gfx/display_servers/dispserv_android.c b/gfx/display_servers/dispserv_android.c index 7c5d5ef8c223..3fef65a81fd6 100644 --- a/gfx/display_servers/dispserv_android.c +++ b/gfx/display_servers/dispserv_android.c @@ -135,7 +135,7 @@ const video_display_server_t dispserv_android = { NULL, /* get_video_output_size */ NULL, /* get_video_output_prev */ NULL, /* get_video_output_next */ - NULL, /* get_metrics */ + android_display_get_metrics, android_display_server_get_flags, "android" }; diff --git a/gfx/display_servers/dispserv_apple.m b/gfx/display_servers/dispserv_apple.m index 7d218f6559c1..68a340b68ef7 100644 --- a/gfx/display_servers/dispserv_apple.m +++ b/gfx/display_servers/dispserv_apple.m @@ -553,7 +553,7 @@ static void apple_display_server_destroy(void *data) NULL, /* get_video_output_size */ NULL, /* get_video_output_prev */ NULL, /* get_video_output_next */ - NULL, /* get_metrics */ + cocoa_get_metrics, NULL, /* get_flags */ "apple" }; diff --git a/gfx/display_servers/dispserv_kms.c b/gfx/display_servers/dispserv_kms.c index b98233122c13..27cec3df1727 100644 --- a/gfx/display_servers/dispserv_kms.c +++ b/gfx/display_servers/dispserv_kms.c @@ -223,6 +223,24 @@ static uint32_t kms_display_server_get_flags(void *data) return flags; } +static float kms_display_server_get_refresh_rate(void *data) +{ + if (g_drm_mode) + return drm_calc_refresh_rate(g_drm_mode); + return 0.0f; +} + +static void kms_display_server_get_video_output_size(void *data, + unsigned *width, unsigned *height, char *s, size_t len) +{ + if (!g_drm_mode) + return; + if (width) + *width = g_drm_mode->hdisplay; + if (height) + *height = g_drm_mode->vdisplay; +} + const video_display_server_t dispserv_kms = { kms_display_server_init, kms_display_server_destroy, @@ -234,8 +252,8 @@ const video_display_server_t dispserv_kms = { NULL, /* get output options */ NULL, /* kms_display_server_set_screen_orientation */ NULL, /* kms_display_server_get_screen_orientation */ - NULL, /* get_refresh_rate */ - NULL, /* get_video_output_size */ + kms_display_server_get_refresh_rate, + kms_display_server_get_video_output_size, NULL, /* get_video_output_prev */ NULL, /* get_video_output_next */ NULL, /* get_metrics */ diff --git a/gfx/display_servers/dispserv_uwp.c b/gfx/display_servers/dispserv_uwp.c new file mode 100644 index 000000000000..dee5a7a73ff7 --- /dev/null +++ b/gfx/display_servers/dispserv_uwp.c @@ -0,0 +1,103 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2026 - RetroArch + * + * RetroArch 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch 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 RetroArch. + * If not, see . + */ + +#include +#include +#include "../video_display_server.h" +#include "../../uwp/uwp_func.h" + +static void *uwp_display_server_init(void) { return NULL; } +static void uwp_display_server_destroy(void *data) { } + +static float uwp_display_server_get_refresh_rate(void *data) +{ + return uwp_get_refresh_rate(); +} + +static void uwp_display_server_get_video_output_size(void *data, + unsigned *width, unsigned *height, char *s, size_t len) +{ + if (width) + *width = uwp_get_width(); + if (height) + *height = uwp_get_height(); +} + +static bool uwp_display_server_get_metrics(void *data, + enum display_metric_types type, float *value) +{ + float dpi; + + if (!value) + return false; + + switch (type) + { + case DISPLAY_METRIC_PIXEL_WIDTH: + *value = (float)uwp_get_width(); + return true; + case DISPLAY_METRIC_PIXEL_HEIGHT: + *value = (float)uwp_get_height(); + return true; + case DISPLAY_METRIC_MM_WIDTH: + { + int pixels_x = uwp_get_width(); + dpi = uwp_get_dpi(); + if (dpi > 0.0f) + *value = (float)(254 * pixels_x) / (dpi * 10.0f); + else + *value = 0.0f; + } + return true; + case DISPLAY_METRIC_MM_HEIGHT: + { + int pixels_y = uwp_get_height(); + dpi = uwp_get_dpi(); + if (dpi > 0.0f) + *value = (float)(254 * pixels_y) / (dpi * 10.0f); + else + *value = 0.0f; + } + return true; + case DISPLAY_METRIC_DPI: + *value = uwp_get_dpi(); + return (*value > 0.0f); + case DISPLAY_METRIC_NONE: + default: + *value = 0.0f; + break; + } + return false; +} + +const video_display_server_t dispserv_uwp = { + uwp_display_server_init, + uwp_display_server_destroy, + NULL, /* set_window_opacity */ + NULL, /* set_window_progress */ + NULL, /* set_window_decorations */ + NULL, /* set_resolution */ + NULL, /* get_resolution_list */ + NULL, /* get_output_options */ + NULL, /* set_screen_orientation */ + NULL, /* get_screen_orientation */ + uwp_display_server_get_refresh_rate, + uwp_display_server_get_video_output_size, + NULL, /* get_video_output_prev */ + NULL, /* get_video_output_next */ + uwp_display_server_get_metrics, + NULL, /* get_flags */ + "uwp" +}; diff --git a/gfx/display_servers/dispserv_win32.c b/gfx/display_servers/dispserv_win32.c index b12074c6348a..e7de8acd0b08 100644 --- a/gfx/display_servers/dispserv_win32.c +++ b/gfx/display_servers/dispserv_win32.c @@ -23,6 +23,7 @@ #include #include + #ifndef COBJMACROS #define COBJMACROS #define COBJMACROS_DEFINED @@ -84,6 +85,119 @@ typedef struct uint8_t flags; } dispserv_win32_t; +/* Display configuration structs for QueryDisplayConfig */ +typedef struct DISPLAYCONFIG_RATIONAL_CUSTOM +{ + UINT32 Numerator; + UINT32 Denominator; +} DISPLAYCONFIG_RATIONAL_CUSTOM; + +typedef struct DISPLAYCONFIG_2DREGION_CUSTOM +{ + UINT32 cx; + UINT32 cy; +} DISPLAYCONFIG_2DREGION_CUSTOM; + +typedef struct DISPLAYCONFIG_VIDEO_SIGNAL_INFO_CUSTOM +{ + UINT64 pixelRate; + DISPLAYCONFIG_RATIONAL_CUSTOM hSyncFreq; + DISPLAYCONFIG_RATIONAL_CUSTOM vSyncFreq; + DISPLAYCONFIG_2DREGION_CUSTOM activeSize; + DISPLAYCONFIG_2DREGION_CUSTOM totalSize; + union + { + struct + { + UINT32 videoStandard :16; + UINT32 vSyncFreqDivider :6; + UINT32 reserved :10; + } AdditionalSignalInfo; + UINT32 videoStandard; + } dummyunionname; + UINT32 scanLineOrdering; +} DISPLAYCONFIG_VIDEO_SIGNAL_INFO_CUSTOM; + +typedef struct DISPLAYCONFIG_TARGET_MODE_CUSTOM +{ + DISPLAYCONFIG_VIDEO_SIGNAL_INFO_CUSTOM targetVideoSignalInfo; +} DISPLAYCONFIG_TARGET_MODE_CUSTOM; + +typedef struct DISPLAYCONFIG_PATH_SOURCE_INFO_CUSTOM +{ + LUID adapterId; + UINT32 id; + union + { + UINT32 modeInfoIdx; + struct + { + UINT32 cloneGroupId :16; + UINT32 sourceModeInfoIdx :16; + } dummystructname; + } dummyunionname; + UINT32 statusFlags; +} DISPLAYCONFIG_PATH_SOURCE_INFO_CUSTOM; + +typedef struct DISPLAYCONFIG_DESKTOP_IMAGE_INFO_CUSTOM +{ + POINTL PathSourceSize; + RECTL DesktopImageRegion; + RECTL DesktopImageClip; +} DISPLAYCONFIG_DESKTOP_IMAGE_INFO_CUSTOM; + +typedef struct DISPLAYCONFIG_SOURCE_MODE_CUSTOM +{ + UINT32 width; + UINT32 height; + UINT32 pixelFormat; + POINTL position; +} DISPLAYCONFIG_SOURCE_MODE_CUSTOM; + +typedef struct DISPLAYCONFIG_MODE_INFO_CUSTOM +{ + UINT32 infoType; + UINT32 id; + LUID adapterId; + union + { + DISPLAYCONFIG_TARGET_MODE_CUSTOM targetMode; + DISPLAYCONFIG_SOURCE_MODE_CUSTOM sourceMode; + DISPLAYCONFIG_DESKTOP_IMAGE_INFO_CUSTOM desktopImageInfo; + } dummyunionname; +} DISPLAYCONFIG_MODE_INFO_CUSTOM; + +typedef struct DISPLAYCONFIG_PATH_TARGET_INFO_CUSTOM +{ + LUID adapterId; + UINT32 id; + union + { + UINT32 modeInfoIdx; + struct + { + UINT32 desktopModeInfoIdx :16; + UINT32 targetModeInfoIdx :16; + } dummystructname; + } dummyunionname; + UINT32 outputTechnology; + UINT32 rotation; + UINT32 scaling; + DISPLAYCONFIG_RATIONAL_CUSTOM refreshRate; + UINT32 scanLineOrdering; + BOOL targetAvailable; + UINT32 statusFlags; +} DISPLAYCONFIG_PATH_TARGET_INFO_CUSTOM; + +typedef struct DISPLAYCONFIG_PATH_INFO_CUSTOM +{ + DISPLAYCONFIG_PATH_SOURCE_INFO_CUSTOM sourceInfo; + DISPLAYCONFIG_PATH_TARGET_INFO_CUSTOM targetInfo; + UINT32 flags; +} DISPLAYCONFIG_PATH_INFO_CUSTOM; + +typedef LONG (WINAPI *QUERYDISPLAYCONFIG)(UINT32, UINT32*, DISPLAYCONFIG_PATH_INFO_CUSTOM*, UINT32*, DISPLAYCONFIG_MODE_INFO_CUSTOM*, UINT32*); +typedef LONG (WINAPI *GETDISPLAYCONFIGBUFFERSIZES)(UINT32, UINT32*, UINT32*); static void *win32_display_server_init(void) { @@ -225,6 +339,30 @@ static bool win32_display_server_set_window_decorations(void *data, bool on) return true; } +static bool win32_get_video_output(DEVMODE *dm, int mode) +{ + MONITORINFOEX current_mon; + HMONITOR hm_to_use = NULL; + unsigned mon_id = 0; + + memset(dm, 0, sizeof(DEVMODE)); + dm->dmSize = sizeof(DEVMODE); + + win32_monitor_info(¤t_mon, &hm_to_use, &mon_id); + +#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500 /* Windows 2K and up*/ + return EnumDisplaySettingsEx( + current_mon.szDevice, + (mode == -1) ? ENUM_CURRENT_SETTINGS : (DWORD)mode, + dm, EDS_ROTATEDMODE) != 0; +#else + return EnumDisplaySettings( + current_mon.szDevice, + (mode == -1) ? ENUM_CURRENT_SETTINGS : (DWORD)mode, + dm) != 0; +#endif +} + static bool win32_display_server_set_resolution(void *data, unsigned width, unsigned height, int int_hz, float hz, int center, int monitor_index, int xoffset, int padjust) { @@ -437,7 +575,7 @@ static void *win32_display_server_get_resolution_list( } #if _WIN32_WINNT >= 0x0500 -enum rotation win32_display_server_get_screen_orientation(void *data) +static enum rotation win32_display_server_get_screen_orientation(void *data) { DEVMODE dm = {0}; win32_get_video_output(&dm, -1); @@ -458,7 +596,7 @@ enum rotation win32_display_server_get_screen_orientation(void *data) return ORIENTATION_NORMAL; } -void win32_display_server_set_screen_orientation(void *data, +static void win32_display_server_set_screen_orientation(void *data, enum rotation rotation) { DEVMODE dm = {0}; @@ -540,36 +678,215 @@ void win32_display_server_set_screen_orientation(void *data, static float win32_display_server_get_refresh_rate(void *data) { - return win32_get_refresh_rate(data); +#if _WIN32_WINNT >= 0x0601 || _WIN32_WINDOWS >= 0x0601 /* Win 7 */ + UINT32 TopologyID; + float refresh_rate = 0.0f; + unsigned int NumPathArrayElements = 0; + unsigned int NumModeInfoArrayElements = 0; + DISPLAYCONFIG_PATH_INFO_CUSTOM *PathInfoArray = NULL; + DISPLAYCONFIG_MODE_INFO_CUSTOM *ModeInfoArray = NULL; +#ifdef HAVE_DYLIB + static QUERYDISPLAYCONFIG pQueryDisplayConfig; + static GETDISPLAYCONFIGBUFFERSIZES pGetDisplayConfigBufferSizes; + if (!pQueryDisplayConfig || !pGetDisplayConfigBufferSizes) + { + HMODULE user32 = GetModuleHandle("user32.dll"); + if (!pQueryDisplayConfig) + pQueryDisplayConfig = (QUERYDISPLAYCONFIG) + GetProcAddress(user32, "QueryDisplayConfig"); + if (!pGetDisplayConfigBufferSizes) + pGetDisplayConfigBufferSizes = (GETDISPLAYCONFIGBUFFERSIZES) + GetProcAddress(user32, "GetDisplayConfigBufferSizes"); + } +#else + static QUERYDISPLAYCONFIG pQueryDisplayConfig = QueryDisplayConfig; + static GETDISPLAYCONFIGBUFFERSIZES pGetDisplayConfigBufferSizes = GetDisplayConfigBufferSizes; +#endif + + /* Both function pointers must be valid before proceeding. */ + if (!pQueryDisplayConfig || !pGetDisplayConfigBufferSizes) + return 0.0f; + + if (pGetDisplayConfigBufferSizes( + QDC_DATABASE_CURRENT, + &NumPathArrayElements, + &NumModeInfoArrayElements) != ERROR_SUCCESS) + return 0.0f; + + PathInfoArray = (DISPLAYCONFIG_PATH_INFO_CUSTOM *) + malloc(sizeof(DISPLAYCONFIG_PATH_INFO_CUSTOM) * NumPathArrayElements); + if (!PathInfoArray) + return 0.0f; + ModeInfoArray = (DISPLAYCONFIG_MODE_INFO_CUSTOM *) + malloc(sizeof(DISPLAYCONFIG_MODE_INFO_CUSTOM) * NumModeInfoArrayElements); + if (!ModeInfoArray) + { + free(PathInfoArray); + return 0.0f; + } + + if (pQueryDisplayConfig(QDC_DATABASE_CURRENT, + &NumPathArrayElements, + PathInfoArray, + &NumModeInfoArrayElements, + ModeInfoArray, + &TopologyID) == ERROR_SUCCESS + && NumPathArrayElements >= 1 + && PathInfoArray[0].targetInfo.refreshRate.Denominator != 0) + refresh_rate = (float)PathInfoArray[0].targetInfo.refreshRate.Numerator + / PathInfoArray[0].targetInfo.refreshRate.Denominator; + + free(ModeInfoArray); + free(PathInfoArray); + return refresh_rate; +#else + return 0.0f; +#endif } static void win32_display_server_get_video_output_size(void *data, unsigned *width, unsigned *height, char *s, size_t len) { - win32_get_video_output_size(data, width, height, s, len); + DEVMODE dm; + if (win32_get_video_output(&dm, -1)) + { + *width = dm.dmPelsWidth; + *height = dm.dmPelsHeight; + } } static void win32_display_server_get_video_output_prev(void *data) { - unsigned width = 0, height = 0; - win32_get_video_output_prev(&width, &height); + MONITORINFOEX current_mon; + HMONITOR hm_to_use = NULL; + unsigned mon_id = 0; + unsigned i; + DEVMODE dm; + DEVMODE prev_dm; + bool have_prev = false; + unsigned curr_width = 0; + unsigned curr_height = 0; + + if (win32_get_video_output(&dm, -1)) + { + curr_width = dm.dmPelsWidth; + curr_height = dm.dmPelsHeight; + } + + for (i = 0; win32_get_video_output(&dm, i); i++) + { + if ( dm.dmPelsWidth == curr_width + && dm.dmPelsHeight == curr_height) + { + if (have_prev) + break; + } + else + { + prev_dm = dm; + have_prev = true; + } + } + + if (have_prev) + { + win32_monitor_info(¤t_mon, &hm_to_use, &mon_id); + win32_change_display_settings( + (const char*)¤t_mon.szDevice, &prev_dm, 0); + } } static void win32_display_server_get_video_output_next(void *data) { - unsigned width = 0, height = 0; - win32_get_video_output_next(&width, &height); + MONITORINFOEX current_mon; + HMONITOR hm_to_use = NULL; + unsigned mon_id = 0; + int i; + DEVMODE dm; + bool found = false; + unsigned curr_width = 0; + unsigned curr_height = 0; + + if (win32_get_video_output(&dm, -1)) + { + curr_width = dm.dmPelsWidth; + curr_height = dm.dmPelsHeight; + } + + for (i = 0; win32_get_video_output(&dm, i); i++) + { + if (found) + { + if ( dm.dmPelsWidth != curr_width + || dm.dmPelsHeight != curr_height) + { + win32_monitor_info(¤t_mon, &hm_to_use, &mon_id); + win32_change_display_settings( + (const char*)¤t_mon.szDevice, &dm, 0); + break; + } + } + + if ( dm.dmPelsWidth == curr_width + && dm.dmPelsHeight == curr_height) + found = true; + } } static bool win32_display_server_get_metrics(void *data, enum display_metric_types type, float *value) { - return win32_get_metrics(data, type, value); + HDC monitor; + + if (type == DISPLAY_METRIC_NONE) + { + *value = 0; + return false; + } + + monitor = GetDC(NULL); + if (!monitor) + { + *value = 0; + return false; + } + + switch (type) + { + case DISPLAY_METRIC_PIXEL_WIDTH: + *value = (float)GetDeviceCaps(monitor, HORZRES); + break; + case DISPLAY_METRIC_PIXEL_HEIGHT: + *value = (float)GetDeviceCaps(monitor, VERTRES); + break; + case DISPLAY_METRIC_MM_WIDTH: + *value = (float)GetDeviceCaps(monitor, HORZSIZE); + break; + case DISPLAY_METRIC_MM_HEIGHT: + *value = (float)GetDeviceCaps(monitor, VERTSIZE); + break; + case DISPLAY_METRIC_DPI: + /* 25.4 mm in an inch. */ + { + int pixels_x = GetDeviceCaps(monitor, HORZRES); + int physical_width = GetDeviceCaps(monitor, HORZSIZE); + *value = (physical_width > 0) + ? (float)(254 * pixels_x) / (float)(physical_width * 10) + : 0.0f; + } + break; + default: + *value = 0; + return false; + } + + ReleaseDC(NULL, monitor); + return true; } static uint32_t win32_display_server_get_flags(void *data) { - uint32_t flags = 0; + uint32_t flags = 0; BIT32_SET(flags, DISPSERV_CTX_CRT_SWITCHRES); diff --git a/gfx/display_servers/dispserv_wl.c b/gfx/display_servers/dispserv_wl.c new file mode 100644 index 000000000000..9bfb5e45213d --- /dev/null +++ b/gfx/display_servers/dispserv_wl.c @@ -0,0 +1,230 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2026 - RetroArch + * + * RetroArch 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 Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch 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 RetroArch. + * If not, see . + */ + +#include +#include +#include +#include + +#include + +#include "../video_display_server.h" + +typedef struct +{ + struct wl_display *dpy; + struct wl_registry *registry; + struct wl_output *output; + int width; + int height; + int physical_width; /* mm */ + int physical_height; /* mm */ + int refresh; /* mHz */ + bool have_mode; + bool have_geometry; +} dispserv_wl_t; + +/* wl_output listener callbacks */ +static void output_handle_geometry(void *data, + struct wl_output *output, + int32_t x, int32_t y, + int32_t physical_width, int32_t physical_height, + int32_t subpixel, + const char *make, const char *model, + int32_t transform) +{ + dispserv_wl_t *serv = (dispserv_wl_t*)data; + serv->physical_width = physical_width; + serv->physical_height = physical_height; + serv->have_geometry = true; +} + +static void output_handle_mode(void *data, + struct wl_output *output, + uint32_t flags, + int32_t width, int32_t height, + int32_t refresh) +{ + dispserv_wl_t *serv = (dispserv_wl_t*)data; + /* Only use the current/preferred mode */ + if (flags & WL_OUTPUT_MODE_CURRENT) + { + serv->width = width; + serv->height = height; + serv->refresh = refresh; + serv->have_mode = true; + } +} + +static void output_handle_done(void *data, + struct wl_output *output) { } +static void output_handle_scale(void *data, + struct wl_output *output, int32_t factor) { } + +static const struct wl_output_listener output_listener = { + output_handle_geometry, + output_handle_mode, + output_handle_done, + output_handle_scale, +}; + +/* wl_registry listener */ +static void registry_handle_global(void *data, + struct wl_registry *registry, + uint32_t name, const char *interface, + uint32_t version) +{ + dispserv_wl_t *serv = (dispserv_wl_t*)data; + + /* Bind to the first wl_output we find */ + if (!serv->output && strcmp(interface, "wl_output") == 0) + { + serv->output = (struct wl_output*) + wl_registry_bind(registry, name, &wl_output_interface, 2); + wl_output_add_listener(serv->output, &output_listener, serv); + } +} + +static void registry_handle_global_remove(void *data, + struct wl_registry *registry, uint32_t name) { } + +static const struct wl_registry_listener registry_listener = { + registry_handle_global, + registry_handle_global_remove, +}; + +static void *wl_display_server_init(void) +{ + dispserv_wl_t *serv = (dispserv_wl_t*)calloc(1, sizeof(*serv)); + if (!serv) + return NULL; + + serv->dpy = wl_display_connect(NULL); + if (!serv->dpy) + { + free(serv); + return NULL; + } + + serv->registry = wl_display_get_registry(serv->dpy); + wl_registry_add_listener(serv->registry, ®istry_listener, serv); + + /* First roundtrip: discover globals (binds wl_output) */ + wl_display_roundtrip(serv->dpy); + /* Second roundtrip: receive wl_output events (mode, geometry) */ + wl_display_roundtrip(serv->dpy); + + return serv; +} + +static void wl_display_server_destroy(void *data) +{ + dispserv_wl_t *serv = (dispserv_wl_t*)data; + if (!serv) + return; + if (serv->output) + wl_output_destroy(serv->output); + if (serv->registry) + wl_registry_destroy(serv->registry); + if (serv->dpy) + wl_display_disconnect(serv->dpy); + free(serv); +} + +static float wl_display_server_get_refresh_rate(void *data) +{ + dispserv_wl_t *serv = (dispserv_wl_t*)data; + if (!serv || !serv->have_mode || serv->refresh <= 0) + return 0.0f; + return (float)serv->refresh / 1000.0f; +} + +static void wl_display_server_get_video_output_size(void *data, + unsigned *width, unsigned *height, char *s, size_t len) +{ + dispserv_wl_t *serv = (dispserv_wl_t*)data; + if (!serv || !serv->have_mode) + return; + if (width) + *width = serv->width; + if (height) + *height = serv->height; +} + +static bool wl_display_server_get_metrics(void *data, + enum display_metric_types type, float *value) +{ + dispserv_wl_t *serv = (dispserv_wl_t*)data; + + if (!serv || !value) + return false; + + switch (type) + { + case DISPLAY_METRIC_MM_WIDTH: + if (!serv->have_geometry) + return false; + *value = (float)serv->physical_width; + break; + case DISPLAY_METRIC_MM_HEIGHT: + if (!serv->have_geometry) + return false; + *value = (float)serv->physical_height; + break; + case DISPLAY_METRIC_DPI: + if (!serv->have_mode || !serv->have_geometry + || serv->physical_width <= 0) + return false; + *value = (float)serv->width * 25.4f + / (float)serv->physical_width; + break; + case DISPLAY_METRIC_PIXEL_WIDTH: + if (!serv->have_mode) + return false; + *value = (float)serv->width; + break; + case DISPLAY_METRIC_PIXEL_HEIGHT: + if (!serv->have_mode) + return false; + *value = (float)serv->height; + break; + case DISPLAY_METRIC_NONE: + default: + *value = 0.0f; + return false; + } + + return true; +} + +const video_display_server_t dispserv_wl = { + wl_display_server_init, + wl_display_server_destroy, + NULL, /* set_window_opacity */ + NULL, /* set_window_progress */ + NULL, /* set_window_decorations */ + NULL, /* set_resolution */ + NULL, /* get_resolution_list */ + NULL, /* get_output_options */ + NULL, /* set_screen_orientation */ + NULL, /* get_screen_orientation */ + wl_display_server_get_refresh_rate, + wl_display_server_get_video_output_size, + NULL, /* get_video_output_prev */ + NULL, /* get_video_output_next */ + wl_display_server_get_metrics, + NULL, /* get_flags */ + "wayland" +}; diff --git a/gfx/display_servers/dispserv_x11.c b/gfx/display_servers/dispserv_x11.c index d9083c28ce19..6a15600abde8 100644 --- a/gfx/display_servers/dispserv_x11.c +++ b/gfx/display_servers/dispserv_x11.c @@ -762,6 +762,308 @@ static uint32_t x11_display_server_get_flags(void *data) return flags; } +#ifdef HAVE_XRANDR +static float x11_display_server_get_refresh_rate(void *data) +{ + float refresh_rate = 0.0f; + dispserv_x11_t *dispserv = (dispserv_x11_t*)data; + Display *dpy = x11_display_server_open_display(dispserv); + XRRScreenResources *screen = NULL; + + if (!dpy) + return 0.0f; + + screen = XRRGetScreenResources(dpy, DefaultRootWindow(dpy)); + + if (screen) + { + int i; + for (i = 0; i < screen->noutput; i++) + { + XRROutputInfo *info = XRRGetOutputInfo(dpy, screen, screen->outputs[i]); + + if (info->connection == RR_Connected && info->crtc) + { + int j; + XRRCrtcInfo *crtc = XRRGetCrtcInfo(dpy, screen, info->crtc); + + if (crtc && crtc->mode) + { + for (j = 0; j < screen->nmode; j++) + { + if (screen->modes[j].id == crtc->mode) + { + XRRModeInfo *mode = &screen->modes[j]; + if (mode->hTotal && mode->vTotal) + refresh_rate = (float)mode->dotClock + / ((float)mode->hTotal * (float)mode->vTotal); + break; + } + } + } + + if (crtc) + XRRFreeCrtcInfo(crtc); + XRRFreeOutputInfo(info); + break; + } + + XRRFreeOutputInfo(info); + } + + XRRFreeScreenResources(screen); + } + + x11_display_server_close_display(dispserv, dpy); + return refresh_rate; +} + +static void x11_display_server_get_video_output_size(void *data, + unsigned *width, unsigned *height, char *s, size_t len) +{ + dispserv_x11_t *dispserv = (dispserv_x11_t*)data; + Display *dpy = x11_display_server_open_display(dispserv); + XRRScreenResources *screen = NULL; + + if (!dpy) + return; + + screen = XRRGetScreenResources(dpy, DefaultRootWindow(dpy)); + + if (screen) + { + int i; + for (i = 0; i < screen->noutput; i++) + { + XRROutputInfo *info = XRRGetOutputInfo(dpy, screen, screen->outputs[i]); + + if (info->connection == RR_Connected && info->crtc) + { + XRRCrtcInfo *crtc = XRRGetCrtcInfo(dpy, screen, info->crtc); + + if (crtc) + { + if (width) + *width = crtc->width; + if (height) + *height = crtc->height; + XRRFreeCrtcInfo(crtc); + } + + XRRFreeOutputInfo(info); + break; + } + + XRRFreeOutputInfo(info); + } + + XRRFreeScreenResources(screen); + } + + x11_display_server_close_display(dispserv, dpy); +} + +static void x11_display_server_get_video_output_prev(void *data) +{ + dispserv_x11_t *dispserv = (dispserv_x11_t*)data; + Display *dpy = x11_display_server_open_display(dispserv); + XRRScreenResources *screen = NULL; + + if (!dpy) + return; + + screen = XRRGetScreenResources(dpy, DefaultRootWindow(dpy)); + + if (screen) + { + int i; + for (i = 0; i < screen->noutput; i++) + { + XRROutputInfo *info = XRRGetOutputInfo(dpy, screen, screen->outputs[i]); + + if (info->connection == RR_Connected && info->crtc) + { + XRRCrtcInfo *crtc = XRRGetCrtcInfo(dpy, screen, info->crtc); + + if (crtc && crtc->mode) + { + int j; + int cur_idx = -1; + + /* Find the current mode index in the output's mode list */ + for (j = 0; j < info->nmode; j++) + { + if (info->modes[j] == crtc->mode) + { + cur_idx = j; + break; + } + } + + /* Select previous mode */ + if (cur_idx > 0) + { + int k; + RRMode prev_mode = info->modes[cur_idx - 1]; + for (k = 0; k < screen->nmode; k++) + { + if (screen->modes[k].id == prev_mode) + { + XRRSetCrtcConfig(dpy, screen, info->crtc, + CurrentTime, crtc->x, crtc->y, + prev_mode, crtc->rotation, + crtc->outputs, crtc->noutput); + break; + } + } + } + } + + if (crtc) + XRRFreeCrtcInfo(crtc); + XRRFreeOutputInfo(info); + break; + } + + XRRFreeOutputInfo(info); + } + + XRRFreeScreenResources(screen); + } + + x11_display_server_close_display(dispserv, dpy); +} + +static void x11_display_server_get_video_output_next(void *data) +{ + dispserv_x11_t *dispserv = (dispserv_x11_t*)data; + Display *dpy = x11_display_server_open_display(dispserv); + XRRScreenResources *screen = NULL; + + if (!dpy) + return; + + screen = XRRGetScreenResources(dpy, DefaultRootWindow(dpy)); + + if (screen) + { + int i; + for (i = 0; i < screen->noutput; i++) + { + XRROutputInfo *info = XRRGetOutputInfo(dpy, screen, screen->outputs[i]); + + if (info->connection == RR_Connected && info->crtc) + { + XRRCrtcInfo *crtc = XRRGetCrtcInfo(dpy, screen, info->crtc); + + if (crtc && crtc->mode) + { + int j; + int cur_idx = -1; + + /* Find the current mode index in the output's mode list */ + for (j = 0; j < info->nmode; j++) + { + if (info->modes[j] == crtc->mode) + { + cur_idx = j; + break; + } + } + + /* Select next mode */ + if (cur_idx >= 0 && cur_idx + 1 < info->nmode) + { + int k; + RRMode next_mode = info->modes[cur_idx + 1]; + for (k = 0; k < screen->nmode; k++) + { + if (screen->modes[k].id == next_mode) + { + XRRSetCrtcConfig(dpy, screen, info->crtc, + CurrentTime, crtc->x, crtc->y, + next_mode, crtc->rotation, + crtc->outputs, crtc->noutput); + break; + } + } + } + } + + if (crtc) + XRRFreeCrtcInfo(crtc); + XRRFreeOutputInfo(info); + break; + } + + XRRFreeOutputInfo(info); + } + + XRRFreeScreenResources(screen); + } + + x11_display_server_close_display(dispserv, dpy); +} +#endif + +#ifndef HAVE_XRANDR +static void x11_display_server_get_video_output_size(void *data, + unsigned *width, unsigned *height, char *s, size_t len) +{ + Display *dpy = XOpenDisplay(NULL); + if (!dpy) + return; + if (width) + *width = DisplayWidth(dpy, DefaultScreen(dpy)); + if (height) + *height = DisplayHeight(dpy, DefaultScreen(dpy)); + XCloseDisplay(dpy); +} +#endif + +static bool x11_get_metrics(void *data, + enum display_metric_types type, float *value) +{ + unsigned screen_no = 0; + Display *dpy = NULL; + + switch (type) + { + case DISPLAY_METRIC_PIXEL_WIDTH: + dpy = (Display*)XOpenDisplay(NULL); + *value = (float)DisplayWidth(dpy, screen_no); + XCloseDisplay(dpy); + break; + case DISPLAY_METRIC_PIXEL_HEIGHT: + dpy = (Display*)XOpenDisplay(NULL); + *value = (float)DisplayHeight(dpy, screen_no); + XCloseDisplay(dpy); + break; + case DISPLAY_METRIC_MM_WIDTH: + dpy = (Display*)XOpenDisplay(NULL); + *value = (float)DisplayWidthMM(dpy, screen_no); + XCloseDisplay(dpy); + break; + case DISPLAY_METRIC_MM_HEIGHT: + dpy = (Display*)XOpenDisplay(NULL); + *value = (float)DisplayHeightMM(dpy, screen_no); + XCloseDisplay(dpy); + break; + case DISPLAY_METRIC_DPI: + dpy = (Display*)XOpenDisplay(NULL); + *value = ((((float)DisplayWidth (dpy, screen_no)) * 25.4) + / ( (float)DisplayWidthMM(dpy, screen_no))); + XCloseDisplay(dpy); + break; + case DISPLAY_METRIC_NONE: + default: + *value = 0; + return false; + } + + return true; +} + const video_display_server_t dispserv_x11 = { x11_display_server_init, x11_display_server_destroy, @@ -782,11 +1084,21 @@ const video_display_server_t dispserv_x11 = { NULL, /* set_screen_orientation */ NULL, /* get_screen_orientation */ #endif - NULL, /* get_refresh_rate */ - NULL, /* get_video_output_size */ +#ifdef HAVE_XRANDR + x11_display_server_get_refresh_rate, + x11_display_server_get_video_output_size, +#else + NULL, /* get_refresh_rate — no standard Xlib API */ + x11_display_server_get_video_output_size, +#endif +#ifdef HAVE_XRANDR + x11_display_server_get_video_output_prev, + x11_display_server_get_video_output_next, +#else NULL, /* get_video_output_prev */ NULL, /* get_video_output_next */ - NULL, /* get_metrics */ +#endif + x11_get_metrics, x11_display_server_get_flags, "x11" }; diff --git a/gfx/drivers/d3d10.c b/gfx/drivers/d3d10.c index 5b44d0bc7513..f4f8036eee53 100644 --- a/gfx/drivers/d3d10.c +++ b/gfx/drivers/d3d10.c @@ -3757,22 +3757,6 @@ static uint32_t d3d10_get_flags(void *data) return flags; } -#ifndef __WINRT__ -static void d3d10_get_video_output_prev(void *data) -{ - unsigned width = 0; - unsigned height = 0; - win32_get_video_output_prev(&width, &height); -} - -static void d3d10_get_video_output_next(void *data) -{ - unsigned width = 0; - unsigned height = 0; - win32_get_video_output_next(&width, &height); -} -#endif - static const video_poke_interface_t d3d10_poke_interface = { d3d10_get_flags, d3d10_gfx_load_texture, @@ -3782,7 +3766,7 @@ static const video_poke_interface_t d3d10_poke_interface = { /* UWP does not expose this information easily */ NULL, /* get_refresh_rate */ #else - win32_get_refresh_rate, + NULL, /* refresh_rate - handled by display server */ #endif d3d10_set_filtering, #ifdef __WINRT__ @@ -3790,9 +3774,9 @@ static const video_poke_interface_t d3d10_poke_interface = { NULL, /* get_video_output_prev */ NULL, /* get_video_output_next */ #else - win32_get_video_output_size, - d3d10_get_video_output_prev, - d3d10_get_video_output_next, + NULL, /* video_output_size - handled by display server */ + NULL, /* get_video_output_prev - handled by display server */ + NULL, /* get_video_output_next - handled by display server */ #endif NULL, /* get_current_framebuffer */ NULL, /* get_proc_address */ diff --git a/gfx/drivers/d3d11.c b/gfx/drivers/d3d11.c index 3f08e201af7c..5b8eb802b48e 100644 --- a/gfx/drivers/d3d11.c +++ b/gfx/drivers/d3d11.c @@ -5359,22 +5359,6 @@ static bool d3d11_get_hw_render_interface( return ((d3d11->flags & D3D11_ST_FLAG_HW_IFACE_ENABLE) > 0); } -#ifndef __WINRT__ -static void d3d11_get_video_output_prev(void *data) -{ - unsigned width = 0; - unsigned height = 0; - win32_get_video_output_prev(&width, &height); -} - -static void d3d11_get_video_output_next(void *data) -{ - unsigned width = 0; - unsigned height = 0; - win32_get_video_output_next(&width, &height); -} -#endif - static const video_poke_interface_t d3d11_poke_interface = { d3d11_get_flags, d3d11_gfx_load_texture, @@ -5384,7 +5368,7 @@ static const video_poke_interface_t d3d11_poke_interface = { /* UWP does not expose this information easily */ NULL, /* get_refresh_rate */ #else - win32_get_refresh_rate, + NULL, /* refresh_rate - handled by display server */ #endif d3d11_set_filtering, #ifdef __WINRT__ @@ -5392,9 +5376,9 @@ static const video_poke_interface_t d3d11_poke_interface = { NULL, /* get_video_output_prev */ NULL, /* get_video_output_next */ #else - win32_get_video_output_size, - d3d11_get_video_output_prev, - d3d11_get_video_output_next, + NULL, /* video_output_size - handled by display server */ + NULL, /* get_video_output_prev - handled by display server */ + NULL, /* get_video_output_next - handled by display server */ #endif NULL, /* get_current_framebuffer */ NULL, /* get_proc_address */ diff --git a/gfx/drivers/d3d12.c b/gfx/drivers/d3d12.c index 38c3d90373e2..1a2ce787a473 100644 --- a/gfx/drivers/d3d12.c +++ b/gfx/drivers/d3d12.c @@ -6389,22 +6389,6 @@ static bool d3d12_get_hw_render_interface( return ((d3d12->flags & D3D12_ST_FLAG_HW_IFACE_ENABLE) > 0); } -#ifndef __WINRT__ -static void d3d12_get_video_output_prev(void *data) -{ - unsigned width = 0; - unsigned height = 0; - win32_get_video_output_prev(&width, &height); -} - -static void d3d12_get_video_output_next(void *data) -{ - unsigned width = 0; - unsigned height = 0; - win32_get_video_output_next(&width, &height); -} -#endif - static bool d3d12_get_current_software_framebuffer( void* data, struct retro_framebuffer* fb) { @@ -6500,7 +6484,7 @@ static const video_poke_interface_t d3d12_poke_interface = { /* UWP does not expose this information easily */ NULL, #else - win32_get_refresh_rate, + NULL, /* refresh_rate - handled by display server */ #endif d3d12_set_filtering, #ifdef __WINRT__ @@ -6508,9 +6492,9 @@ static const video_poke_interface_t d3d12_poke_interface = { NULL, /* get_video_output_prev */ NULL, /* get_video_output_next */ #else - win32_get_video_output_size, - d3d12_get_video_output_prev, - d3d12_get_video_output_next, + NULL, /* video_output_size - handled by display server */ + NULL, /* get_video_output_prev - handled by display server */ + NULL, /* get_video_output_next - handled by display server */ #endif NULL, /* get_current_framebuffer */ NULL, /* get_proc_address */ diff --git a/gfx/drivers/d3d8.c b/gfx/drivers/d3d8.c index 818902379bec..4424618e7aee 100644 --- a/gfx/drivers/d3d8.c +++ b/gfx/drivers/d3d8.c @@ -2188,7 +2188,7 @@ static const video_poke_interface_t d3d_poke_interface = { NULL, /* get_refresh_rate */ #else /* UWP does not expose this information easily */ - win32_get_refresh_rate, + NULL, /* refresh_rate - handled by display server */ #endif NULL, /* set_filtering */ NULL, /* get_video_output_size */ diff --git a/gfx/drivers/d3d9cg.c b/gfx/drivers/d3d9cg.c index d8169e5111dd..2bdd3339eaf9 100644 --- a/gfx/drivers/d3d9cg.c +++ b/gfx/drivers/d3d9cg.c @@ -4651,7 +4651,7 @@ static const video_poke_interface_t d3d9_cg_poke_interface = { NULL, /* get_refresh_rate */ #else /* UWP does not expose this information easily */ - win32_get_refresh_rate, + NULL, /* refresh_rate - handled by display server */ #endif NULL, /* set_filtering */ NULL, /* get_video_output_size */ diff --git a/gfx/drivers/d3d9hlsl.c b/gfx/drivers/d3d9hlsl.c index 160d126c6564..4691199e5014 100644 --- a/gfx/drivers/d3d9hlsl.c +++ b/gfx/drivers/d3d9hlsl.c @@ -7965,7 +7965,7 @@ static const video_poke_interface_t d3d9_hlsl_poke_interface = { NULL, /* get_refresh_rate */ #else /* UWP does not expose this information easily */ - win32_get_refresh_rate, + NULL, /* refresh_rate - handled by display server */ #endif NULL, /* set_filtering */ NULL, /* get_video_output_size */ diff --git a/gfx/drivers/drm_gfx.c b/gfx/drivers/drm_gfx.c index 6ed16738355f..d7b138b6a9d5 100644 --- a/gfx/drivers/drm_gfx.c +++ b/gfx/drivers/drm_gfx.c @@ -919,7 +919,7 @@ static const video_poke_interface_t drm_poke_interface = { NULL, /* load_texture */ NULL, /* unload_texture */ NULL, /* set_video_mode */ - drm_get_refresh_rate, + NULL, /* refresh_rate - handled by display server */ NULL, /* set_filtering */ NULL, /* get_video_output_size */ NULL, /* get_video_output_prev */ diff --git a/gfx/drivers/exynos_gfx.c b/gfx/drivers/exynos_gfx.c index fdce6b7cb09c..57d99e55f115 100644 --- a/gfx/drivers/exynos_gfx.c +++ b/gfx/drivers/exynos_gfx.c @@ -1455,7 +1455,7 @@ static const video_poke_interface_t exynos_poke_interface = { NULL, /* load_texture */ NULL, /* unload_texture */ NULL, /* set_video_mode */ - drm_get_refresh_rate, + NULL, /* refresh_rate - handled by display server */ NULL, /* set_filtering */ NULL, /* get_video_output_size */ NULL, /* get_video_output_prev */ diff --git a/gfx/drivers/gdi_gfx.c b/gfx/drivers/gdi_gfx.c index 110c23887b5b..92a35f492b72 100644 --- a/gfx/drivers/gdi_gfx.c +++ b/gfx/drivers/gdi_gfx.c @@ -968,30 +968,18 @@ static void gdi_unload_texture(void *data, static uint32_t gdi_get_flags(void *data) { return 0; } -static void gdi_get_video_output_prev(void *data) -{ - unsigned width = 0; - unsigned height = 0; - win32_get_video_output_prev(&width, &height); -} -static void gdi_get_video_output_next(void *data) -{ - unsigned width = 0; - unsigned height = 0; - win32_get_video_output_next(&width, &height); -} static const video_poke_interface_t gdi_poke_interface = { gdi_get_flags, gdi_load_texture, gdi_unload_texture, gdi_set_video_mode, - win32_get_refresh_rate, + NULL, /* refresh_rate - handled by display server */ NULL, /* set_filtering */ - win32_get_video_output_size, - gdi_get_video_output_prev, - gdi_get_video_output_next, + NULL, /* video_output_size - handled by display server */ + NULL, /* get_video_output_prev - handled by display server */ + NULL, /* get_video_output_next - handled by display server */ NULL, /* get_current_framebuffer */ NULL, /* get_proc_address */ NULL, /* set_aspect_ratio */ diff --git a/gfx/drivers/gl1.c b/gfx/drivers/gl1.c index 6a5dd6f3be30..8f6ea5bed28e 100644 --- a/gfx/drivers/gl1.c +++ b/gfx/drivers/gl1.c @@ -2040,30 +2040,6 @@ static void gl1_set_texture_frame(void *data, } } -static void gl1_get_video_output_size(void *data, - unsigned *width, unsigned *height, char *desc, size_t desc_len) -{ - gl1_t *gl = (gl1_t*)data; - if (gl && gl->ctx_driver && gl->ctx_driver->get_video_output_size) - gl->ctx_driver->get_video_output_size( - gl->ctx_data, - width, height, desc, desc_len); -} - -static void gl1_get_video_output_prev(void *data) -{ - gl1_t *gl = (gl1_t*)data; - if (gl && gl->ctx_driver && gl->ctx_driver->get_video_output_prev) - gl->ctx_driver->get_video_output_prev(gl->ctx_data); -} - -static void gl1_get_video_output_next(void *data) -{ - gl1_t *gl = (gl1_t*)data; - if (gl && gl->ctx_driver && gl->ctx_driver->get_video_output_next) - gl->ctx_driver->get_video_output_next(gl->ctx_data); -} - static void gl1_set_video_mode(void *data, unsigned width, unsigned height, bool fullscreen) { @@ -2266,14 +2242,6 @@ static void gl1_unload_texture(void *data, glDeleteTextures(1, &glid); } -static float gl1_get_refresh_rate(void *data) -{ - float refresh_rate = 0.0f; - if (video_context_driver_get_refresh_rate(&refresh_rate)) - return refresh_rate; - return 0.0f; -} - static void gl1_set_texture_enable(void *data, bool state, bool full_screen) { gl1_t *gl1 = (gl1_t*)data; @@ -2308,11 +2276,11 @@ static const video_poke_interface_t gl1_poke_interface = { gl1_load_texture, gl1_unload_texture, gl1_set_video_mode, - gl1_get_refresh_rate, + NULL, /* refresh_rate - handled by display server */ NULL, /* set_filtering */ - gl1_get_video_output_size, - gl1_get_video_output_prev, - gl1_get_video_output_next, + NULL, /* video_output_size - handled by display server */ + NULL, /* video_output_prev - handled by display server */ + NULL, /* video_output_next - handled by display server */ NULL, /* get_current_framebuffer */ NULL, /* get_proc_address */ gl1_set_aspect_ratio, diff --git a/gfx/drivers/gl2.c b/gfx/drivers/gl2.c index f584cf3213ec..eab0a4f11378 100644 --- a/gfx/drivers/gl2.c +++ b/gfx/drivers/gl2.c @@ -5275,29 +5275,6 @@ static void gl2_apply_state_changes(void *data) gl->flags |= GL2_FLAG_SHOULD_RESIZE; } -static void gl2_get_video_output_size(void *data, - unsigned *width, unsigned *height, char *s, size_t len) -{ - gl2_t *gl = (gl2_t*)data; - if (gl && gl->ctx_driver && gl->ctx_driver->get_video_output_size) - gl->ctx_driver->get_video_output_size( - gl->ctx_data, width, height, s, len); -} - -static void gl2_get_video_output_prev(void *data) -{ - gl2_t *gl = (gl2_t*)data; - if (gl && gl->ctx_driver && gl->ctx_driver->get_video_output_prev) - gl->ctx_driver->get_video_output_prev(gl->ctx_data); -} - -static void gl2_get_video_output_next(void *data) -{ - gl2_t *gl = (gl2_t*)data; - if (gl && gl->ctx_driver && gl->ctx_driver->get_video_output_next) - gl->ctx_driver->get_video_output_next(gl->ctx_data); -} - static void video_texture_load_gl2( struct texture_image *ti, enum texture_filter_type filter_type, @@ -5437,14 +5414,6 @@ static void gl2_unload_texture(void *data, glDeleteTextures(1, &glid); } -static float gl2_get_refresh_rate(void *data) -{ - float refresh_rate = 0.0f; - if (video_context_driver_get_refresh_rate(&refresh_rate)) - return refresh_rate; - return 0.0f; -} - static uint32_t gl2_get_flags(void *data) { uint32_t flags = 0; @@ -5463,11 +5432,11 @@ static const video_poke_interface_t gl2_poke_interface = { gl2_load_texture, gl2_unload_texture, gl2_set_video_mode, - gl2_get_refresh_rate, + NULL, /* refresh_rate - handled by display server */ NULL, /* set_filtering */ - gl2_get_video_output_size, - gl2_get_video_output_prev, - gl2_get_video_output_next, + NULL, /* video_output_size - handled by display server */ + NULL, /* video_output_prev - handled by display server */ + NULL, /* video_output_next - handled by display server */ gl2_get_current_framebuffer, gl2_get_proc_address, gl2_set_aspect_ratio, diff --git a/gfx/drivers/gl3.c b/gfx/drivers/gl3.c index 284a01e477a7..a2dd7ae1b6a9 100644 --- a/gfx/drivers/gl3.c +++ b/gfx/drivers/gl3.c @@ -4545,14 +4545,6 @@ static uint32_t gl3_get_flags(void *data) return flags; } -static float gl3_get_refresh_rate(void *data) -{ - float refresh_rate; - if (video_context_driver_get_refresh_rate(&refresh_rate)) - return refresh_rate; - return 0.0f; -} - static void gl3_set_aspect_ratio(void *data, unsigned aspect_ratio_idx) { gl3_t *gl = (gl3_t*)data; @@ -4774,30 +4766,6 @@ static void gl3_set_texture_enable(void *data, bool state, bool fullscreen) gl->flags &= ~GL3_FLAG_MENU_TEXTURE_FULLSCREEN; } -static void gl3_get_video_output_size(void *data, - unsigned *width, unsigned *height, char *desc, size_t desc_len) -{ - gl3_t *gl = (gl3_t*)data; - if (gl && gl->ctx_driver && gl->ctx_driver->get_video_output_size) - gl->ctx_driver->get_video_output_size( - gl->ctx_data, - width, height, desc, desc_len); -} - -static void gl3_get_video_output_prev(void *data) -{ - gl3_t *gl = (gl3_t*)data; - if (gl && gl->ctx_driver && gl->ctx_driver->get_video_output_prev) - gl->ctx_driver->get_video_output_prev(gl->ctx_data); -} - -static void gl3_get_video_output_next(void *data) -{ - gl3_t *gl = (gl3_t*)data; - if (gl && gl->ctx_driver && gl->ctx_driver->get_video_output_next) - gl->ctx_driver->get_video_output_next(gl->ctx_data); -} - static uintptr_t gl3_get_current_framebuffer(void *data) { gl3_t *gl = (gl3_t*)data; @@ -4820,11 +4788,11 @@ static const video_poke_interface_t gl3_poke_interface = { gl3_load_texture, gl3_unload_texture, gl3_set_video_mode, - gl3_get_refresh_rate, + NULL, /* refresh_rate - handled by display server */ NULL, /* set_filtering */ - gl3_get_video_output_size, - gl3_get_video_output_prev, - gl3_get_video_output_next, + NULL, /* video_output_size - handled by display server */ + NULL, /* video_output_prev - handled by display server */ + NULL, /* video_output_next - handled by display server */ gl3_get_current_framebuffer, gl3_get_proc_address, gl3_set_aspect_ratio, diff --git a/gfx/drivers_context/android_ctx.c b/gfx/drivers_context/android_ctx.c index 53f40b3bc73c..3352ddb07403 100644 --- a/gfx/drivers_context/android_ctx.c +++ b/gfx/drivers_context/android_ctx.c @@ -307,7 +307,7 @@ const gfx_ctx_driver_t gfx_ctx_android = { NULL, /* get_video_output_size */ NULL, /* get_video_output_prev */ NULL, /* get_video_output_next */ - android_display_get_metrics, + NULL, /* get_metrics - handled by display server */ NULL, NULL, /* update_title */ android_gfx_ctx_check_window, diff --git a/gfx/drivers_context/android_vk_ctx.c b/gfx/drivers_context/android_vk_ctx.c index bd05a82cd458..c606b442f5a8 100644 --- a/gfx/drivers_context/android_vk_ctx.c +++ b/gfx/drivers_context/android_vk_ctx.c @@ -261,7 +261,7 @@ const gfx_ctx_driver_t gfx_ctx_vk_android = { NULL, /* get_video_output_size */ NULL, /* get_video_output_prev */ NULL, /* get_video_output_next */ - android_display_get_metrics, + NULL, /* get_metrics - handled by display server */ NULL, NULL, /* update_title */ android_gfx_ctx_vk_check_window, diff --git a/gfx/drivers_context/drm_ctx.c b/gfx/drivers_context/drm_ctx.c index 2c0ad91c2a6b..78119d03e735 100644 --- a/gfx/drivers_context/drm_ctx.c +++ b/gfx/drivers_context/drm_ctx.c @@ -1134,7 +1134,7 @@ const gfx_ctx_driver_t gfx_ctx_drm = { gfx_ctx_drm_swap_interval, gfx_ctx_drm_set_video_mode, gfx_ctx_drm_get_video_size, - drm_get_refresh_rate, + NULL, /* refresh_rate - handled by display server */ gfx_ctx_drm_get_video_output_size, NULL, /* get_video_output_prev */ NULL, /* get_video_output_next */ diff --git a/gfx/drivers_context/drm_go2_ctx.c b/gfx/drivers_context/drm_go2_ctx.c index 9f9e46acb571..daf5ff8fdb1e 100644 --- a/gfx/drivers_context/drm_go2_ctx.c +++ b/gfx/drivers_context/drm_go2_ctx.c @@ -400,7 +400,7 @@ const gfx_ctx_driver_t gfx_ctx_go2_drm = { gfx_ctx_go2_drm_swap_interval, gfx_ctx_go2_drm_set_video_mode, gfx_ctx_go2_drm_get_video_size, - drm_get_refresh_rate, + NULL, /* refresh_rate - handled by display server */ NULL, /* get_video_output_size */ NULL, /* get_video_output_prev */ NULL, /* get_video_output_next */ diff --git a/gfx/drivers_context/uwp_egl_ctx.c b/gfx/drivers_context/uwp_egl_ctx.c index 82523db261f7..0eeec06adcf9 100644 --- a/gfx/drivers_context/uwp_egl_ctx.c +++ b/gfx/drivers_context/uwp_egl_ctx.c @@ -283,7 +283,7 @@ const gfx_ctx_driver_t gfx_ctx_uwp = { NULL, /* get video output size */ NULL, /* get video output prev */ NULL, /* get video output next */ - win32_get_metrics, + NULL, /* metrics - handled by display server */ NULL, NULL, /* update title */ win32_check_window, diff --git a/gfx/drivers_context/w_vk_ctx.c b/gfx/drivers_context/w_vk_ctx.c index eaae3c64168c..e4759073ddb1 100644 --- a/gfx/drivers_context/w_vk_ctx.c +++ b/gfx/drivers_context/w_vk_ctx.c @@ -293,8 +293,6 @@ static uint32_t gfx_ctx_w_vk_get_flags(void *data) } static void gfx_ctx_w_vk_set_flags(void *data, uint32_t flags) { } -static void gfx_ctx_w_vk_get_video_output_prev(void *data) { } -static void gfx_ctx_w_vk_get_video_output_next(void *data) { } const gfx_ctx_driver_t gfx_ctx_w_vk = { gfx_ctx_w_vk_init, @@ -304,11 +302,11 @@ const gfx_ctx_driver_t gfx_ctx_w_vk = { gfx_ctx_w_vk_swap_interval, gfx_ctx_w_vk_set_video_mode, win32_get_video_size, - win32_get_refresh_rate, - win32_get_video_output_size, - gfx_ctx_w_vk_get_video_output_prev, - gfx_ctx_w_vk_get_video_output_next, - win32_get_metrics, + NULL, /* refresh_rate - handled by display server */ + NULL, /* video_output_size - handled by display server */ + NULL, /* get_video_output_prev - handled by display server */ + NULL, /* get_video_output_next - handled by display server */ + NULL, /* metrics - handled by display server */ NULL, video_driver_update_title, gfx_ctx_w_vk_check_window, diff --git a/gfx/drivers_context/wayland_ctx.c b/gfx/drivers_context/wayland_ctx.c index 76ea16e816cc..741f84425690 100644 --- a/gfx/drivers_context/wayland_ctx.c +++ b/gfx/drivers_context/wayland_ctx.c @@ -659,11 +659,11 @@ const gfx_ctx_driver_t gfx_ctx_wayland = { gfx_ctx_wl_set_swap_interval, gfx_ctx_wl_set_video_mode, gfx_ctx_wl_get_video_size_common, - gfx_ctx_wl_get_refresh_rate, + NULL, /* refresh_rate - handled by display server */ NULL, /* get_video_output_size */ NULL, /* get_video_output_prev */ NULL, /* get_video_output_next */ - gfx_ctx_wl_get_metrics_common, + NULL, /* metrics - handled by display server */ NULL, gfx_ctx_wl_update_title_common, gfx_ctx_wl_check_window, diff --git a/gfx/drivers_context/wayland_vk_ctx.c b/gfx/drivers_context/wayland_vk_ctx.c index 7e52ddd38bfa..a54d40ba9113 100644 --- a/gfx/drivers_context/wayland_vk_ctx.c +++ b/gfx/drivers_context/wayland_vk_ctx.c @@ -304,11 +304,11 @@ const gfx_ctx_driver_t gfx_ctx_vk_wayland = { gfx_ctx_wl_set_swap_interval, gfx_ctx_wl_set_video_mode, gfx_ctx_wl_get_video_size_common, - gfx_ctx_wl_get_refresh_rate, + NULL, /* refresh_rate - handled by display server */ NULL, /* get_video_output_size */ NULL, /* get_video_output_prev */ NULL, /* get_video_output_next */ - gfx_ctx_wl_get_metrics_common, + NULL, /* metrics - handled by display server */ NULL, gfx_ctx_wl_update_title_common, gfx_ctx_wl_check_window, diff --git a/gfx/drivers_context/wgl_ctx.c b/gfx/drivers_context/wgl_ctx.c index 3e265258e499..424328f7b5cc 100644 --- a/gfx/drivers_context/wgl_ctx.c +++ b/gfx/drivers_context/wgl_ctx.c @@ -830,8 +830,6 @@ static void gfx_ctx_wgl_set_flags(void *data, uint32_t flags) } -static void gfx_ctx_wgl_get_video_output_prev(void *data) { } -static void gfx_ctx_wgl_get_video_output_next(void *data) { } static bool gfx_ctx_wgl_create_surface(void *data) { @@ -853,7 +851,6 @@ static bool gfx_ctx_wgl_destroy_surface(void *data) /* TODO: maybe create an uwp_mesa_common.c? */ #ifdef __WINRT__ - static void win32_get_video_size(void* data, unsigned* width, unsigned* height) { @@ -864,23 +861,11 @@ static void win32_get_video_size(void* data, height = uwp_get_height(); } -void win32_get_video_output_size(void* data, unsigned* width, unsigned* height, char* desc, size_t desc_len) -{ - win32_get_video_size(data, width, height); -} - bool win32_suspend_screensaver(void* data, bool enable) { return true; } -float win32_get_refresh_rate(void* data) -{ - return 60.0; -} - -#define win32_get_refresh_rate NULL - HWND win32_get_window(void) { return (HWND)uwp_get_corewindow(); @@ -902,11 +887,11 @@ const gfx_ctx_driver_t gfx_ctx_wgl = { gfx_ctx_wgl_swap_interval, gfx_ctx_wgl_set_video_mode, win32_get_video_size, - win32_get_refresh_rate, - win32_get_video_output_size, - gfx_ctx_wgl_get_video_output_prev, - gfx_ctx_wgl_get_video_output_next, - win32_get_metrics, + NULL, /* refresh_rate - handled by display server */ + NULL, /* video_output_size - handled by display server */ + NULL, /* get_video_output_prev - handled by display server */ + NULL, /* get_video_output_next - handled by display server */ + NULL, /* metrics - handled by display server */ NULL, video_driver_update_title, win32_check_window, diff --git a/gfx/drivers_context/x_ctx.c b/gfx/drivers_context/x_ctx.c index 373d25080815..c9121d276568 100644 --- a/gfx/drivers_context/x_ctx.c +++ b/gfx/drivers_context/x_ctx.c @@ -1190,7 +1190,7 @@ const gfx_ctx_driver_t gfx_ctx_x = { NULL, /* get_video_output_size */ NULL, /* get_video_output_prev */ NULL, /* get_video_output_next */ - x11_get_metrics, + NULL, /* get_metrics - handled by display server */ NULL, x11_update_title, x11_check_window, diff --git a/gfx/drivers_context/x_vk_ctx.c b/gfx/drivers_context/x_vk_ctx.c index 82a0420070d3..9ea8dc77ba2d 100644 --- a/gfx/drivers_context/x_vk_ctx.c +++ b/gfx/drivers_context/x_vk_ctx.c @@ -582,7 +582,7 @@ const gfx_ctx_driver_t gfx_ctx_vk_x = { NULL, /* get_video_output_size */ NULL, /* get_video_output_prev */ NULL, /* get_video_output_next */ - x11_get_metrics, + NULL, /* get_metrics - handled by display server */ NULL, x11_update_title, gfx_ctx_x_vk_check_window, diff --git a/gfx/drivers_context/xegl_ctx.c b/gfx/drivers_context/xegl_ctx.c index ac769047220a..5c325630d760 100644 --- a/gfx/drivers_context/xegl_ctx.c +++ b/gfx/drivers_context/xegl_ctx.c @@ -637,7 +637,7 @@ const gfx_ctx_driver_t gfx_ctx_x_egl = NULL, /* get_video_output_size */ NULL, /* get_video_output_prev */ NULL, /* get_video_output_next */ - x11_get_metrics, + NULL, /* get_metrics - handled by display server */ NULL, x11_update_title, x11_check_window, diff --git a/gfx/gfx_display.c b/gfx/gfx_display.c index 3655f32f03dd..19200dcc541f 100644 --- a/gfx/gfx_display.c +++ b/gfx/gfx_display.c @@ -128,22 +128,6 @@ static float gfx_display_get_dpi_scale_internal( diagonal_pixels = (float)sqrt( (double)((width * width) + (height * height))); - /* TODO/FIXME: On Mac, calling video_context_driver_get_metrics() - * here causes RetroArch to crash (EXC_BAD_ACCESS). This is - * unfortunate, and needs to be fixed at the gfx context driver - * level. Until this is done, all we can do is fallback to using - * the old legacy 'magic number' scaling on Mac platforms. */ -#if !defined(HAVE_COCOATOUCH) && (defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL)) - if (true) - { - scale = (diagonal_pixels / 6.5f) / 212.0f; - scale_cached = true; - last_width = width; - last_height = height; - return scale; - } -#endif - /* Get pixel scale relative to baseline 1080p display */ pixel_scale = diagonal_pixels / (float)DIAGONAL_PIXELS_1080P; diff --git a/gfx/video_display_server.h b/gfx/video_display_server.h index ae66bc79f6d8..e31534ebab27 100644 --- a/gfx/video_display_server.h +++ b/gfx/video_display_server.h @@ -120,7 +120,9 @@ void video_display_server_restore_refresh_rate(void); enum rotation video_display_server_get_screen_orientation(void); extern const video_display_server_t dispserv_win32; +extern const video_display_server_t dispserv_uwp; extern const video_display_server_t dispserv_x11; +extern const video_display_server_t dispserv_wl; extern const video_display_server_t dispserv_kms; extern const video_display_server_t dispserv_android; extern const video_display_server_t dispserv_apple; diff --git a/gfx/video_driver.c b/gfx/video_driver.c index 33c1502d6d73..041eb3bad137 100644 --- a/gfx/video_driver.c +++ b/gfx/video_driver.c @@ -1259,16 +1259,28 @@ void* video_display_server_init(enum rarch_display_type type) case RARCH_DISPLAY_WIN32: #if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__) current_display_server = &dispserv_win32; +#elif defined(__WINRT__) + current_display_server = &dispserv_uwp; #endif break; case RARCH_DISPLAY_X11: #if defined(HAVE_X11) current_display_server = &dispserv_x11; +#endif + break; + case RARCH_DISPLAY_WAYLAND: +#if defined(HAVE_WAYLAND) + current_display_server = &dispserv_wl; #endif break; case RARCH_DISPLAY_KMS: #if defined(HAVE_KMS) current_display_server = &dispserv_kms; +#endif + break; + case RARCH_DISPLAY_OSX: +#if defined(__APPLE__) + current_display_server = &dispserv_apple; #endif break; default: @@ -1980,6 +1992,8 @@ bool video_driver_get_video_output_size(unsigned *width, unsigned *height, char { video_driver_state_t *video_st = &video_driver_st; const video_poke_interface_t *poke = video_st->poke; + if (video_display_server_get_video_output_size(width, height, s, len)) + return true; if (!poke || !poke->get_video_output_size) return false; poke->get_video_output_size(video_st->data, @@ -2243,6 +2257,8 @@ bool video_driver_get_next_video_out(void) { video_driver_state_t *video_st = &video_driver_st; const video_poke_interface_t *poke = video_st->poke; + if (video_display_server_get_video_output_next()) + return true; if (!poke || !poke->get_video_output_next) return false; poke->get_video_output_next(video_st->data); @@ -2253,6 +2269,8 @@ bool video_driver_get_prev_video_out(void) { video_driver_state_t *video_st = &video_driver_st; const video_poke_interface_t *poke = video_st->poke; + if (video_display_server_get_video_output_prev()) + return true; if (!poke || !poke->get_video_output_prev) return false; poke->get_video_output_prev(video_st->data); @@ -3443,6 +3461,8 @@ bool video_context_driver_get_metrics(gfx_ctx_metrics_t *metrics) video_driver_state_t *video_st = &video_driver_st; const gfx_ctx_driver_t *ctx = &video_st->current_video_context; void *ctx_data = (void*)video_st->context_data; + if (video_display_server_get_metrics(metrics->type, metrics->value)) + return true; if (ctx->get_metrics) return ctx->get_metrics(ctx_data, metrics->type, metrics->value); return false; @@ -3579,29 +3599,29 @@ enum gfx_ctx_api video_context_driver_get_api(void) const char *video_ident = (vid) ? vid->ident : NULL; if (string_starts_with_size(video_ident, "d3d", STRLEN_CONST("d3d"))) { - if (!memcmp(video_ident, "d3d9_hlsl", STRLEN_CONST("d3d9_hlsl") + 1)) + if (!strcmp(video_ident, "d3d9_hlsl")) return GFX_CTX_DIRECT3D9_API; - else if (!memcmp(video_ident, "d3d10", STRLEN_CONST("d3d10") + 1)) + else if (!strcmp(video_ident, "d3d10")) return GFX_CTX_DIRECT3D10_API; - else if (!memcmp(video_ident, "d3d11", STRLEN_CONST("d3d11") + 1)) + else if (!strcmp(video_ident, "d3d11")) return GFX_CTX_DIRECT3D11_API; - else if (!memcmp(video_ident, "d3d12", STRLEN_CONST("d3d12") + 1)) + else if (!strcmp(video_ident, "d3d12")) return GFX_CTX_DIRECT3D12_API; } if (string_starts_with_size(video_ident, "gl", STRLEN_CONST("gl"))) { - if (!memcmp(video_ident, "gl", STRLEN_CONST("gl") + 1)) + if (!strcmp(video_ident, "gl")) return GFX_CTX_OPENGL_API; - else if (!memcmp(video_ident, "gl1", STRLEN_CONST("gl1") + 1)) + else if (!strcmp(video_ident, "gl1")) return GFX_CTX_OPENGL_API; - else if (!memcmp(video_ident, "glcore", STRLEN_CONST("glcore") + 1)) + else if (!strcmp(video_ident, "glcore")) return GFX_CTX_OPENGL_API; } - else if (!memcmp(video_ident, "vulkan", STRLEN_CONST("vulkan") + 1)) + else if (!strcmp(video_ident, "vulkan")) return GFX_CTX_VULKAN_API; - else if (!memcmp(video_ident, "metal", STRLEN_CONST("metal") + 1)) + else if (!strcmp(video_ident, "metal")) return GFX_CTX_METAL_API; - else if (!memcmp(video_ident, "rsx", STRLEN_CONST("rsx") + 1)) + else if (!strcmp(video_ident, "rsx")) return GFX_CTX_RSX_API; return GFX_CTX_NONE; } @@ -3634,8 +3654,12 @@ bool video_shader_driver_get_current_shader(video_shader_ctx_t *shader) float video_driver_get_refresh_rate(void) { + float rate; video_driver_state_t *video_st = &video_driver_st; const video_poke_interface_t *poke = video_st->poke; + rate = video_display_server_get_refresh_rate(); + if (rate != 0.0f) + return rate; if (poke && poke->get_refresh_rate) return poke->get_refresh_rate(video_st->data); @@ -3779,10 +3803,17 @@ bool video_driver_init_internal(bool *video_is_threaded, bool verbosity_enabled) if ((max_win_width == 0) || (max_win_height == 0)) { /* Maximum window width/size *must* be non-zero; - * if all else fails, used defined default - * maximum window size */ - max_win_width = DEFAULT_WINDOW_AUTO_WIDTH_MAX; - max_win_height = DEFAULT_WINDOW_AUTO_HEIGHT_MAX; + * try querying the display server for the actual + * monitor resolution before falling back to the + * compiled-in default */ + if ( !video_display_server_get_video_output_size( + &max_win_width, &max_win_height, NULL, 0) + || (max_win_width == 0) + || (max_win_height == 0)) + { + max_win_width = DEFAULT_WINDOW_AUTO_WIDTH_MAX; + max_win_height = DEFAULT_WINDOW_AUTO_HEIGHT_MAX; + } } } @@ -4994,15 +5025,24 @@ static void video_frame_delay_auto(video_driver_state_t *video_st, video_frame_d #endif int8_t mode = 0; - /* Calculate average frame time */ + /* Calculate average frame time. + * + * The sample ring (frame_time_samples) is power-of-two sized and masked + * with (MEASURE_FRAME_TIME_SAMPLES_COUNT - 1). Wrap the read index the + * same way so that when frame_time_index is small (e.g. just after the + * ring wrapped), we correctly fetch the most recent samples from the + * tail of the buffer instead of skipping them. + * + * The caller already guarantees video_st->frame_count > frame_time_interval + * before invoking this function, so the ring is always populated by the + * time we get here. */ for (i = 1; i < frame_time_frames + 1; i++) { retro_time_t frame_time_i = 0; + uint16_t sample_index = (uint16_t) + ((frame_time_index - i) & (MEASURE_FRAME_TIME_SAMPLES_COUNT - 1)); - if (i > frame_time_index) - continue; - - frame_time_i = video_st->frame_time_samples[frame_time_index - i]; + frame_time_i = video_st->frame_time_samples[sample_index]; if (frame_time_i > frame_time_limit_cap) frame_time_i = frame_time_target; @@ -5092,7 +5132,10 @@ static void video_frame_delay_auto(video_driver_state_t *video_st, video_frame_d vfda->frame_time_target = frame_time_target; #if FRAME_DELAY_AUTO_DEBUG - if (frame_time_index > frame_time_frames) + { + /* Match the averager's wrapped read order so debug output + * reflects the samples actually used. */ + const uint16_t mask = MEASURE_FRAME_TIME_SAMPLES_COUNT - 1; RARCH_DBG("[Video] %5d / pos:%d,%d min:%d med:%d max:%d / delta:%5d = %5d %5d %5d %5d %5d %5d %5d %5d\n", frame_time_avg, count_pos, @@ -5101,15 +5144,16 @@ static void video_frame_delay_auto(video_driver_state_t *video_st, video_frame_d count_med, count_max, frame_time_max - frame_time_min, - video_st->frame_time_samples[frame_time_index - 8], - video_st->frame_time_samples[frame_time_index - 7], - video_st->frame_time_samples[frame_time_index - 6], - video_st->frame_time_samples[frame_time_index - 5], - video_st->frame_time_samples[frame_time_index - 4], - video_st->frame_time_samples[frame_time_index - 3], - video_st->frame_time_samples[frame_time_index - 2], - video_st->frame_time_samples[frame_time_index - 1] + video_st->frame_time_samples[(uint16_t)((frame_time_index - 8) & mask)], + video_st->frame_time_samples[(uint16_t)((frame_time_index - 7) & mask)], + video_st->frame_time_samples[(uint16_t)((frame_time_index - 6) & mask)], + video_st->frame_time_samples[(uint16_t)((frame_time_index - 5) & mask)], + video_st->frame_time_samples[(uint16_t)((frame_time_index - 4) & mask)], + video_st->frame_time_samples[(uint16_t)((frame_time_index - 3) & mask)], + video_st->frame_time_samples[(uint16_t)((frame_time_index - 2) & mask)], + video_st->frame_time_samples[(uint16_t)((frame_time_index - 1) & mask)] ); + } #endif } diff --git a/griffin/griffin.c b/griffin/griffin.c index 2daf4a7f3f36..562fd82ff2d3 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -298,6 +298,8 @@ VIDEO CONTEXT #if !defined(__WINRT__) #include "../gfx/display_servers/dispserv_win32.c" +#else +#include "../gfx/display_servers/dispserv_uwp.c" #endif #endif @@ -326,6 +328,7 @@ VIDEO CONTEXT #ifdef HAVE_WAYLAND #include "../gfx/drivers_context/wayland_ctx.c" +#include "../gfx/display_servers/dispserv_wl.c" #ifdef HAVE_VULKAN #include "../gfx/drivers_context/wayland_vk_ctx.c" #endif @@ -1584,12 +1587,6 @@ HTTP SERVER ============================================================ */ #if defined(HAVE_DISCORD) #include "../network/discord.c" -#if defined(_WIN32) -#include "../deps/discord-rpc/src/discord_register_win.c" -#endif -#if defined(__linux__) -#include "../deps/discord-rpc/src/discord_register_linux.c" -#endif #endif /*============================================================ diff --git a/griffin/griffin_cpp.cpp b/griffin/griffin_cpp.cpp index f7f882e7ffc4..94566aeeb7aa 100644 --- a/griffin/griffin_cpp.cpp +++ b/griffin/griffin_cpp.cpp @@ -91,20 +91,3 @@ VIDEO DRIVER #include "../deps/glslang/glslang/glslang/OSDependent/Unix/ossource.cpp" #endif #endif - -/*============================================================ -FONTS -============================================================ */ -#if defined(HAVE_DISCORD) -#include "../deps/discord-rpc/src/discord_rpc.cpp" -#include "../deps/discord-rpc/src/rpc_connection.cpp" -#include "../deps/discord-rpc/src/serialization.cpp" - -#if defined(_WIN32) -#include "../deps/discord-rpc/src/connection_win.cpp" -#endif -#if defined(__unix__) || defined(__APPLE__) -#include "../deps/discord-rpc/src/connection_unix.cpp" -#endif -#endif - diff --git a/griffin/griffin_objc.m b/griffin/griffin_objc.m index 30c8194a3102..2375a3ad7c8e 100644 --- a/griffin/griffin_objc.m +++ b/griffin/griffin_objc.m @@ -79,10 +79,6 @@ #include "../record/drivers/record_avfoundation.m" #endif -#if defined(HAVE_DISCORD) -#include "../deps/discord-rpc/src/discord_register_osx.m" -#endif - #ifdef HAVE_METAL #import "../gfx/common/metal/metal_renderer.m" #import "../gfx/drivers/metal.m" diff --git a/libretro-common/formats/png/rpng.c b/libretro-common/formats/png/rpng.c index 6a765eac02e6..159154b916d6 100644 --- a/libretro-common/formats/png/rpng.c +++ b/libretro-common/formats/png/rpng.c @@ -957,41 +957,57 @@ static void rpng_pass_geom(const struct png_ihdr *ihdr, unsigned width, unsigned height, unsigned *bpp_out, unsigned *pitch_out, size_t *pass_size) { - unsigned bpp = 0; - unsigned pitch = 0; + /* Perform pitch and pass_size arithmetic in size_t. Previously these + * were done in unsigned int, which can silently wrap on 32-bit at a + * width of ~67M for 16bpc RGBA (pitch = width*8) or, more plausibly, + * at a pitch*height product exceeding ~4 GiB — reachable today with + * a 30000x30000 16bpc-RGBA image that passes the IHDR output-size + * cap (based on the RGBA-8 output buffer) but whose 16bpc intermediate + * scanline buffer is ~6.7 GiB. A wrapped pass_size underallocates the + * inflate buffer and exposes a heap overflow during decode. + * + * The `(size_t)ihdr->width * ihdr->depth` leading term forces the + * whole expression to size_t width. Callers with `unsigned *pitch_out` + * still receive a narrowed value — safe on 64-bit where size_t is 64 + * bits, since realistic pitches fit comfortably. On 32-bit targets + * pitch_out itself has no headroom beyond UINT32_MAX, but the caller + * won't reach any allocation using pitch if the IHDR check further + * down rejects such images for their overall size. */ + size_t bpp = 0; + size_t pitch = 0; switch (ihdr->color_type) { case PNG_IHDR_COLOR_GRAY: - bpp = (ihdr->depth + 7) / 8; - pitch = (ihdr->width * ihdr->depth + 7) / 8; + bpp = ((size_t)ihdr->depth + 7) / 8; + pitch = ((size_t)ihdr->width * ihdr->depth + 7) / 8; break; case PNG_IHDR_COLOR_RGB: - bpp = (ihdr->depth * 3 + 7) / 8; - pitch = (ihdr->width * ihdr->depth * 3 + 7) / 8; + bpp = ((size_t)ihdr->depth * 3 + 7) / 8; + pitch = ((size_t)ihdr->width * ihdr->depth * 3 + 7) / 8; break; case PNG_IHDR_COLOR_PLT: - bpp = (ihdr->depth + 7) / 8; - pitch = (ihdr->width * ihdr->depth + 7) / 8; + bpp = ((size_t)ihdr->depth + 7) / 8; + pitch = ((size_t)ihdr->width * ihdr->depth + 7) / 8; break; case PNG_IHDR_COLOR_GRAY_ALPHA: - bpp = (ihdr->depth * 2 + 7) / 8; - pitch = (ihdr->width * ihdr->depth * 2 + 7) / 8; + bpp = ((size_t)ihdr->depth * 2 + 7) / 8; + pitch = ((size_t)ihdr->width * ihdr->depth * 2 + 7) / 8; break; case PNG_IHDR_COLOR_RGBA: - bpp = (ihdr->depth * 4 + 7) / 8; - pitch = (ihdr->width * ihdr->depth * 4 + 7) / 8; + bpp = ((size_t)ihdr->depth * 4 + 7) / 8; + pitch = ((size_t)ihdr->width * ihdr->depth * 4 + 7) / 8; break; default: break; } if (pass_size) - *pass_size = (pitch + 1) * ihdr->height; + *pass_size = (pitch + 1) * (size_t)ihdr->height; if (bpp_out) - *bpp_out = bpp; + *bpp_out = (unsigned)bpp; if (pitch_out) - *pitch_out = pitch; + *pitch_out = (unsigned)pitch; } static void rpng_reverse_filter_adam7_deinterlace_pass(uint32_t *data, @@ -1544,16 +1560,44 @@ bool rpng_iterate_image(rpng_t *rpng) rpng->ihdr.filter = buf[11]; rpng->ihdr.interlace = buf[12]; - if ( rpng->ihdr.width == 0 - || rpng->ihdr.height == 0 - /* Ensure multiplications don't overflow and wrap around, - * that'd give buffer overflow crashes */ - || (uint64_t)rpng->ihdr.width*rpng->ihdr.height*sizeof(uint32_t) >= 0x80000000) + /* Validate color_type + depth combination before any size + * arithmetic; rpng_pass_geom's switch relies on color_type + * being one of the five legal values. */ + if (!rpng_process_ihdr(&rpng->ihdr)) return false; - if (!rpng_process_ihdr(&rpng->ihdr)) + if (rpng->ihdr.width == 0 || rpng->ihdr.height == 0) return false; + /* Two independent size caps, both at 4 GiB: + * + * 1) Output buffer — rpng always decodes to ARGB32 regardless + * of the source depth, so the final buffer is always + * width * height * 4 bytes. + * + * 2) Intermediate inflate buffer — sized by rpng_pass_geom + * as (pitch + 1) * height. For 8bpc RGBA this matches + * the output (~4 bytes/pixel), but for 16bpc RGBA it is + * 2x (8 bytes/pixel), and palette/gray paths are smaller. + * A 30000x30000 16bpc-RGBA image passes the output cap + * (3.35 GiB) but needs a 7 GiB intermediate — reject it + * here rather than relying on malloc to fail downstream. + * + * Both caps use 64-bit arithmetic; the ULL literal keeps the + * constant unambiguously 64-bit on LLP64 (Windows) where + * unsigned long is 32-bit. rpng_pass_geom's arithmetic is + * itself size_t-wide after the prior widening commit, so the + * pass_size returned here is trustworthy. */ + { + size_t pass_size = 0; + rpng_pass_geom(&rpng->ihdr, rpng->ihdr.width, + rpng->ihdr.height, NULL, NULL, &pass_size); + if ((uint64_t)rpng->ihdr.width * rpng->ihdr.height + * sizeof(uint32_t) >= 0x100000000ULL + || (uint64_t)pass_size >= 0x100000000ULL) + return false; + } + if (rpng->ihdr.compression != 0) { #if defined(DEBUG) || defined(RPNG_TEST) diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index e5bc4a647bc8..63bf6f00124b 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -7297,11 +7297,13 @@ int action_cb_push_dropdown_item_resolution(const char *path, ++end; height = (unsigned)strtoul(end, &end, 0); - if (*end == ' ') + /* Skip whitespace and opening parenthesis: "2160 (120 Hz)" → "120 Hz)" */ + while (*end == ' ' || *end == '(') ++end; refreshrate = (float)strtod(end, NULL); + if (video_display_server_set_resolution(width, height, floor(refreshrate), refreshrate, 0, 0, 0, 0)) { diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index fd7fbec42be6..7c21adaf7206 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -260,12 +260,12 @@ static int filebrowser_parse( if (string_is_equal(label, MENU_ENUM_LABEL_SCAN_FILE_STR)) filter_ext = false; - if ( memcmp(label, "database_manager_list", STRLEN_CONST("database_manager_list")) == 0 + if ( !strcmp(label, "database_manager_list") #ifdef IOS - || memcmp(label, "video_filter", STRLEN_CONST("video_filter")) == 0 - || memcmp(label, "audio_dsp_plugin", STRLEN_CONST("audio_dsp_plugin")) == 0 + || !strcmp(label, "video_filter") + || !strcmp(label, "audio_dsp_plugin") #endif - || memcmp(label, "cursor_manager_list", STRLEN_CONST("cursor_manager_list")) == 0) + || !strcmp(label, "cursor_manager_list")) allow_parent_directory = false; if (filebrowser_type == FILEBROWSER_SELECT_FILE_SUBSYSTEM) diff --git a/network/discord.c b/network/discord.c index 642b7c7ec210..325ce3f1bcaf 100644 --- a/network/discord.c +++ b/network/discord.c @@ -1,6 +1,6 @@ /* RetroArch - A frontend for libretro. * Copyright (C) 2011-2021 - Daniel De Matteis - * Copyright (C) 2016-2019 - Andr�s Su�rez + * Copyright (C) 2016-2019 - Andres Suarez * * RetroArch 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 Found- @@ -14,13 +14,53 @@ * If not, see . */ +/* This file folds in the former deps/discord-rpc C++ library as pure C89. + * + * Design notes: + * - No background IO thread. The RetroArch runloop calls discord_run_callbacks() + * every frame, which drives reads/writes/reconnects on the main thread. All + * atomics/mutexes/condvars from the upstream library are therefore removed. + * - No auto-register. Discord_Register() is kept as an exported no-op stub so + * the existing init code path still links; the upstream per-OS desktop-file + * / registry logic is dropped. + * - Unix socket / Windows named-pipe backends are gated by #ifdef _WIN32. + * - JSON read/write use libretro-common's formats/rjson.h directly, without + * the C++ RAII wrappers (JsonWriter/JsonDocument/JsonReader). + */ + +#include +#include +#include +#include +#include +#include + +#include +#include #include +#include #include #include #include #include +#include #include