# HG changeset patch # User Paper # Date 1671240906 18000 # Node ID be4835547dd0bddb15c7e62b1c9798debb9515c3 # Parent 8ce85aee15c0bc766f3db52f0fc17c88bb4716bc clean up code, convert git files to hg, etc. diff -r 8ce85aee15c0 -r be4835547dd0 .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Fri Dec 16 20:35:06 2022 -0500 @@ -0,0 +1,5 @@ +syntax: glob +*.o +*.dll +*.exe +discord_game_sdk \ No newline at end of file diff -r 8ce85aee15c0 -r be4835547dd0 Makefile --- a/Makefile Sat Dec 17 01:48:13 2022 +0000 +++ b/Makefile Fri Dec 16 20:35:06 2022 -0500 @@ -8,11 +8,11 @@ else CFLAGS += -I"/c/Program Files (x86)/Winamp SDK" endif -LDFLAGS=-L"discord_game_sdk/lib/x86" -ldiscord_game_sdk +LDFLAGS=-L"discord_game_sdk/lib/x86" -ldiscord_game_sdk -Wl,--enable-stdcall-fixup DEPS=src/include/config.h src/include/dirtools.h src/include/main.h \ - src/include/timer.h src/include/resource.h + src/include/timer.h src/include/resource.h src/include/utils.h RC=src/include/dialog.rc -OBJ=src/config.o src/dirtools.o src/main.o src/timer.o +OBJ=src/config.o src/dirtools.o src/main.o src/timer.o src/utils.o gen_DiscordGameSDK.dll: $(OBJ) src/include/dialog.o gcc -o $@ $(CFLAGS) $^ $(LDFLAGS) diff -r 8ce85aee15c0 -r be4835547dd0 src/config.c --- a/src/config.c Sat Dec 17 01:48:13 2022 +0000 +++ b/src/config.c Fri Dec 16 20:35:06 2022 -0500 @@ -1,11 +1,24 @@ +/** + * config.c: + * + * Functions to load/save/edit the config. +**/ + +/** + * example config: + * + * ----- wgsdk config ---- + * display_title=1 + * show_elapsed_time=1 +**/ #include #include #include #include #include "dirtools.h" #include "config.h" -#include "main.h" #include "resource.h" +#include "utils.h" #ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN #endif @@ -13,35 +26,19 @@ #include #define MAX_LINE_LENGTH 128 -extern struct config config; // from main - -static unsigned int crc32b(unsigned char *message) { - int i, j; - unsigned int byte, crc, mask; - - i = 0; - crc = 0xFFFFFFFF; - while (message[i] != 0) { - byte = message[i]; // Get next byte. - crc = crc ^ byte; - for (j = 7; j >= 0; j--) { // Do eight times. - mask = -(crc & 1); - crc = (crc >> 1) ^ (0xEDB88320 & mask); - } - i = i + 1; - } - return ~crc; -} +/* from main */ +extern void update_rich_presence_details(void); +extern struct config config; int cfg_load(struct config* config) { - char line[MAX_LINE_LENGTH] = {0}, + char line[MAX_LINE_LENGTH] = {0}, *path = dirtools_concat_paths(getenv("APPDATA"), "Winamp\\Plugins\\wgsdk\\config.txt"); - FILE* config_fp; - config_fp = fopen(path, "r"); + FILE* config_fp = fopen(path, "r"); if (config_fp == NULL) { free(path); return 1; } + /* parse the config */ while (fgets(line, MAX_LINE_LENGTH, config_fp)) { switch (crc32b((unsigned char*)strtok(line, "="))) { case 0x2a666380: // display_title @@ -60,16 +57,15 @@ int cfg_save(struct config config) { char* path = dirtools_concat_paths(getenv("APPDATA"), "Winamp\\Plugins\\wgsdk"); - FILE* config_fp; assert(!dirtools_create_directory(path)); free(path); + path = dirtools_concat_paths(getenv("APPDATA"), "Winamp\\Plugins\\wgsdk\\config.txt"); - config_fp = fopen(path, "w"); - if (config_fp == NULL) { + FILE* config_fp = fopen(path, "w"); + if (config_fp == NULL) return 1; - } fprintf(config_fp, "----- wgsdk config ----\n"); - fprintf(config_fp, "display_title=%d\n", config.display_title); + fprintf(config_fp, "display_title=%d\n", config.display_title); fprintf(config_fp, "show_elapsed_time=%d\n", config.show_elapsed_time); fclose(config_fp); return 0; @@ -77,57 +73,53 @@ /* --------------------------------- */ -void cfg_dialog_to_struct(HWND hWnd) { - HWND checkboxHwnd = GetDlgItem(hWnd, TITLE_CHECK); - config.display_title = Button_GetCheck(checkboxHwnd); +#define conf_item_to_dlg(cons, var) \ + checkboxHwnd = GetDlgItem(hWnd, cons); \ + Button_SetCheck(checkboxHwnd, var) +#define dlg_item_to_conf(cons, var) \ + checkboxHwnd = GetDlgItem(hWnd, cons); \ + var = Button_GetCheck(checkboxHwnd) +void cfg_get_controls(HWND hWnd) { + HWND checkboxHwnd; - checkboxHwnd = GetDlgItem(hWnd, ELAPSED_TIME_CHECK); - config.show_elapsed_time = Button_GetCheck(checkboxHwnd); -} - -void cfg_on_confirm_settings_dialog(HWND hWnd) -{ - cfg_dialog_to_struct(hWnd); - cfg_save(config); - update_rich_presence_details(); + dlg_item_to_conf(TITLE_CHECK, config.display_title); + dlg_item_to_conf(ELAPSED_TIME_CHECK, config.show_elapsed_time); } void cfg_set_controls(HWND hWnd) { - HWND checkboxHwnd = GetDlgItem(hWnd, TITLE_CHECK); - Button_SetCheck(checkboxHwnd, config.display_title); + HWND checkboxHwnd; - checkboxHwnd = GetDlgItem(hWnd, ELAPSED_TIME_CHECK); - Button_SetCheck(checkboxHwnd, config.show_elapsed_time); + conf_item_to_dlg(TITLE_CHECK, config.display_title); + conf_item_to_dlg(ELAPSED_TIME_CHECK, config.show_elapsed_time); +} +#undef conf_item_to_dlg +#undef dlg_item_to_conf + +void cfg_on_confirm_settings_dialog(HWND hWnd) { + cfg_get_controls(hWnd); + cfg_save(config); + update_rich_presence_details(); } BOOL CALLBACK cfg_win_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { - case WM_INITDIALOG: { + case WM_INITDIALOG: + /* do nothing if this is a child window (tab page) callback, pass to the parent */ if (GetWindowLong(hWnd, GWL_STYLE) & WS_CHILD) - { - // do nothing if this is a child window (tab page) callback, pass to the parent return FALSE; - } - cfg_set_controls(hWnd); return TRUE; - } - case WM_COMMAND: switch (LOWORD(wParam)) { - case IDOK: { + case IDOK: cfg_on_confirm_settings_dialog(hWnd); EndDialog(hWnd, 0); return TRUE; - break; - } - case IDCANCEL: { + case IDCANCEL: EndDialog(hWnd, 0); return TRUE; - break; - } } } - return FALSE; + return FALSE; } diff -r 8ce85aee15c0 -r be4835547dd0 src/dirtools.c --- a/src/dirtools.c Sat Dec 17 01:48:13 2022 +0000 +++ b/src/dirtools.c Fri Dec 16 20:35:06 2022 -0500 @@ -1,8 +1,14 @@ +/** + * dirtools.c: + * + * Useful tools for manipulating directory names, + * or pretty much anything involving directories. +**/ #include #include #include #ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN #endif #include #include "dirtools.h" diff -r 8ce85aee15c0 -r be4835547dd0 src/include/timer.h --- a/src/include/timer.h Sat Dec 17 01:48:13 2022 +0000 +++ b/src/include/timer.h Fri Dec 16 20:35:06 2022 -0500 @@ -5,7 +5,7 @@ #endif #include -struct timer_t { +struct timer { int initialized; int is_timer_alive; UINT interval; @@ -13,8 +13,8 @@ TIMERPROC timer_proc; }; -void timer_init(struct timer_t* timer, HWND winampClientWindow, TIMERPROC timer_proc); -void timer_set(struct timer_t* timer, HWND winampClientWindow); -void timer_stop(struct timer_t* timer, HWND winampClientWindow); +void timer_init(struct timer* timer, HWND winampClientWindow, TIMERPROC timer_proc); +void timer_set(struct timer* timer, HWND winampClientWindow); +void timer_stop(struct timer* timer, HWND winampClientWindow); #endif // __timer_h \ No newline at end of file diff -r 8ce85aee15c0 -r be4835547dd0 src/include/utils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/include/utils.h Fri Dec 16 20:35:06 2022 -0500 @@ -0,0 +1,7 @@ +#ifndef __utils_h +#define __utils_h + +long long get_system_time_in_milliseconds(void); +unsigned int crc32b(unsigned char *message); + +#endif \ No newline at end of file diff -r 8ce85aee15c0 -r be4835547dd0 src/main.c --- a/src/main.c Sat Dec 17 01:48:13 2022 +0000 +++ b/src/main.c Fri Dec 16 20:35:06 2022 -0500 @@ -1,12 +1,15 @@ +/** + * wgsdk - Winamp plugin for Discord's GameSDK +**/ #include #include #include #include -#include "main.h" #include "discord_game_sdk.h" #include "timer.h" #include "config.h" #include "resource.h" +#include "utils.h" #ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN #endif @@ -19,7 +22,22 @@ #define GPPHDR_VER 0x10 -winamp_general_purpose_plugin g_plugin = { +int init(); +void conf(); +void quit(); + +/* Winamp-specific stuff */ +struct winamp_gpp { + int version; // version of the plugin structure + char *description; // name/title of the plugin + int(*init)(); // function which will be executed on init event + void(*conf)(); // function which will be executed on config event + void(*quit)(); // function which will be executed on quit event + HWND hwndParent; // hwnd of the Winamp client main window (stored by Winamp when dll is loaded) + HINSTANCE hDllInstance; // hinstance of this plugin DLL. (stored by Winamp when dll is loaded) +}; + +struct winamp_gpp g_plugin = { GPPHDR_VER, // version of the plugin, defined in "gen_myplugin.h" "Discord GameSDK", // name/title of the plugin, defined in "gen_myplugin.h" init, // function name which will be executed on init event @@ -29,13 +47,7 @@ 0 // hinstance to this dll, loaded by winamp when this dll is loaded }; -WNDPROC g_lpWndProcOld = 0; - -struct timer_t timer_callbacks = { .interval = 16 }; -struct config config = { - .display_title = 1, - .show_elapsed_time = 1 -}; +/* Discord stuff */ struct DiscordActivity activity = { .application_id = CLIENT_ID, @@ -45,40 +57,42 @@ struct IDiscordActivityEvents activities_events; -struct app_t app; +struct application { + struct IDiscordCore* core; + struct IDiscordUsers* users; + struct IDiscordActivityManager* activities; +} app; + +/* Now we get to our built-in stuff */ + +struct timer timer_callbacks = { .interval = 16 }; -void update_activity_callback(void* data, enum EDiscordResult result) -{ +struct config config = { + .display_title = 1, + .show_elapsed_time = 1 +}; + +/* CallWindowProc is the *only* function that ever needs this. */ +WNDPROC _old_wnd_proc = 0; + +/* ------------------------------------ */ + +void DISCORD_CALLBACK update_activity_callback(void* data, enum EDiscordResult result) { DISCORD_REQUIRE(result); } -void report_current_song_status(int playbackState) -{ - assert(playbackState != 0); - activity.timestamps.start = 0; - strcpy(activity.state, playbackState == 1 ? "(Playing)" : "(Paused)"); +void report_current_song_status(int playback_state) { + assert(playback_state != 0); + strcpy(activity.state, playback_state == 1 ? "(Playing)" : "(Paused)"); - if (playbackState == 1 && config.show_elapsed_time) { - FILETIME ft; - GetSystemTimeAsFileTime(&ft); - ULARGE_INTEGER ul; - ul.LowPart = ft.dwLowDateTime; - ul.HighPart = ft.dwHighDateTime; - long long dtn = ((ul.QuadPart - 116444736000000000ULL)/10000000); + activity.timestamps.start = (playback_state == 1 && config.show_elapsed_time) + ? get_system_time_in_milliseconds() - SendMessage(g_plugin.hwndParent, WM_WA_IPC, 0, IPC_GETOUTPUTTIME) / 1000 + : 0; - activity.timestamps.start = dtn - SendMessage(g_plugin.hwndParent, WM_WA_IPC, 0, IPC_GETOUTPUTTIME) / 1000; - } else { - activity.timestamps.start = 0; - } - - char* details_message = calloc(256, sizeof(char)); if (config.display_title) { wchar_t* title = (wchar_t*)SendMessageW(g_plugin.hwndParent, WM_WA_IPC, 0, IPC_GET_PLAYING_TITLE); - assert(WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, title, -1, details_message, 256, NULL, NULL)); - free(title); + assert(WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, title, -1, activity.details, 256, NULL, NULL)); } - strcpy(activity.details, details_message); - free(details_message); app.activities->update_activity(app.activities, &activity, &app, update_activity_callback); } @@ -93,41 +107,43 @@ void update_rich_presence_details(void) { - LONG isPlayingResult = SendMessageW(g_plugin.hwndParent, WM_WA_IPC, 0, IPC_ISPLAYING); + LONG is_playing = SendMessageW(g_plugin.hwndParent, WM_WA_IPC, 0, IPC_ISPLAYING); - switch (isPlayingResult) { + switch (is_playing) { case 0: report_idle_status(); break; case 1: case 3: - report_current_song_status(isPlayingResult); + report_current_song_status(is_playing); default: break; } } -LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ +void CALLBACK TimerProc(HWND, UINT, UINT_PTR, DWORD) { + DISCORD_REQUIRE(app.core->run_callbacks(app.core)); +} + +LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { if (message == WM_WA_IPC && lParam == IPC_CB_MISC && wParam == IPC_CB_MISC_STATUS) - { update_rich_presence_details(); - } - return CallWindowProc(g_lpWndProcOld, hwnd, message, wParam, lParam); + return CallWindowProc(_old_wnd_proc, hwnd, message, wParam, lParam); } +#define set_wnd_long(x) \ + (WNDPROC)SetWindowLong##x(g_plugin.hwndParent, GWLP_WNDPROC, (LONG)WndProc) int init() { memset(&app, 0, sizeof(app)); - if (IsWindowUnicode(g_plugin.hwndParent)) { - g_lpWndProcOld = (WNDPROC)SetWindowLongW(g_plugin.hwndParent, -4, (LONG)WndProc); - } else { - g_lpWndProcOld = (WNDPROC)SetWindowLongA(g_plugin.hwndParent, -4, (LONG)WndProc); - } - memset(&activity, 0, sizeof(activity)); memset(&activities_events, 0, sizeof(activities_events)); + if (IsWindowUnicode(g_plugin.hwndParent)) + _old_wnd_proc = set_wnd_long(W); + else + _old_wnd_proc = set_wnd_long(A); + struct DiscordCreateParams params; DiscordCreateParamsSetDefault(¶ms); params.client_id = CLIENT_ID; @@ -150,20 +166,17 @@ return 0; } +#undef set_wnd_long void quit() { assert(!cfg_save(config)); app.activities->clear_activity(app.activities, &app, update_activity_callback); } -void CALLBACK TimerProc(HWND, UINT, UINT_PTR, DWORD) { - DISCORD_REQUIRE(app.core->run_callbacks(app.core)); -} - void conf() { DialogBoxW(g_plugin.hDllInstance, (LPWSTR)DIALOG_CONFIG, g_plugin.hwndParent, (DLGPROC)cfg_win_proc); } -__declspec(dllexport) winamp_general_purpose_plugin* winampGetGeneralPurposePlugin() { +__declspec(dllexport) struct winamp_gpp* winampGetGeneralPurposePlugin() { return &g_plugin; } diff -r 8ce85aee15c0 -r be4835547dd0 src/timer.c --- a/src/timer.c Sat Dec 17 01:48:13 2022 +0000 +++ b/src/timer.c Fri Dec 16 20:35:06 2022 -0500 @@ -5,13 +5,13 @@ #include #include "timer.h" -void timer_init(struct timer_t* timer, HWND winampClientWindow, TIMERPROC timer_proc) { +void timer_init(struct timer* timer, HWND winampClientWindow, TIMERPROC timer_proc) { timer->winampClientWindow = winampClientWindow; timer->timer_proc = timer_proc; timer->initialized = 1; } -void timer_set(struct timer_t* timer, HWND winampClientWindow) { +void timer_set(struct timer* timer, HWND winampClientWindow) { assert(timer->initialized); if (timer->is_timer_alive) @@ -21,7 +21,7 @@ SetTimer(winampClientWindow, 1, timer->interval, timer->timer_proc); } -void timer_stop(struct timer_t* timer, HWND winampClientWindow) { +void timer_stop(struct timer* timer, HWND winampClientWindow) { assert(timer->initialized); if (!timer->is_timer_alive) diff -r 8ce85aee15c0 -r be4835547dd0 src/utils.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/utils.c Fri Dec 16 20:35:06 2022 -0500 @@ -0,0 +1,35 @@ +/** + * utils.c: + * + * Useful utilities for general use. +**/ +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include +#include + +uint64_t get_system_time_in_milliseconds(void) { + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + uint64_t ul = (uint64_t) ft.dwHighDateTime << 32 | ft.dwLowDateTime; + return ((ul - 116444736000000000ULL)/10000000); +} + +unsigned int crc32b(unsigned char *message) { + int i, j; + unsigned int byte, crc, mask; + + i = 0; + crc = 0xFFFFFFFF; + while (message[i] != 0) { + byte = message[i]; // Get next byte. + crc = crc ^ byte; + for (j = 7; j >= 0; j--) { // Do eight times. + mask = -(crc & 1); + crc = (crc >> 1) ^ (0xEDB88320 & mask); + } + i = i + 1; + } + return ~crc; +}