Also do registering on OSX and Linux.
This commit is contained in:
parent
11e74bca5e
commit
a5a56bcf68
9 changed files with 253 additions and 27 deletions
9
build.py
Normal file → Executable file
9
build.py
Normal file → Executable file
|
@ -1,3 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import click
|
||||
import os
|
||||
import subprocess
|
||||
|
@ -45,7 +47,7 @@ def build_lib(build_name, generator, options):
|
|||
|
||||
|
||||
def create_archive():
|
||||
archive_file_path = os.path.join(SCRIPT_PATH, 'builds', 'discord-rpc.zip')
|
||||
archive_file_path = os.path.join(SCRIPT_PATH, 'builds', 'discord-rpc-%s.zip' % sys.platform)
|
||||
archive_file = zipfile.ZipFile(archive_file_path, 'w', zipfile.ZIP_DEFLATED)
|
||||
archive_src_base_path = os.path.join(SCRIPT_PATH, 'builds', 'install')
|
||||
archive_dst_base_path = 'discord-rpc'
|
||||
|
@ -64,6 +66,8 @@ def main(clean):
|
|||
if clean:
|
||||
shutil.rmtree('builds', ignore_errors=True)
|
||||
|
||||
mkdir_p('builds')
|
||||
|
||||
if sys.platform.startswith('win'):
|
||||
generator32 = 'Visual Studio 14 2015'
|
||||
generator64 = 'Visual Studio 14 2015 Win64'
|
||||
|
@ -79,6 +83,9 @@ def main(clean):
|
|||
shutil.copy(src_dll, dst_dll)
|
||||
dst_dll = os.path.join(SCRIPT_PATH, 'examples', 'unrealstatus', 'Plugins', 'discordrpc', 'Binaries', 'ThirdParty', 'discordrpcLibrary', 'Win64', 'discord-rpc.dll')
|
||||
shutil.copy(src_dll, dst_dll)
|
||||
elif sys.platform == 'darwin':
|
||||
build_lib('osx-static', None, {})
|
||||
build_lib('osx-dynamic', None, {'BUILD_DYNAMIC_LIB': True})
|
||||
|
||||
create_archive()
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ By committing to an RPC-only integration, you decide to forego the work our libr
|
|||
|
||||
## Application Protocol Registration
|
||||
|
||||
One thing that cannot be explicitly done over RPC is registering an application protocol for your game. If you choose to do an RPC-only implementation, you will have to register your application protocol yourself in the format of `discord-[your_app_id]://`. You can use `Discord_Register()` from `src/discord-register.cpp` as a good example of how to properly register an application protocol for use with Discord.
|
||||
One thing that cannot be explicitly done over RPC is registering an application protocol for your game. If you choose to do an RPC-only implementation, you will have to register your application protocol yourself in the format of `discord-[your_app_id]://`. You can use `Discord_Register()` as a good(?) example of how to properly register an application protocol for use with Discord. For OSX and Linux it is probably simpler to handle the protocol registration as part of your install/packaging.
|
||||
|
||||
## New RPC Command
|
||||
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
include_directories(${PROJECT_SOURCE_DIR}/include)
|
||||
add_executable(send-presence send-presence.c)
|
||||
add_executable(
|
||||
send-presence
|
||||
MACOSX_BUNDLE
|
||||
send-presence.c
|
||||
)
|
||||
set_target_properties(send-presence PROPERTIES
|
||||
MACOSX_BUNDLE_BUNDLE_NAME "Send Presence"
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER "com.discordapp.examples.send-presence"
|
||||
)
|
||||
target_link_libraries(send-presence discord-rpc)
|
||||
|
||||
install(
|
||||
|
@ -7,4 +15,7 @@ install(
|
|||
RUNTIME
|
||||
DESTINATION "bin"
|
||||
CONFIGURATIONS Release
|
||||
BUNDLE
|
||||
DESTINATION "bin"
|
||||
CONFIGURATIONS Release
|
||||
)
|
|
@ -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)
|
||||
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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
96
src/discord_register_linux.cpp
Normal file
96
src/discord_register_linux.cpp
Normal 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);
|
||||
}
|
95
src/discord_register_osx.m
Normal file
95
src/discord_register_osx.m
Normal 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);
|
||||
}
|
|
@ -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
|
||||
}
|
Loading…
Reference in a new issue