discord-rpc: Formatting
This commit is contained in:
42
3rdparty/discord-rpc/CMakeLists.txt
vendored
42
3rdparty/discord-rpc/CMakeLists.txt
vendored
@@ -1 +1,41 @@
|
|||||||
add_subdirectory(src)
|
set(DISCORD_RPC_SOURCES
|
||||||
|
discord_rpc.h
|
||||||
|
discord_register.h
|
||||||
|
discord_rpc.cpp
|
||||||
|
discord_rpc_connection.h
|
||||||
|
discord_rpc_connection.cpp
|
||||||
|
discord_serialization.h
|
||||||
|
discord_serialization.cpp
|
||||||
|
discord_connection.h
|
||||||
|
discord_backoff.h
|
||||||
|
discord_msg_queue.h
|
||||||
|
)
|
||||||
|
|
||||||
|
if(UNIX)
|
||||||
|
list(APPEND DISCORD_RPC_SOURCES discord_connection_unix.cpp)
|
||||||
|
if(APPLE)
|
||||||
|
list(APPEND DISCORD_RPC_SOURCES discord_register_osx.m)
|
||||||
|
add_definitions(-DDISCORD_OSX)
|
||||||
|
else()
|
||||||
|
list(APPEND DISCORD_RPC_SOURCES discord_register_linux.cpp)
|
||||||
|
add_definitions(-DDISCORD_LINUX)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
list(APPEND DISCORD_RPC_SOURCES discord_connection_win.cpp discord_register_win.cpp)
|
||||||
|
add_definitions(-DDISCORD_WINDOWS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_library(discord-rpc STATIC ${DISCORD_RPC_SOURCES})
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
target_link_libraries(discord-rpc PRIVATE "-framework AppKit")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
target_link_libraries(discord-rpc PRIVATE psapi advapi32)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_include_directories(discord-rpc SYSTEM PRIVATE ${RapidJSON_INCLUDE_DIRS})
|
||||||
|
target_include_directories(discord-rpc PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ int GetProcessId();
|
|||||||
struct BaseConnection {
|
struct BaseConnection {
|
||||||
static BaseConnection *Create();
|
static BaseConnection *Create();
|
||||||
static void Destroy(BaseConnection *&);
|
static void Destroy(BaseConnection *&);
|
||||||
bool isOpen { false };
|
bool isOpen = false;
|
||||||
bool Open();
|
bool Open();
|
||||||
bool Close();
|
bool Close();
|
||||||
bool Write(const void *data, size_t length);
|
bool Write(const void *data, size_t length);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "connection.h"
|
#include "discord_connection.h"
|
||||||
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -28,28 +28,34 @@ static int MsgFlags = 0;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const char *GetTempPath() {
|
static const char *GetTempPath() {
|
||||||
|
|
||||||
const char *temp = getenv("XDG_RUNTIME_DIR");
|
const char *temp = getenv("XDG_RUNTIME_DIR");
|
||||||
temp = temp ? temp : getenv("TMPDIR");
|
temp = temp ? temp : getenv("TMPDIR");
|
||||||
temp = temp ? temp : getenv("TMP");
|
temp = temp ? temp : getenv("TMP");
|
||||||
temp = temp ? temp : getenv("TEMP");
|
temp = temp ? temp : getenv("TEMP");
|
||||||
temp = temp ? temp : "/tmp";
|
temp = temp ? temp : "/tmp";
|
||||||
|
|
||||||
return temp;
|
return temp;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static*/ BaseConnection *BaseConnection::Create() {
|
BaseConnection *BaseConnection::Create() {
|
||||||
PipeAddr.sun_family = AF_UNIX;
|
PipeAddr.sun_family = AF_UNIX;
|
||||||
return &Connection;
|
return &Connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static*/ void BaseConnection::Destroy(BaseConnection *&c) {
|
void BaseConnection::Destroy(BaseConnection *&c) {
|
||||||
auto self = reinterpret_cast<BaseConnectionUnix *>(c);
|
|
||||||
|
auto self = reinterpret_cast<BaseConnectionUnix*>(c);
|
||||||
self->Close();
|
self->Close();
|
||||||
c = nullptr;
|
c = nullptr;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseConnection::Open() {
|
bool BaseConnection::Open() {
|
||||||
|
|
||||||
const char *tempPath = GetTempPath();
|
const char *tempPath = GetTempPath();
|
||||||
auto self = reinterpret_cast<BaseConnectionUnix *>(this);
|
auto self = reinterpret_cast<BaseConnectionUnix*>(this);
|
||||||
self->sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
self->sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
if (self->sock == -1) {
|
if (self->sock == -1) {
|
||||||
return false;
|
return false;
|
||||||
@@ -61,8 +67,7 @@ bool BaseConnection::Open() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int pipeNum = 0; pipeNum < 10; ++pipeNum) {
|
for (int pipeNum = 0; pipeNum < 10; ++pipeNum) {
|
||||||
snprintf(
|
snprintf(PipeAddr.sun_path, sizeof(PipeAddr.sun_path), "%s/discord-ipc-%d", tempPath, pipeNum);
|
||||||
PipeAddr.sun_path, sizeof(PipeAddr.sun_path), "%s/discord-ipc-%d", tempPath, pipeNum);
|
|
||||||
int err = connect(self->sock, reinterpret_cast<const sockaddr*>(&PipeAddr), sizeof(PipeAddr));
|
int err = connect(self->sock, reinterpret_cast<const sockaddr*>(&PipeAddr), sizeof(PipeAddr));
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
self->isOpen = true;
|
self->isOpen = true;
|
||||||
@@ -70,10 +75,13 @@ bool BaseConnection::Open() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self->Close();
|
self->Close();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseConnection::Close() {
|
bool BaseConnection::Close() {
|
||||||
|
|
||||||
auto self = reinterpret_cast<BaseConnectionUnix *>(this);
|
auto self = reinterpret_cast<BaseConnectionUnix *>(this);
|
||||||
if (self->sock == -1) {
|
if (self->sock == -1) {
|
||||||
return false;
|
return false;
|
||||||
@@ -81,11 +89,14 @@ bool BaseConnection::Close() {
|
|||||||
close(self->sock);
|
close(self->sock);
|
||||||
self->sock = -1;
|
self->sock = -1;
|
||||||
self->isOpen = false;
|
self->isOpen = false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseConnection::Write(const void *data, size_t length) {
|
bool BaseConnection::Write(const void *data, size_t length) {
|
||||||
auto self = reinterpret_cast<BaseConnectionUnix *>(this);
|
|
||||||
|
auto self = reinterpret_cast<BaseConnectionUnix*>(this);
|
||||||
|
|
||||||
if (self->sock == -1) {
|
if (self->sock == -1) {
|
||||||
return false;
|
return false;
|
||||||
@@ -95,11 +106,14 @@ bool BaseConnection::Write(const void *data, size_t length) {
|
|||||||
if (sentBytes < 0) {
|
if (sentBytes < 0) {
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
return sentBytes == static_cast<ssize_t>(length);
|
return sentBytes == static_cast<ssize_t>(length);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseConnection::Read(void *data, size_t length) {
|
bool BaseConnection::Read(void *data, size_t length) {
|
||||||
auto self = reinterpret_cast<BaseConnectionUnix *>(this);
|
|
||||||
|
auto self = reinterpret_cast<BaseConnectionUnix*>(this);
|
||||||
|
|
||||||
if (self->sock == -1) {
|
if (self->sock == -1) {
|
||||||
return false;
|
return false;
|
||||||
@@ -115,7 +129,9 @@ bool BaseConnection::Read(void *data, size_t length) {
|
|||||||
else if (res == 0) {
|
else if (res == 0) {
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
return static_cast<size_t>(res) == length;
|
return static_cast<size_t>(res) == length;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace discord_rpc
|
} // namespace discord_rpc
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
#include "connection.h"
|
#include "discord_connection.h"
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#define NOMCX
|
#define NOMCX
|
||||||
#define NOSERVICE
|
#define NOSERVICE
|
||||||
#define NOIME
|
#define NOIME
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
@@ -19,24 +20,26 @@ struct BaseConnectionWin : public BaseConnection {
|
|||||||
|
|
||||||
static BaseConnectionWin Connection;
|
static BaseConnectionWin Connection;
|
||||||
|
|
||||||
/*static*/ BaseConnection *BaseConnection::Create() {
|
BaseConnection *BaseConnection::Create() {
|
||||||
return &Connection;
|
return &Connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static*/ void BaseConnection::Destroy(BaseConnection *&c) {
|
void BaseConnection::Destroy(BaseConnection *&c) {
|
||||||
|
|
||||||
auto self = reinterpret_cast<BaseConnectionWin*>(c);
|
auto self = reinterpret_cast<BaseConnectionWin*>(c);
|
||||||
self->Close();
|
self->Close();
|
||||||
c = nullptr;
|
c = nullptr;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseConnection::Open() {
|
bool BaseConnection::Open() {
|
||||||
|
|
||||||
wchar_t pipeName[] { L"\\\\?\\pipe\\discord-ipc-0" };
|
wchar_t pipeName[] { L"\\\\?\\pipe\\discord-ipc-0" };
|
||||||
const size_t pipeDigit = sizeof(pipeName) / sizeof(wchar_t) - 2;
|
const size_t pipeDigit = sizeof(pipeName) / sizeof(wchar_t) - 2;
|
||||||
pipeName[pipeDigit] = L'0';
|
pipeName[pipeDigit] = L'0';
|
||||||
auto self = reinterpret_cast<BaseConnectionWin *>(this);
|
auto self = reinterpret_cast<BaseConnectionWin *>(this);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
self->pipe = ::CreateFileW(
|
self->pipe = ::CreateFileW(pipeName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||||
pipeName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
|
|
||||||
if (self->pipe != INVALID_HANDLE_VALUE) {
|
if (self->pipe != INVALID_HANDLE_VALUE) {
|
||||||
self->isOpen = true;
|
self->isOpen = true;
|
||||||
return true;
|
return true;
|
||||||
@@ -57,17 +60,22 @@ bool BaseConnection::Open() {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseConnection::Close() {
|
bool BaseConnection::Close() {
|
||||||
|
|
||||||
auto self = reinterpret_cast<BaseConnectionWin *>(this);
|
auto self = reinterpret_cast<BaseConnectionWin *>(this);
|
||||||
::CloseHandle(self->pipe);
|
::CloseHandle(self->pipe);
|
||||||
self->pipe = INVALID_HANDLE_VALUE;
|
self->pipe = INVALID_HANDLE_VALUE;
|
||||||
self->isOpen = false;
|
self->isOpen = false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseConnection::Write(const void *data, size_t length) {
|
bool BaseConnection::Write(const void *data, size_t length) {
|
||||||
|
|
||||||
if (length == 0) {
|
if (length == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -85,11 +93,13 @@ bool BaseConnection::Write(const void *data, size_t length) {
|
|||||||
}
|
}
|
||||||
const DWORD bytesLength = static_cast<DWORD>(length);
|
const DWORD bytesLength = static_cast<DWORD>(length);
|
||||||
DWORD bytesWritten = 0;
|
DWORD bytesWritten = 0;
|
||||||
return ::WriteFile(self->pipe, data, bytesLength, &bytesWritten, nullptr) == TRUE &&
|
|
||||||
bytesWritten == bytesLength;
|
return ::WriteFile(self->pipe, data, bytesLength, &bytesWritten, nullptr) == TRUE && bytesWritten == bytesLength;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseConnection::Read(void *data, size_t length) {
|
bool BaseConnection::Read(void *data, size_t length) {
|
||||||
|
|
||||||
assert(data);
|
assert(data);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return false;
|
return false;
|
||||||
@@ -119,7 +129,9 @@ bool BaseConnection::Read(void *data, size_t length) {
|
|||||||
else {
|
else {
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace discord_rpc
|
} // namespace discord_rpc
|
||||||
@@ -5,7 +5,6 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void Discord_Register(const char *applicationId, const char *command);
|
void Discord_Register(const char *applicationId, const char *command);
|
||||||
void Discord_RegisterSteamGame(const char *applicationId, const char *steamId);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
@@ -24,8 +24,9 @@ static bool Mkdir(const char *path) {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// we want to register games so we can run them from Discord client as discord-<appid>://
|
// We want to register games so we can run them from Discord client as discord-<appid>://
|
||||||
extern "C" void Discord_Register(const char *applicationId, const char *command) {
|
extern "C" void Discord_Register(const char *applicationId, const char *command) {
|
||||||
|
|
||||||
// Add a desktop file and update some mime handlers so that xdg-open does the right thing.
|
// Add a desktop file and update some mime handlers so that xdg-open does the right thing.
|
||||||
|
|
||||||
const char *home = getenv("HOME");
|
const char *home = getenv("HOME");
|
||||||
@@ -33,9 +34,9 @@ extern "C" void Discord_Register(const char *applicationId, const char *command)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char exePath[1024];
|
char exePath[1024]{};
|
||||||
if (!command || !command[0]) {
|
if (!command || !command[0]) {
|
||||||
ssize_t size = readlink("/proc/self/exe", exePath, sizeof(exePath));
|
const ssize_t size = readlink("/proc/self/exe", exePath, sizeof(exePath));
|
||||||
if (size <= 0 || size >= static_cast<ssize_t>(sizeof(exePath))) {
|
if (size <= 0 || size >= static_cast<ssize_t>(sizeof(exePath))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -50,17 +51,16 @@ extern "C" void Discord_Register(const char *applicationId, const char *command)
|
|||||||
"NoDisplay=true\n"
|
"NoDisplay=true\n"
|
||||||
"Categories=Discord;Games;\n"
|
"Categories=Discord;Games;\n"
|
||||||
"MimeType=x-scheme-handler/discord-%s;\n";
|
"MimeType=x-scheme-handler/discord-%s;\n";
|
||||||
char desktopFile[2048];
|
char desktopFile[2048]{};
|
||||||
int fileLen = snprintf(
|
int fileLen = snprintf(desktopFile, sizeof(desktopFile), desktopFileFormat, applicationId, command, applicationId);
|
||||||
desktopFile, sizeof(desktopFile), desktopFileFormat, applicationId, command, applicationId);
|
|
||||||
if (fileLen <= 0) {
|
if (fileLen <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char desktopFilename[256];
|
char desktopFilename[256]{};
|
||||||
(void)snprintf(desktopFilename, sizeof(desktopFilename), "/discord-%s.desktop", applicationId);
|
(void)snprintf(desktopFilename, sizeof(desktopFilename), "/discord-%s.desktop", applicationId);
|
||||||
|
|
||||||
char desktopFilePath[1024];
|
char desktopFilePath[1024]{};
|
||||||
(void)snprintf(desktopFilePath, sizeof(desktopFilePath), "%s/.local", home);
|
(void)snprintf(desktopFilePath, sizeof(desktopFilePath), "%s/.local", home);
|
||||||
if (!Mkdir(desktopFilePath)) {
|
if (!Mkdir(desktopFilePath)) {
|
||||||
return;
|
return;
|
||||||
@@ -84,7 +84,7 @@ extern "C" void Discord_Register(const char *applicationId, const char *command)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char xdgMimeCommand[1024];
|
char xdgMimeCommand[1024]{};
|
||||||
snprintf(xdgMimeCommand,
|
snprintf(xdgMimeCommand,
|
||||||
sizeof(xdgMimeCommand),
|
sizeof(xdgMimeCommand),
|
||||||
"xdg-mime default discord-%s.desktop x-scheme-handler/discord-%s",
|
"xdg-mime default discord-%s.desktop x-scheme-handler/discord-%s",
|
||||||
@@ -93,11 +93,5 @@ extern "C" void Discord_Register(const char *applicationId, const char *command)
|
|||||||
if (system(xdgMimeCommand) < 0) {
|
if (system(xdgMimeCommand) < 0) {
|
||||||
fprintf(stderr, "Failed to register mime handler\n");
|
fprintf(stderr, "Failed to register mime handler\n");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void Discord_RegisterSteamGame(const char *applicationId,
|
|
||||||
const char *steamId) {
|
|
||||||
char command[256];
|
|
||||||
sprintf(command, "xdg-open steam://rungameid/%s", steamId);
|
|
||||||
Discord_Register(applicationId, command);
|
|
||||||
}
|
}
|
||||||
76
3rdparty/discord-rpc/discord_register_osx.m
vendored
Normal file
76
3rdparty/discord-rpc/discord_register_osx.m
vendored
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#import <AppKit/AppKit.h>
|
||||||
|
|
||||||
|
#include "discord_register.h"
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -46,12 +46,8 @@ static HRESULT StringCbPrintfW(LPWSTR pszDest, size_t cbDest, LPCWSTR pszFormat,
|
|||||||
#endif
|
#endif
|
||||||
#define RegSetKeyValueW regset
|
#define RegSetKeyValueW regset
|
||||||
|
|
||||||
static LSTATUS regset(HKEY hkey,
|
static LSTATUS regset(HKEY hkey, LPCWSTR subkey, LPCWSTR name, DWORD type, const void *data, DWORD len) {
|
||||||
LPCWSTR subkey,
|
|
||||||
LPCWSTR name,
|
|
||||||
DWORD type,
|
|
||||||
const void *data,
|
|
||||||
DWORD len) {
|
|
||||||
HKEY htkey = hkey, hsubkey = nullptr;
|
HKEY htkey = hkey, hsubkey = nullptr;
|
||||||
LSTATUS ret;
|
LSTATUS ret;
|
||||||
if (subkey && subkey[0]) {
|
if (subkey && subkey[0]) {
|
||||||
@@ -64,16 +60,18 @@ static LSTATUS regset(HKEY hkey,
|
|||||||
if (hsubkey && hsubkey != hkey)
|
if (hsubkey && hsubkey != hkey)
|
||||||
RegCloseKey(hsubkey);
|
RegCloseKey(hsubkey);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Discord_RegisterW(const wchar_t *applicationId, const wchar_t *command) {
|
static void Discord_RegisterW(const wchar_t *applicationId, const wchar_t *command) {
|
||||||
|
|
||||||
// https://msdn.microsoft.com/en-us/library/aa767914(v=vs.85).aspx
|
// https://msdn.microsoft.com/en-us/library/aa767914(v=vs.85).aspx
|
||||||
// we want to register games so we can run them as discord-<appid>://
|
// we want to register games so we can run them as discord-<appid>://
|
||||||
// Update the HKEY_CURRENT_USER, because it doesn't seem to require special permissions.
|
// Update the HKEY_CURRENT_USER, because it doesn't seem to require special permissions.
|
||||||
|
|
||||||
wchar_t exeFilePath[MAX_PATH];
|
wchar_t exeFilePath[MAX_PATH]{};
|
||||||
DWORD exeLen = GetModuleFileNameW(nullptr, exeFilePath, MAX_PATH);
|
DWORD exeLen = GetModuleFileNameW(nullptr, exeFilePath, MAX_PATH);
|
||||||
wchar_t openCommand[1024];
|
wchar_t openCommand[1024]{};
|
||||||
|
|
||||||
if (command && command[0]) {
|
if (command && command[0]) {
|
||||||
StringCbPrintfW(openCommand, sizeof(openCommand), L"%s", command);
|
StringCbPrintfW(openCommand, sizeof(openCommand), L"%s", command);
|
||||||
@@ -83,18 +81,16 @@ static void Discord_RegisterW(const wchar_t *applicationId, const wchar_t *comma
|
|||||||
StringCbPrintfW(openCommand, sizeof(openCommand), L"%s", exeFilePath);
|
StringCbPrintfW(openCommand, sizeof(openCommand), L"%s", exeFilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
wchar_t protocolName[64];
|
wchar_t protocolName[64]{};
|
||||||
StringCbPrintfW(protocolName, sizeof(protocolName), L"discord-%s", applicationId);
|
StringCbPrintfW(protocolName, sizeof(protocolName), L"discord-%s", applicationId);
|
||||||
wchar_t protocolDescription[128];
|
wchar_t protocolDescription[128]{};
|
||||||
StringCbPrintfW(
|
StringCbPrintfW(protocolDescription, sizeof(protocolDescription), L"URL:Run game %s protocol", applicationId);
|
||||||
protocolDescription, sizeof(protocolDescription), L"URL:Run game %s protocol", applicationId);
|
|
||||||
wchar_t urlProtocol = 0;
|
wchar_t urlProtocol = 0;
|
||||||
|
|
||||||
wchar_t keyName[256];
|
wchar_t keyName[256]{};
|
||||||
StringCbPrintfW(keyName, sizeof(keyName), L"Software\\Classes\\%s", protocolName);
|
StringCbPrintfW(keyName, sizeof(keyName), L"Software\\Classes\\%s", protocolName);
|
||||||
HKEY key;
|
HKEY key;
|
||||||
auto status =
|
auto status = RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, nullptr, 0, KEY_WRITE, nullptr, &key, nullptr);
|
||||||
RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, nullptr, 0, KEY_WRITE, nullptr, &key, nullptr);
|
|
||||||
if (status != ERROR_SUCCESS) {
|
if (status != ERROR_SUCCESS) {
|
||||||
fprintf(stderr, "Error creating key\n");
|
fprintf(stderr, "Error creating key\n");
|
||||||
return;
|
return;
|
||||||
@@ -102,8 +98,7 @@ static void Discord_RegisterW(const wchar_t *applicationId, const wchar_t *comma
|
|||||||
DWORD len;
|
DWORD len;
|
||||||
LSTATUS result;
|
LSTATUS result;
|
||||||
len = static_cast<DWORD>(lstrlenW(protocolDescription) + 1);
|
len = static_cast<DWORD>(lstrlenW(protocolDescription) + 1);
|
||||||
result =
|
result = RegSetKeyValueW(key, nullptr, nullptr, REG_SZ, protocolDescription, len * sizeof(wchar_t));
|
||||||
RegSetKeyValueW(key, nullptr, nullptr, REG_SZ, protocolDescription, len * sizeof(wchar_t));
|
|
||||||
if (FAILED(result)) {
|
if (FAILED(result)) {
|
||||||
fprintf(stderr, "Error writing description\n");
|
fprintf(stderr, "Error writing description\n");
|
||||||
}
|
}
|
||||||
@@ -114,26 +109,26 @@ static void Discord_RegisterW(const wchar_t *applicationId, const wchar_t *comma
|
|||||||
fprintf(stderr, "Error writing description\n");
|
fprintf(stderr, "Error writing description\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
result = RegSetKeyValueW(
|
result = RegSetKeyValueW(key, L"DefaultIcon", nullptr, REG_SZ, exeFilePath, (exeLen + 1) * sizeof(wchar_t));
|
||||||
key, L"DefaultIcon", nullptr, REG_SZ, exeFilePath, (exeLen + 1) * sizeof(wchar_t));
|
|
||||||
if (FAILED(result)) {
|
if (FAILED(result)) {
|
||||||
fprintf(stderr, "Error writing icon\n");
|
fprintf(stderr, "Error writing icon\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
len = static_cast<DWORD>(lstrlenW(openCommand) + 1);
|
len = static_cast<DWORD>(lstrlenW(openCommand) + 1);
|
||||||
result = RegSetKeyValueW(
|
result = RegSetKeyValueW(key, L"shell\\open\\command", nullptr, REG_SZ, openCommand, len * sizeof(wchar_t));
|
||||||
key, L"shell\\open\\command", nullptr, REG_SZ, openCommand, len * sizeof(wchar_t));
|
|
||||||
if (FAILED(result)) {
|
if (FAILED(result)) {
|
||||||
fprintf(stderr, "Error writing command\n");
|
fprintf(stderr, "Error writing command\n");
|
||||||
}
|
}
|
||||||
RegCloseKey(key);
|
RegCloseKey(key);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void Discord_Register(const char *applicationId, const char *command) {
|
extern "C" void Discord_Register(const char *applicationId, const char *command) {
|
||||||
wchar_t appId[32];
|
|
||||||
|
wchar_t appId[32]{};
|
||||||
MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32);
|
MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32);
|
||||||
|
|
||||||
wchar_t openCommand[1024];
|
wchar_t openCommand[1024]{};
|
||||||
const wchar_t *wcommand = nullptr;
|
const wchar_t *wcommand = nullptr;
|
||||||
if (command && command[0]) {
|
if (command && command[0]) {
|
||||||
const auto commandBufferLen = sizeof(openCommand) / sizeof(*openCommand);
|
const auto commandBufferLen = sizeof(openCommand) / sizeof(*openCommand);
|
||||||
@@ -142,41 +137,6 @@ extern "C" void Discord_Register(const char *applicationId, const char *command)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Discord_RegisterW(appId, wcommand);
|
Discord_RegisterW(appId, wcommand);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void Discord_RegisterSteamGame(const char *applicationId,
|
|
||||||
const char *steamId) {
|
|
||||||
wchar_t appId[32];
|
|
||||||
MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32);
|
|
||||||
|
|
||||||
wchar_t wSteamId[32];
|
|
||||||
MultiByteToWideChar(CP_UTF8, 0, steamId, -1, wSteamId, 32);
|
|
||||||
|
|
||||||
HKEY key;
|
|
||||||
auto 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
wchar_t steamPath[MAX_PATH];
|
|
||||||
DWORD pathBytes = sizeof(steamPath);
|
|
||||||
status = RegQueryValueExW(key, L"SteamExe", nullptr, nullptr, (BYTE *)steamPath, &pathBytes);
|
|
||||||
RegCloseKey(key);
|
|
||||||
if (status != ERROR_SUCCESS || pathBytes < 1) {
|
|
||||||
fprintf(stderr, "Error reading SteamExe key\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD pathChars = pathBytes / sizeof(wchar_t);
|
|
||||||
for (DWORD i = 0; i < pathChars; ++i) {
|
|
||||||
if (steamPath[i] == L'/') {
|
|
||||||
steamPath[i] = L'\\';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wchar_t command[1024];
|
|
||||||
StringCbPrintfW(command, sizeof(command), L"\"%s\" steam://rungameid/%s", steamPath, wSteamId);
|
|
||||||
|
|
||||||
Discord_RegisterW(appId, command);
|
|
||||||
}
|
|
||||||
@@ -1,18 +1,16 @@
|
|||||||
#include "discord_rpc.h"
|
|
||||||
|
|
||||||
#include "backoff.h"
|
|
||||||
#include "discord_register.h"
|
|
||||||
#include "msg_queue.h"
|
|
||||||
#include "rpc_connection.h"
|
|
||||||
#include "serialization.h"
|
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
#include "discord_rpc.h"
|
||||||
|
#include "discord_backoff.h"
|
||||||
|
#include "discord_register.h"
|
||||||
|
#include "discord_msg_queue.h"
|
||||||
|
#include "discord_rpc_connection.h"
|
||||||
|
#include "discord_serialization.h"
|
||||||
|
|
||||||
namespace discord_rpc {
|
namespace discord_rpc {
|
||||||
|
|
||||||
constexpr size_t MaxMessageSize { 16 * 1024 };
|
constexpr size_t MaxMessageSize { 16 * 1024 };
|
||||||
@@ -67,8 +65,7 @@ static MsgQueue<QueuedMessage, MessageQueueSize> SendQueue;
|
|||||||
static MsgQueue<User, JoinQueueSize> JoinAskQueue;
|
static MsgQueue<User, JoinQueueSize> JoinAskQueue;
|
||||||
static User connectedUser;
|
static User connectedUser;
|
||||||
|
|
||||||
// We want to auto connect, and retry on failure, but not as fast as possible. This does expoential
|
// We want to auto connect, and retry on failure, but not as fast as possible. This does expoential backoff from 0.5 seconds to 1 minute
|
||||||
// backoff from 0.5 seconds to 1 minute
|
|
||||||
static Backoff ReconnectTimeMs(500, 60 * 1000);
|
static Backoff ReconnectTimeMs(500, 60 * 1000);
|
||||||
static auto NextConnect = std::chrono::system_clock::now();
|
static auto NextConnect = std::chrono::system_clock::now();
|
||||||
static int Pid { 0 };
|
static int Pid { 0 };
|
||||||
@@ -111,11 +108,13 @@ class IoThreadHolder {
|
|||||||
static IoThreadHolder *IoThread { nullptr };
|
static IoThreadHolder *IoThread { nullptr };
|
||||||
|
|
||||||
static void UpdateReconnectTime() {
|
static void UpdateReconnectTime() {
|
||||||
NextConnect = std::chrono::system_clock::now() +
|
|
||||||
std::chrono::duration<int64_t, std::milli> { ReconnectTimeMs.nextDelay() };
|
NextConnect = std::chrono::system_clock::now() + std::chrono::duration<int64_t, std::milli> { ReconnectTimeMs.nextDelay() };
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Discord_UpdateConnection(void) {
|
static void Discord_UpdateConnection() {
|
||||||
|
|
||||||
if (!Connection) {
|
if (!Connection) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -217,54 +216,54 @@ static void Discord_UpdateConnection(void) {
|
|||||||
SendQueue.CommitSend();
|
SendQueue.CommitSend();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SignalIOActivity() {
|
static void SignalIOActivity() {
|
||||||
|
|
||||||
if (IoThread != nullptr) {
|
if (IoThread != nullptr) {
|
||||||
IoThread->Notify();
|
IoThread->Notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool RegisterForEvent(const char *evtName) {
|
static bool RegisterForEvent(const char *evtName) {
|
||||||
|
|
||||||
auto qmessage = SendQueue.GetNextAddMessage();
|
auto qmessage = SendQueue.GetNextAddMessage();
|
||||||
if (qmessage) {
|
if (qmessage) {
|
||||||
qmessage->length =
|
qmessage->length = JsonWriteSubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName);
|
||||||
JsonWriteSubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName);
|
|
||||||
SendQueue.CommitAdd();
|
SendQueue.CommitAdd();
|
||||||
SignalIOActivity();
|
SignalIOActivity();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool DeregisterForEvent(const char *evtName) {
|
static bool DeregisterForEvent(const char *evtName) {
|
||||||
|
|
||||||
auto qmessage = SendQueue.GetNextAddMessage();
|
auto qmessage = SendQueue.GetNextAddMessage();
|
||||||
if (qmessage) {
|
if (qmessage) {
|
||||||
qmessage->length =
|
qmessage->length = JsonWriteUnsubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName);
|
||||||
JsonWriteUnsubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName);
|
|
||||||
SendQueue.CommitAdd();
|
SendQueue.CommitAdd();
|
||||||
SignalIOActivity();
|
SignalIOActivity();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void Discord_Initialize(const char *applicationId,
|
extern "C" void Discord_Initialize(const char *applicationId, DiscordEventHandlers *handlers, const int autoRegister) {
|
||||||
DiscordEventHandlers *handlers,
|
|
||||||
int autoRegister,
|
|
||||||
const char *optionalSteamId) {
|
|
||||||
IoThread = new (std::nothrow) IoThreadHolder();
|
IoThread = new (std::nothrow) IoThreadHolder();
|
||||||
if (IoThread == nullptr) {
|
if (IoThread == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (autoRegister) {
|
if (autoRegister) {
|
||||||
if (optionalSteamId && optionalSteamId[0]) {
|
Discord_Register(applicationId, nullptr);
|
||||||
Discord_RegisterSteamGame(applicationId, optionalSteamId);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Discord_Register(applicationId, nullptr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Pid = GetProcessId();
|
Pid = GetProcessId();
|
||||||
@@ -323,9 +322,11 @@ extern "C" void Discord_Initialize(const char *applicationId,
|
|||||||
};
|
};
|
||||||
|
|
||||||
IoThread->Start();
|
IoThread->Start();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void Discord_Shutdown(void) {
|
extern "C" void Discord_Shutdown(void) {
|
||||||
|
|
||||||
if (!Connection) {
|
if (!Connection) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -341,15 +342,19 @@ extern "C" void Discord_Shutdown(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RpcConnection::Destroy(Connection);
|
RpcConnection::Destroy(Connection);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void Discord_UpdatePresence(const DiscordRichPresence *presence) {
|
extern "C" void Discord_UpdatePresence(const DiscordRichPresence *presence) {
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> guard(PresenceMutex);
|
std::lock_guard<std::mutex> guard(PresenceMutex);
|
||||||
QueuedPresence.length = JsonWriteRichPresenceObj(QueuedPresence.buffer, sizeof(QueuedPresence.buffer), Nonce++, Pid, presence);
|
QueuedPresence.length = JsonWriteRichPresenceObj(QueuedPresence.buffer, sizeof(QueuedPresence.buffer), Nonce++, Pid, presence);
|
||||||
UpdatePresence.exchange(true);
|
UpdatePresence.exchange(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
SignalIOActivity();
|
SignalIOActivity();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void Discord_ClearPresence(void) {
|
extern "C" void Discord_ClearPresence(void) {
|
||||||
@@ -357,20 +362,22 @@ extern "C" void Discord_ClearPresence(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void Discord_Respond(const char *userId, /* DISCORD_REPLY_ */ int reply) {
|
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 we are not connected, let's not batch up stale messages for later
|
||||||
if (!Connection || !Connection->IsOpen()) {
|
if (!Connection || !Connection->IsOpen()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto qmessage = SendQueue.GetNextAddMessage();
|
auto qmessage = SendQueue.GetNextAddMessage();
|
||||||
if (qmessage) {
|
if (qmessage) {
|
||||||
qmessage->length =
|
qmessage->length = JsonWriteJoinReply(qmessage->buffer, sizeof(qmessage->buffer), userId, reply, Nonce++);
|
||||||
JsonWriteJoinReply(qmessage->buffer, sizeof(qmessage->buffer), userId, reply, Nonce++);
|
|
||||||
SendQueue.CommitAdd();
|
SendQueue.CommitAdd();
|
||||||
SignalIOActivity();
|
SignalIOActivity();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void Discord_RunCallbacks(void) {
|
extern "C" void Discord_RunCallbacks() {
|
||||||
|
|
||||||
// Note on some weirdness: internally we might connect, get other signals, disconnect any number
|
// 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
|
// 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.
|
// signals are book-ended by calls to ready and disconnect.
|
||||||
@@ -379,8 +386,8 @@ extern "C" void Discord_RunCallbacks(void) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wasDisconnected = WasJustDisconnected.exchange(false);
|
const bool wasDisconnected = WasJustDisconnected.exchange(false);
|
||||||
bool isConnected = Connection->IsOpen();
|
const bool isConnected = Connection->IsOpen();
|
||||||
|
|
||||||
if (isConnected) {
|
if (isConnected) {
|
||||||
// if we are connected, disconnect cb first
|
// if we are connected, disconnect cb first
|
||||||
@@ -393,10 +400,7 @@ extern "C" void Discord_RunCallbacks(void) {
|
|||||||
if (WasJustConnected.exchange(false)) {
|
if (WasJustConnected.exchange(false)) {
|
||||||
std::lock_guard<std::mutex> guard(HandlerMutex);
|
std::lock_guard<std::mutex> guard(HandlerMutex);
|
||||||
if (Handlers.ready) {
|
if (Handlers.ready) {
|
||||||
DiscordUser du { connectedUser.userId,
|
DiscordUser du { connectedUser.userId, connectedUser.username, connectedUser.discriminator, connectedUser.avatar };
|
||||||
connectedUser.username,
|
|
||||||
connectedUser.discriminator,
|
|
||||||
connectedUser.avatar };
|
|
||||||
Handlers.ready(&du);
|
Handlers.ready(&du);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -428,7 +432,7 @@ extern "C" void Discord_RunCallbacks(void) {
|
|||||||
// maybe show them in one common dialog and/or start fetching the avatars in parallel, and if
|
// 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.
|
// not it should be trivial for the implementer to make a queue themselves.
|
||||||
while (JoinAskQueue.HavePendingSends()) {
|
while (JoinAskQueue.HavePendingSends()) {
|
||||||
auto req = JoinAskQueue.GetNextSendMessage();
|
const auto req = JoinAskQueue.GetNextSendMessage();
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> guard(HandlerMutex);
|
std::lock_guard<std::mutex> guard(HandlerMutex);
|
||||||
if (Handlers.joinRequest) {
|
if (Handlers.joinRequest) {
|
||||||
@@ -446,9 +450,11 @@ extern "C" void Discord_RunCallbacks(void) {
|
|||||||
Handlers.disconnected(LastDisconnectErrorCode, LastDisconnectErrorMessage);
|
Handlers.disconnected(LastDisconnectErrorCode, LastDisconnectErrorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void Discord_UpdateHandlers(DiscordEventHandlers *newHandlers) {
|
extern "C" void Discord_UpdateHandlers(DiscordEventHandlers *newHandlers) {
|
||||||
|
|
||||||
if (newHandlers) {
|
if (newHandlers) {
|
||||||
#define HANDLE_EVENT_REGISTRATION(handler_name, event) \
|
#define HANDLE_EVENT_REGISTRATION(handler_name, event) \
|
||||||
if (!Handlers.handler_name && newHandlers->handler_name) { \
|
if (!Handlers.handler_name && newHandlers->handler_name) { \
|
||||||
@@ -471,7 +477,7 @@ extern "C" void Discord_UpdateHandlers(DiscordEventHandlers *newHandlers) {
|
|||||||
std::lock_guard<std::mutex> guard(HandlerMutex);
|
std::lock_guard<std::mutex> guard(HandlerMutex);
|
||||||
Handlers = {};
|
Handlers = {};
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace discord_rpc
|
} // namespace discord_rpc
|
||||||
@@ -1,10 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
namespace discord_rpc {
|
namespace discord_rpc {
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@@ -54,13 +50,10 @@ typedef struct DiscordEventHandlers {
|
|||||||
#define DISCORD_PARTY_PRIVATE 0
|
#define DISCORD_PARTY_PRIVATE 0
|
||||||
#define DISCORD_PARTY_PUBLIC 1
|
#define DISCORD_PARTY_PUBLIC 1
|
||||||
|
|
||||||
void Discord_Initialize(const char *applicationId,
|
void Discord_Initialize(const char *applicationId, DiscordEventHandlers *handlers, const int autoRegister);
|
||||||
DiscordEventHandlers *handlers,
|
|
||||||
int autoRegister,
|
|
||||||
const char *optionalSteamId);
|
|
||||||
void Discord_Shutdown(void);
|
void Discord_Shutdown(void);
|
||||||
|
|
||||||
/* checks for incoming messages, dispatches callbacks */
|
// checks for incoming messages, dispatches callbacks
|
||||||
void Discord_RunCallbacks(void);
|
void Discord_RunCallbacks(void);
|
||||||
|
|
||||||
void Discord_UpdatePresence(const DiscordRichPresence *presence);
|
void Discord_UpdatePresence(const DiscordRichPresence *presence);
|
||||||
@@ -1,24 +1,29 @@
|
|||||||
#include "rpc_connection.h"
|
#include "discord_rpc_connection.h"
|
||||||
#include "serialization.h"
|
#include "discord_serialization.h"
|
||||||
|
|
||||||
namespace discord_rpc {
|
namespace discord_rpc {
|
||||||
|
|
||||||
static const int RpcVersion = 1;
|
static const int RpcVersion = 1;
|
||||||
static RpcConnection Instance;
|
static RpcConnection Instance;
|
||||||
|
|
||||||
/*static*/ RpcConnection *RpcConnection::Create(const char *applicationId) {
|
RpcConnection *RpcConnection::Create(const char *applicationId) {
|
||||||
|
|
||||||
Instance.connection = BaseConnection::Create();
|
Instance.connection = BaseConnection::Create();
|
||||||
StringCopy(Instance.appId, applicationId);
|
StringCopy(Instance.appId, applicationId);
|
||||||
return &Instance;
|
return &Instance;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static*/ void RpcConnection::Destroy(RpcConnection *&c) {
|
void RpcConnection::Destroy(RpcConnection *&c) {
|
||||||
|
|
||||||
c->Close();
|
c->Close();
|
||||||
BaseConnection::Destroy(c->connection);
|
BaseConnection::Destroy(c->connection);
|
||||||
c = nullptr;
|
c = nullptr;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RpcConnection::Open() {
|
void RpcConnection::Open() {
|
||||||
|
|
||||||
if (state == State::Connected) {
|
if (state == State::Connected) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -51,17 +56,21 @@ void RpcConnection::Open() {
|
|||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RpcConnection::Close() {
|
void RpcConnection::Close() {
|
||||||
|
|
||||||
if (onDisconnect && (state == State::Connected || state == State::SentHandshake)) {
|
if (onDisconnect && (state == State::Connected || state == State::SentHandshake)) {
|
||||||
onDisconnect(lastErrorCode, lastErrorMessage);
|
onDisconnect(lastErrorCode, lastErrorMessage);
|
||||||
}
|
}
|
||||||
connection->Close();
|
connection->Close();
|
||||||
state = State::Disconnected;
|
state = State::Disconnected;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RpcConnection::Write(const void *data, size_t length) {
|
bool RpcConnection::Write(const void *data, size_t length) {
|
||||||
|
|
||||||
sendFrame.opcode = Opcode::Frame;
|
sendFrame.opcode = Opcode::Frame;
|
||||||
memcpy(sendFrame.message, data, length);
|
memcpy(sendFrame.message, data, length);
|
||||||
sendFrame.length = static_cast<uint32_t>(length);
|
sendFrame.length = static_cast<uint32_t>(length);
|
||||||
@@ -69,14 +78,17 @@ bool RpcConnection::Write(const void *data, size_t length) {
|
|||||||
Close();
|
Close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RpcConnection::Read(JsonDocument &message) {
|
bool RpcConnection::Read(JsonDocument &message) {
|
||||||
|
|
||||||
if (state != State::Connected && state != State::SentHandshake) {
|
if (state != State::Connected && state != State::SentHandshake) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
MessageFrame readFrame;
|
MessageFrame readFrame{};
|
||||||
for (;;) {
|
for (;;) {
|
||||||
bool didRead = connection->Read(&readFrame, sizeof(MessageFrameHeader));
|
bool didRead = connection->Read(&readFrame, sizeof(MessageFrameHeader));
|
||||||
if (!didRead) {
|
if (!didRead) {
|
||||||
@@ -127,6 +139,7 @@ bool RpcConnection::Read(JsonDocument &message) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace discord_rpc
|
} // namespace discord_rpc
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "connection.h"
|
#include "discord_connection.h"
|
||||||
#include "serialization.h"
|
#include "discord_serialization.h"
|
||||||
|
|
||||||
namespace discord_rpc {
|
namespace discord_rpc {
|
||||||
|
|
||||||
// I took this from the buffer size libuv uses for named pipes; I suspect ours would usually be much
|
// I took this from the buffer size libuv uses for named pipes; I suspect ours would usually be much smaller.
|
||||||
// smaller.
|
|
||||||
constexpr size_t MaxRpcFrameSize = 64 * 1024;
|
constexpr size_t MaxRpcFrameSize = 64 * 1024;
|
||||||
|
|
||||||
struct RpcConnection {
|
struct RpcConnection {
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
#include "serialization.h"
|
#include "discord_serialization.h"
|
||||||
#include "connection.h"
|
#include "discord_connection.h"
|
||||||
#include "discord_rpc.h"
|
#include "discord_rpc.h"
|
||||||
|
|
||||||
namespace discord_rpc {
|
namespace discord_rpc {
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void NumberToString(char *dest, T number) {
|
void NumberToString(char *dest, T number) {
|
||||||
|
|
||||||
if (!number) {
|
if (!number) {
|
||||||
*dest++ = '0';
|
*dest++ = '0';
|
||||||
*dest++ = 0;
|
*dest++ = 0;
|
||||||
@@ -26,6 +27,7 @@ void NumberToString(char *dest, T number) {
|
|||||||
*dest++ = temp[place];
|
*dest++ = temp[place];
|
||||||
}
|
}
|
||||||
*dest = 0;
|
*dest = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// it's ever so slightly faster to not have to strlen the key
|
// it's ever so slightly faster to not have to strlen the key
|
||||||
@@ -62,24 +64,25 @@ struct WriteArray {
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void WriteOptionalString(JsonWriter &w, T &k, const char *value) {
|
void WriteOptionalString(JsonWriter &w, T &k, const char *value) {
|
||||||
|
|
||||||
if (value && value[0]) {
|
if (value && value[0]) {
|
||||||
w.Key(k, sizeof(T) - 1);
|
w.Key(k, sizeof(T) - 1);
|
||||||
w.String(value);
|
w.String(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void JsonWriteNonce(JsonWriter &writer, int nonce) {
|
static void JsonWriteNonce(JsonWriter &writer, const int nonce) {
|
||||||
|
|
||||||
WriteKey(writer, "nonce");
|
WriteKey(writer, "nonce");
|
||||||
char nonceBuffer[32];
|
char nonceBuffer[32];
|
||||||
NumberToString(nonceBuffer, nonce);
|
NumberToString(nonceBuffer, nonce);
|
||||||
writer.String(nonceBuffer);
|
writer.String(nonceBuffer);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t JsonWriteRichPresenceObj(char *dest,
|
size_t JsonWriteRichPresenceObj(char *dest, const size_t maxLen, const int nonce, const int pid, const DiscordRichPresence *presence) {
|
||||||
size_t maxLen,
|
|
||||||
int nonce,
|
|
||||||
int pid,
|
|
||||||
const DiscordRichPresence *presence) {
|
|
||||||
JsonWriter writer(dest, maxLen);
|
JsonWriter writer(dest, maxLen);
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -168,6 +171,7 @@ size_t JsonWriteRichPresenceObj(char *dest,
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t JsonWriteHandshakeObj(char *dest, size_t maxLen, int version, const char *applicationId) {
|
size_t JsonWriteHandshakeObj(char *dest, size_t maxLen, int version, const char *applicationId) {
|
||||||
|
|
||||||
JsonWriter writer(dest, maxLen);
|
JsonWriter writer(dest, maxLen);
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -179,9 +183,11 @@ size_t JsonWriteHandshakeObj(char *dest, size_t maxLen, int version, const char
|
|||||||
}
|
}
|
||||||
|
|
||||||
return writer.Size();
|
return writer.Size();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t JsonWriteSubscribeCommand(char *dest, size_t maxLen, int nonce, const char *evtName) {
|
size_t JsonWriteSubscribeCommand(char *dest, size_t maxLen, int nonce, const char *evtName) {
|
||||||
|
|
||||||
JsonWriter writer(dest, maxLen);
|
JsonWriter writer(dest, maxLen);
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -197,9 +203,11 @@ size_t JsonWriteSubscribeCommand(char *dest, size_t maxLen, int nonce, const cha
|
|||||||
}
|
}
|
||||||
|
|
||||||
return writer.Size();
|
return writer.Size();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t JsonWriteUnsubscribeCommand(char *dest, size_t maxLen, int nonce, const char *evtName) {
|
size_t JsonWriteUnsubscribeCommand(char *dest, size_t maxLen, int nonce, const char *evtName) {
|
||||||
|
|
||||||
JsonWriter writer(dest, maxLen);
|
JsonWriter writer(dest, maxLen);
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -215,9 +223,11 @@ size_t JsonWriteUnsubscribeCommand(char *dest, size_t maxLen, int nonce, const c
|
|||||||
}
|
}
|
||||||
|
|
||||||
return writer.Size();
|
return writer.Size();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t JsonWriteJoinReply(char *dest, size_t maxLen, const char *userId, int reply, int nonce) {
|
size_t JsonWriteJoinReply(char *dest, size_t maxLen, const char *userId, const int reply, const int nonce) {
|
||||||
|
|
||||||
JsonWriter writer(dest, maxLen);
|
JsonWriter writer(dest, maxLen);
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -243,6 +253,7 @@ size_t JsonWriteJoinReply(char *dest, size_t maxLen, const char *userId, int rep
|
|||||||
}
|
}
|
||||||
|
|
||||||
return writer.Size();
|
return writer.Size();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace discord_rpc
|
} // namespace discord_rpc
|
||||||
@@ -25,11 +25,7 @@ size_t JsonWriteHandshakeObj(char *dest, size_t maxLen, int version, const char
|
|||||||
|
|
||||||
// Commands
|
// Commands
|
||||||
struct DiscordRichPresence;
|
struct DiscordRichPresence;
|
||||||
size_t JsonWriteRichPresenceObj(char *dest,
|
size_t JsonWriteRichPresenceObj(char *dest, const size_t maxLen, const int nonce, const int pid, const DiscordRichPresence *presence);
|
||||||
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 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 JsonWriteUnsubscribeCommand(char *dest, size_t maxLen, int nonce, const char *evtName);
|
||||||
@@ -149,35 +145,42 @@ class JsonDocument : public JsonDocumentBase {
|
|||||||
using JsonValue = rapidjson::GenericValue<UTF8, PoolAllocator>;
|
using JsonValue = rapidjson::GenericValue<UTF8, PoolAllocator>;
|
||||||
|
|
||||||
inline JsonValue *GetObjMember(JsonValue *obj, const char *name) {
|
inline JsonValue *GetObjMember(JsonValue *obj, const char *name) {
|
||||||
|
|
||||||
if (obj) {
|
if (obj) {
|
||||||
auto member = obj->FindMember(name);
|
auto member = obj->FindMember(name);
|
||||||
if (member != obj->MemberEnd() && member->value.IsObject()) {
|
if (member != obj->MemberEnd() && member->value.IsObject()) {
|
||||||
return &member->value;
|
return &member->value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int GetIntMember(JsonValue *obj, const char *name, int notFoundDefault = 0) {
|
inline int GetIntMember(JsonValue *obj, const char *name, int notFoundDefault = 0) {
|
||||||
|
|
||||||
if (obj) {
|
if (obj) {
|
||||||
auto member = obj->FindMember(name);
|
auto member = obj->FindMember(name);
|
||||||
if (member != obj->MemberEnd() && member->value.IsInt()) {
|
if (member != obj->MemberEnd() && member->value.IsInt()) {
|
||||||
return member->value.GetInt();
|
return member->value.GetInt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return notFoundDefault;
|
return notFoundDefault;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const char *GetStrMember(JsonValue *obj,
|
inline const char *GetStrMember(JsonValue *obj, const char *name, const char *notFoundDefault = nullptr) {
|
||||||
const char *name,
|
|
||||||
const char *notFoundDefault = nullptr) {
|
|
||||||
if (obj) {
|
if (obj) {
|
||||||
auto member = obj->FindMember(name);
|
auto member = obj->FindMember(name);
|
||||||
if (member != obj->MemberEnd() && member->value.IsString()) {
|
if (member != obj->MemberEnd() && member->value.IsString()) {
|
||||||
return member->value.GetString();
|
return member->value.GetString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return notFoundDefault;
|
return notFoundDefault;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace discord_rpc
|
} // namespace discord_rpc
|
||||||
41
3rdparty/discord-rpc/src/CMakeLists.txt
vendored
41
3rdparty/discord-rpc/src/CMakeLists.txt
vendored
@@ -1,41 +0,0 @@
|
|||||||
set(DISCORD_RPC_SOURCES
|
|
||||||
../include/discord_rpc.h
|
|
||||||
../include/discord_register.h
|
|
||||||
discord_rpc.cpp
|
|
||||||
rpc_connection.h
|
|
||||||
rpc_connection.cpp
|
|
||||||
serialization.h
|
|
||||||
serialization.cpp
|
|
||||||
connection.h
|
|
||||||
backoff.h
|
|
||||||
msg_queue.h
|
|
||||||
)
|
|
||||||
|
|
||||||
if(UNIX)
|
|
||||||
list(APPEND DISCORD_RPC_SOURCES connection_unix.cpp)
|
|
||||||
if(APPLE)
|
|
||||||
list(APPEND DISCORD_RPC_SOURCES discord_register_osx.m)
|
|
||||||
add_definitions(-DDISCORD_OSX)
|
|
||||||
else()
|
|
||||||
list(APPEND DISCORD_RPC_SOURCES discord_register_linux.cpp)
|
|
||||||
add_definitions(-DDISCORD_LINUX)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
list(APPEND DISCORD_RPC_SOURCES connection_win.cpp discord_register_win.cpp)
|
|
||||||
add_definitions(-DDISCORD_WINDOWS)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_library(discord-rpc STATIC ${DISCORD_RPC_SOURCES})
|
|
||||||
|
|
||||||
if(APPLE)
|
|
||||||
target_link_libraries(discord-rpc PRIVATE "-framework AppKit")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
target_link_libraries(discord-rpc PRIVATE psapi advapi32)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_include_directories(discord-rpc SYSTEM PRIVATE ${RapidJSON_INCLUDE_DIRS})
|
|
||||||
target_include_directories(discord-rpc PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../include)
|
|
||||||
80
3rdparty/discord-rpc/src/discord_register_osx.m
vendored
80
3rdparty/discord-rpc/src/discord_register_osx.m
vendored
@@ -1,80 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#import <AppKit/AppKit.h>
|
|
||||||
|
|
||||||
#include "discord_register.h"
|
|
||||||
|
|
||||||
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, 256, "steam://rungameid/%s", steamId);
|
|
||||||
Discord_Register(applicationId, command);
|
|
||||||
}
|
|
||||||
@@ -1494,7 +1494,7 @@ endif()
|
|||||||
|
|
||||||
if(HAVE_DISCORD_RPC)
|
if(HAVE_DISCORD_RPC)
|
||||||
add_subdirectory(3rdparty/discord-rpc)
|
add_subdirectory(3rdparty/discord-rpc)
|
||||||
target_include_directories(strawberry_lib PUBLIC 3rdparty/discord-rpc/include)
|
target_include_directories(strawberry_lib PUBLIC 3rdparty/discord-rpc)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(HAVE_TRANSLATIONS)
|
if(HAVE_TRANSLATIONS)
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ RichPresence::RichPresence(const SharedPtr<Player> player,
|
|||||||
send_presence_timestamp_(0),
|
send_presence_timestamp_(0),
|
||||||
enabled_(false) {
|
enabled_(false) {
|
||||||
|
|
||||||
Discord_Initialize(kDiscordApplicationId, nullptr, 1, nullptr);
|
Discord_Initialize(kDiscordApplicationId, nullptr, 1);
|
||||||
|
|
||||||
QObject::connect(&*player_->engine(), &EngineBase::StateChanged, this, &RichPresence::EngineStateChanged);
|
QObject::connect(&*player_->engine(), &EngineBase::StateChanged, this, &RichPresence::EngineStateChanged);
|
||||||
QObject::connect(&*playlist_manager_, &PlaylistManager::CurrentSongChanged, this, &RichPresence::CurrentSongChanged);
|
QObject::connect(&*playlist_manager_, &PlaylistManager::CurrentSongChanged, this, &RichPresence::CurrentSongChanged);
|
||||||
|
|||||||
Reference in New Issue
Block a user