changeset 7:be4835547dd0

clean up code, convert git files to hg, etc.
author Paper
date Fri, 16 Dec 2022 20:35:06 -0500
parents 8ce85aee15c0
children 00399cc5f7ce
files .hgignore Makefile src/config.c src/dirtools.c src/include/timer.h src/include/utils.h src/main.c src/timer.c src/utils.c
diffstat 9 files changed, 180 insertions(+), 122 deletions(-) [+]
line wrap: on
line diff
--- /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
--- 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)
--- 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 <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #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 <windowsx.h>
 #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;
 }
--- 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 <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #ifndef WIN32_LEAN_AND_MEAN
-#  define WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
 #endif
 #include <windows.h>
 #include "dirtools.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 <windows.h>
 
-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
--- /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
--- 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 <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <Winamp/wa_ipc.h>
-#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(&params);
 	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;
 }
--- 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 <windows.h>
 #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)
--- /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 <windows.h>
+#include <stdint.h>
+
+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;
+}