Mercurial > wgsdk
comparison src/main.c @ 7:be4835547dd0
clean up code, convert git files to hg, etc.
author | Paper |
---|---|
date | Fri, 16 Dec 2022 20:35:06 -0500 |
parents | 59bf702b2b21 |
children | 42ac054c0231 |
comparison
equal
deleted
inserted
replaced
6:8ce85aee15c0 | 7:be4835547dd0 |
---|---|
1 /** | |
2 * wgsdk - Winamp plugin for Discord's GameSDK | |
3 **/ | |
1 #include <assert.h> | 4 #include <assert.h> |
2 #include <stdio.h> | 5 #include <stdio.h> |
3 #include <stdlib.h> | 6 #include <stdlib.h> |
4 #include <Winamp/wa_ipc.h> | 7 #include <Winamp/wa_ipc.h> |
5 #include "main.h" | |
6 #include "discord_game_sdk.h" | 8 #include "discord_game_sdk.h" |
7 #include "timer.h" | 9 #include "timer.h" |
8 #include "config.h" | 10 #include "config.h" |
9 #include "resource.h" | 11 #include "resource.h" |
12 #include "utils.h" | |
10 #ifndef WIN32_LEAN_AND_MEAN | 13 #ifndef WIN32_LEAN_AND_MEAN |
11 # define WIN32_LEAN_AND_MEAN | 14 # define WIN32_LEAN_AND_MEAN |
12 #endif | 15 #endif |
13 #include <windows.h> | 16 #include <windows.h> |
14 #include <windowsx.h> | 17 #include <windowsx.h> |
17 #define DISCORD_REQUIRE(x) \ | 20 #define DISCORD_REQUIRE(x) \ |
18 assert(x == DiscordResult_Ok) | 21 assert(x == DiscordResult_Ok) |
19 | 22 |
20 #define GPPHDR_VER 0x10 | 23 #define GPPHDR_VER 0x10 |
21 | 24 |
22 winamp_general_purpose_plugin g_plugin = { | 25 int init(); |
26 void conf(); | |
27 void quit(); | |
28 | |
29 /* Winamp-specific stuff */ | |
30 struct winamp_gpp { | |
31 int version; // version of the plugin structure | |
32 char *description; // name/title of the plugin | |
33 int(*init)(); // function which will be executed on init event | |
34 void(*conf)(); // function which will be executed on config event | |
35 void(*quit)(); // function which will be executed on quit event | |
36 HWND hwndParent; // hwnd of the Winamp client main window (stored by Winamp when dll is loaded) | |
37 HINSTANCE hDllInstance; // hinstance of this plugin DLL. (stored by Winamp when dll is loaded) | |
38 }; | |
39 | |
40 struct winamp_gpp g_plugin = { | |
23 GPPHDR_VER, // version of the plugin, defined in "gen_myplugin.h" | 41 GPPHDR_VER, // version of the plugin, defined in "gen_myplugin.h" |
24 "Discord GameSDK", // name/title of the plugin, defined in "gen_myplugin.h" | 42 "Discord GameSDK", // name/title of the plugin, defined in "gen_myplugin.h" |
25 init, // function name which will be executed on init event | 43 init, // function name which will be executed on init event |
26 conf, // function name which will be executed on config event | 44 conf, // function name which will be executed on config event |
27 quit, // function name which will be executed on quit event | 45 quit, // function name which will be executed on quit event |
28 0, // handle to Winamp main window, loaded by winamp when this dll is loaded | 46 0, // handle to Winamp main window, loaded by winamp when this dll is loaded |
29 0 // hinstance to this dll, loaded by winamp when this dll is loaded | 47 0 // hinstance to this dll, loaded by winamp when this dll is loaded |
30 }; | 48 }; |
31 | 49 |
32 WNDPROC g_lpWndProcOld = 0; | 50 /* Discord stuff */ |
33 | |
34 struct timer_t timer_callbacks = { .interval = 16 }; | |
35 struct config config = { | |
36 .display_title = 1, | |
37 .show_elapsed_time = 1 | |
38 }; | |
39 | 51 |
40 struct DiscordActivity activity = { | 52 struct DiscordActivity activity = { |
41 .application_id = CLIENT_ID, | 53 .application_id = CLIENT_ID, |
42 .name = "Winamp", | 54 .name = "Winamp", |
43 .instance = 0 | 55 .instance = 0 |
44 }; | 56 }; |
45 | 57 |
46 struct IDiscordActivityEvents activities_events; | 58 struct IDiscordActivityEvents activities_events; |
47 | 59 |
48 struct app_t app; | 60 struct application { |
61 struct IDiscordCore* core; | |
62 struct IDiscordUsers* users; | |
63 struct IDiscordActivityManager* activities; | |
64 } app; | |
49 | 65 |
50 void update_activity_callback(void* data, enum EDiscordResult result) | 66 /* Now we get to our built-in stuff */ |
51 { | 67 |
68 struct timer timer_callbacks = { .interval = 16 }; | |
69 | |
70 struct config config = { | |
71 .display_title = 1, | |
72 .show_elapsed_time = 1 | |
73 }; | |
74 | |
75 /* CallWindowProc is the *only* function that ever needs this. */ | |
76 WNDPROC _old_wnd_proc = 0; | |
77 | |
78 /* ------------------------------------ */ | |
79 | |
80 void DISCORD_CALLBACK update_activity_callback(void* data, enum EDiscordResult result) { | |
52 DISCORD_REQUIRE(result); | 81 DISCORD_REQUIRE(result); |
53 } | 82 } |
54 | 83 |
55 void report_current_song_status(int playbackState) | 84 void report_current_song_status(int playback_state) { |
56 { | 85 assert(playback_state != 0); |
57 assert(playbackState != 0); | 86 strcpy(activity.state, playback_state == 1 ? "(Playing)" : "(Paused)"); |
58 activity.timestamps.start = 0; | |
59 strcpy(activity.state, playbackState == 1 ? "(Playing)" : "(Paused)"); | |
60 | 87 |
61 if (playbackState == 1 && config.show_elapsed_time) { | 88 activity.timestamps.start = (playback_state == 1 && config.show_elapsed_time) |
62 FILETIME ft; | 89 ? get_system_time_in_milliseconds() - SendMessage(g_plugin.hwndParent, WM_WA_IPC, 0, IPC_GETOUTPUTTIME) / 1000 |
63 GetSystemTimeAsFileTime(&ft); | 90 : 0; |
64 ULARGE_INTEGER ul; | |
65 ul.LowPart = ft.dwLowDateTime; | |
66 ul.HighPart = ft.dwHighDateTime; | |
67 long long dtn = ((ul.QuadPart - 116444736000000000ULL)/10000000); | |
68 | 91 |
69 activity.timestamps.start = dtn - SendMessage(g_plugin.hwndParent, WM_WA_IPC, 0, IPC_GETOUTPUTTIME) / 1000; | |
70 } else { | |
71 activity.timestamps.start = 0; | |
72 } | |
73 | |
74 char* details_message = calloc(256, sizeof(char)); | |
75 if (config.display_title) { | 92 if (config.display_title) { |
76 wchar_t* title = (wchar_t*)SendMessageW(g_plugin.hwndParent, WM_WA_IPC, 0, IPC_GET_PLAYING_TITLE); | 93 wchar_t* title = (wchar_t*)SendMessageW(g_plugin.hwndParent, WM_WA_IPC, 0, IPC_GET_PLAYING_TITLE); |
77 assert(WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, title, -1, details_message, 256, NULL, NULL)); | 94 assert(WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, title, -1, activity.details, 256, NULL, NULL)); |
78 free(title); | |
79 } | 95 } |
80 strcpy(activity.details, details_message); | |
81 free(details_message); | |
82 | 96 |
83 app.activities->update_activity(app.activities, &activity, &app, update_activity_callback); | 97 app.activities->update_activity(app.activities, &activity, &app, update_activity_callback); |
84 } | 98 } |
85 | 99 |
86 void report_idle_status(void) | 100 void report_idle_status(void) |
91 app.activities->update_activity(app.activities, &activity, &app, update_activity_callback); | 105 app.activities->update_activity(app.activities, &activity, &app, update_activity_callback); |
92 } | 106 } |
93 | 107 |
94 void update_rich_presence_details(void) | 108 void update_rich_presence_details(void) |
95 { | 109 { |
96 LONG isPlayingResult = SendMessageW(g_plugin.hwndParent, WM_WA_IPC, 0, IPC_ISPLAYING); | 110 LONG is_playing = SendMessageW(g_plugin.hwndParent, WM_WA_IPC, 0, IPC_ISPLAYING); |
97 | 111 |
98 switch (isPlayingResult) { | 112 switch (is_playing) { |
99 case 0: | 113 case 0: |
100 report_idle_status(); | 114 report_idle_status(); |
101 break; | 115 break; |
102 case 1: | 116 case 1: |
103 case 3: | 117 case 3: |
104 report_current_song_status(isPlayingResult); | 118 report_current_song_status(is_playing); |
105 default: | 119 default: |
106 break; | 120 break; |
107 } | 121 } |
108 } | 122 } |
109 | 123 |
110 LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) | 124 void CALLBACK TimerProc(HWND, UINT, UINT_PTR, DWORD) { |
111 { | 125 DISCORD_REQUIRE(app.core->run_callbacks(app.core)); |
112 if (message == WM_WA_IPC && lParam == IPC_CB_MISC && wParam == IPC_CB_MISC_STATUS) | |
113 { | |
114 update_rich_presence_details(); | |
115 } | |
116 | |
117 return CallWindowProc(g_lpWndProcOld, hwnd, message, wParam, lParam); | |
118 } | 126 } |
119 | 127 |
128 LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { | |
129 if (message == WM_WA_IPC && lParam == IPC_CB_MISC && wParam == IPC_CB_MISC_STATUS) | |
130 update_rich_presence_details(); | |
131 | |
132 return CallWindowProc(_old_wnd_proc, hwnd, message, wParam, lParam); | |
133 } | |
134 | |
135 #define set_wnd_long(x) \ | |
136 (WNDPROC)SetWindowLong##x(g_plugin.hwndParent, GWLP_WNDPROC, (LONG)WndProc) | |
120 int init() { | 137 int init() { |
121 memset(&app, 0, sizeof(app)); | 138 memset(&app, 0, sizeof(app)); |
122 if (IsWindowUnicode(g_plugin.hwndParent)) { | |
123 g_lpWndProcOld = (WNDPROC)SetWindowLongW(g_plugin.hwndParent, -4, (LONG)WndProc); | |
124 } else { | |
125 g_lpWndProcOld = (WNDPROC)SetWindowLongA(g_plugin.hwndParent, -4, (LONG)WndProc); | |
126 } | |
127 | |
128 memset(&activity, 0, sizeof(activity)); | 139 memset(&activity, 0, sizeof(activity)); |
129 memset(&activities_events, 0, sizeof(activities_events)); | 140 memset(&activities_events, 0, sizeof(activities_events)); |
141 | |
142 if (IsWindowUnicode(g_plugin.hwndParent)) | |
143 _old_wnd_proc = set_wnd_long(W); | |
144 else | |
145 _old_wnd_proc = set_wnd_long(A); | |
130 | 146 |
131 struct DiscordCreateParams params; | 147 struct DiscordCreateParams params; |
132 DiscordCreateParamsSetDefault(¶ms); | 148 DiscordCreateParamsSetDefault(¶ms); |
133 params.client_id = CLIENT_ID; | 149 params.client_id = CLIENT_ID; |
134 params.flags = DiscordCreateFlags_Default; | 150 params.flags = DiscordCreateFlags_Default; |
148 | 164 |
149 update_rich_presence_details(); | 165 update_rich_presence_details(); |
150 | 166 |
151 return 0; | 167 return 0; |
152 } | 168 } |
169 #undef set_wnd_long | |
153 | 170 |
154 void quit() { | 171 void quit() { |
155 assert(!cfg_save(config)); | 172 assert(!cfg_save(config)); |
156 app.activities->clear_activity(app.activities, &app, update_activity_callback); | 173 app.activities->clear_activity(app.activities, &app, update_activity_callback); |
157 } | 174 } |
158 | 175 |
159 void CALLBACK TimerProc(HWND, UINT, UINT_PTR, DWORD) { | |
160 DISCORD_REQUIRE(app.core->run_callbacks(app.core)); | |
161 } | |
162 | |
163 void conf() { | 176 void conf() { |
164 DialogBoxW(g_plugin.hDllInstance, (LPWSTR)DIALOG_CONFIG, g_plugin.hwndParent, (DLGPROC)cfg_win_proc); | 177 DialogBoxW(g_plugin.hDllInstance, (LPWSTR)DIALOG_CONFIG, g_plugin.hwndParent, (DLGPROC)cfg_win_proc); |
165 } | 178 } |
166 | 179 |
167 __declspec(dllexport) winamp_general_purpose_plugin* winampGetGeneralPurposePlugin() { | 180 __declspec(dllexport) struct winamp_gpp* winampGetGeneralPurposePlugin() { |
168 return &g_plugin; | 181 return &g_plugin; |
169 } | 182 } |