Also do registering on OSX and Linux.

This commit is contained in:
Chris Marsh
2017-09-14 08:59:32 -07:00
parent 11e74bca5e
commit a5a56bcf68
9 changed files with 253 additions and 27 deletions

View File

@ -6,8 +6,7 @@ option(BUILD_DYNAMIC_LIB "Build library as a DLL" OFF)
set(BASE_RPC_SRC
${PROJECT_SOURCE_DIR}/include/discord-rpc.h
discord-rpc.cpp
discord-register.h
discord-register.cpp
discord_register.h
rpc_connection.h
rpc_connection.cpp
serialization.h
@ -18,20 +17,39 @@ set(BASE_RPC_SRC
if (${BUILD_DYNAMIC_LIB})
set(RPC_LIBRARY_TYPE SHARED)
set(BASE_RPC_SRC ${BASE_RPC_SRC} dllmain.cpp)
if(WIN32)
set(BASE_RPC_SRC ${BASE_RPC_SRC} dllmain.cpp)
endif(WIN32)
else(${BUILD_DYNAMIC_LIB})
set(RPC_LIBRARY_TYPE STATIC)
endif(${BUILD_DYNAMIC_LIB})
if(WIN32)
add_library(discord-rpc ${RPC_LIBRARY_TYPE} ${BASE_RPC_SRC} connection_win.cpp)
add_definitions(-DDISCORD_WINDOWS)
set(BASE_RPC_SRC ${BASE_RPC_SRC} connection_win.cpp discord_register_win.cpp)
add_library(discord-rpc ${RPC_LIBRARY_TYPE} ${BASE_RPC_SRC})
target_compile_options(discord-rpc PRIVATE /W4)
endif(WIN32)
if(UNIX)
add_library(discord-rpc ${RPC_LIBRARY_TYPE} ${BASE_RPC_SRC} connection_unix.cpp)
set(BASE_RPC_SRC ${BASE_RPC_SRC} connection_unix.cpp)
if (APPLE)
add_definitions(-DDISCORD_OSX)
set(BASE_RPC_SRC ${BASE_RPC_SRC} discord_register_osx.m)
else (APPLE)
add_definitions(-DDISCORD_LINUX)
set(BASE_RPC_SRC ${BASE_RPC_SRC} discord_register_linux.cpp)
endif(APPLE)
add_library(discord-rpc ${RPC_LIBRARY_TYPE} ${BASE_RPC_SRC})
target_link_libraries(discord-rpc PUBLIC pthread)
target_compile_options(discord-rpc PRIVATE -g -Wall -std=c++14)
target_compile_options(discord-rpc PRIVATE -g -Wall)
target_compile_options(discord-rpc PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-std=c++14>)
if (APPLE)
target_link_libraries(discord-rpc PRIVATE "-framework AppKit")
endif (APPLE)
endif(UNIX)
target_include_directories(discord-rpc PRIVATE ${RAPIDJSON}/include)

View File

@ -1,7 +1,7 @@
#include "discord-rpc.h"
#include "backoff.h"
#include "discord-register.h"
#include "discord_register.h"
#include "rpc_connection.h"
#include "serialization.h"
@ -93,7 +93,7 @@ static void SendQueueCommitMessage()
SendQueuePendingSends++;
}
extern "C" void Discord_UpdateConnection()
DISCORD_EXPORT void Discord_UpdateConnection()
{
if (!Connection) {
return;
@ -210,7 +210,7 @@ bool RegisterForEvent(const char* evtName)
return false;
}
extern "C" void Discord_Initialize(const char* applicationId,
DISCORD_EXPORT void Discord_Initialize(const char* applicationId,
DiscordEventHandlers* handlers,
int autoRegister,
const char* optionalSteamId)
@ -263,7 +263,7 @@ extern "C" void Discord_Initialize(const char* applicationId,
#endif
}
extern "C" void Discord_Shutdown()
DISCORD_EXPORT void Discord_Shutdown()
{
if (!Connection) {
return;
@ -281,7 +281,7 @@ extern "C" void Discord_Shutdown()
RpcConnection::Destroy(Connection);
}
extern "C" void Discord_UpdatePresence(const DiscordRichPresence* presence)
DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence)
{
PresenceMutex.lock();
QueuedPresence.length = JsonWriteRichPresenceObj(
@ -290,7 +290,7 @@ extern "C" void Discord_UpdatePresence(const DiscordRichPresence* presence)
SignalIOActivity();
}
extern "C" void Discord_RunCallbacks()
DISCORD_EXPORT void Discord_RunCallbacks()
{
// 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

View File

@ -1,4 +1,12 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void Discord_Register(const char* applicationId, const char* command);
void Discord_RegisterSteamGame(const char* applicationId, const char* steamId);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,96 @@
#include "discord-rpc.h"
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
bool Mkdir(const char* path)
{
int result = mkdir(path, 0755);
if (result == 0) {
return true;
}
if (errno == EEXIST) {
return true;
}
return false;
}
// 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)
{
// Add a desktop file and update some mime handlers so that xdg-open does the right thing.
const char* home = getenv("HOME");
if (!home) {
return;
}
char exePath[1024];
if (!command || !command[0]) {
if (readlink("/proc/self/exe", exePath, sizeof(exePath)) <= 0) {
return;
}
command = exePath;
}
const char* destopFileFormat = "[Desktop Entry]\n"
"Name=Game %s\n"
"Exec=%s %%u\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";
char desktopFile[2048];
int fileLen = snprintf(
desktopFile, sizeof(desktopFile), destopFileFormat, applicationId, command, applicationId);
if (fileLen <= 0) {
return;
}
char desktopFilename[256];
snprintf(desktopFilename, sizeof(desktopFilename), "/discord-%s.desktop", applicationId);
char desktopFilePath[1024];
snprintf(desktopFilePath, sizeof(desktopFilePath), "%s/.local", home);
if (!Mkdir(desktopFilePath)) {
return;
}
strcat(desktopFilePath, "/share");
if (!Mkdir(desktopFilePath)) {
return;
}
strcat(desktopFilePath, "/applications");
if (!Mkdir(desktopFilePath)) {
return;
}
strcat(desktopFilePath, desktopFilename);
FILE* fp = fopen(desktopFilePath, "w");
if (fp) {
fwrite(desktopFile, 1, fileLen, fp);
fclose(fp);
}
else {
return;
}
char xdgMimeCommand[1024];
snprintf(xdgMimeCommand,
sizeof(xdgMimeCommand),
"xdg-mime default discord-%s.desktop x-scheme-handler/discord-%s",
applicationId,
applicationId);
system(xdgMimeCommand);
}
extern "C" void Discord_RegisterSteamGame(const char* applicationId, const char* steamId)
{
char command[256];
sprintf(command, "xdg-open steam://run/%s", steamId);
Discord_Register(applicationId, command);
}

View File

@ -0,0 +1,95 @@
#include <stdio.h>
#include <sys/stat.h>
#import <AppKit/AppKit.h>
static bool Mkdir(const char* path)
{
int result = mkdir(path, 0755);
if (result == 0) {
return true;
}
if (errno == EEXIST) {
return true;
}
return false;
}
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)
const char* home = getenv("HOME");
if (!home) {
return;
}
char path[2048];
sprintf(path, "%s/Library/Application Support/discord", home);
Mkdir(path);
strcat(path, "/games");
Mkdir(path);
strcat(path, "/");
strcat(path, applicationId);
strcat(path, ".json");
FILE* f = fopen(path, "w");
if (f) {
char jsonBuffer[2048];
int len = snprintf(jsonBuffer, sizeof(jsonBuffer), "{\"command\": \"%s\"}", command);
fwrite(jsonBuffer, len, 1, f);
fclose(f);
}
}
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
void* pool = [[NSAutoreleasePool alloc] init];
RegisterURL(applicationId);
[(id)pool drain];
}
}
void Discord_RegisterSteamGame(const char* applicationId, const char* steamId)
{
char command[256];
sprintf(command, "steam://run/%s", steamId);
Discord_Register(applicationId, command);
}

View File

@ -1,7 +1,6 @@
#include "discord-rpc.h"
#include <stdio.h>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#define NOMCX
#define NOSERVICE
@ -10,9 +9,7 @@
#include <Psapi.h>
#include <Strsafe.h>
#pragma comment(lib, "Psapi.lib")
#endif
#ifdef _WIN32
void Discord_RegisterW(const wchar_t* applicationId, const wchar_t* command)
{
// https://msdn.microsoft.com/en-us/library/aa767914(v=vs.85).aspx
@ -76,12 +73,9 @@ void Discord_RegisterW(const wchar_t* applicationId, const wchar_t* command)
}
RegCloseKey(key);
}
#endif
void Discord_Register(const char* applicationId, const char* command)
extern "C" void Discord_Register(const char* applicationId, const char* command)
{
#ifdef _WIN32
wchar_t appId[32];
MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32);
@ -94,12 +88,10 @@ void Discord_Register(const char* applicationId, const char* command)
}
Discord_RegisterW(appId, wcommand);
#endif
}
void Discord_RegisterSteamGame(const char* applicationId, const char* steamId)
extern "C" void Discord_RegisterSteamGame(const char* applicationId, const char* steamId)
{
#ifdef _WIN32
wchar_t appId[32];
MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32);
@ -133,5 +125,4 @@ void Discord_RegisterSteamGame(const char* applicationId, const char* steamId)
StringCbPrintfW(command, sizeof(command), L"\"%s\" steam://run/%s", steamPath, wSteamId);
Discord_RegisterW(appId, command);
#endif
}