From bc16157c9db9e2da8aebb87725a1a314c6906cce Mon Sep 17 00:00:00 2001 From: Jesse Chounard Date: Thu, 5 Feb 2026 08:20:24 -0600 Subject: [PATCH] testtray: created VS project and added new click callbacks --- VisualC/SDL.sln | 15 ++ VisualC/tests/testtray/testtray.vcxproj | 345 ++++++++++++++++++++++++ test/testtray.c | 89 +++++- 3 files changed, 441 insertions(+), 8 deletions(-) create mode 100644 VisualC/tests/testtray/testtray.vcxproj diff --git a/VisualC/SDL.sln b/VisualC/SDL.sln index 98d8793073..a942d5fca9 100644 --- a/VisualC/SDL.sln +++ b/VisualC/SDL.sln @@ -54,6 +54,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testsurround", "tests\tests EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testpen", "tests\testpen\testpen.vcxproj", "{C4E04D18-EF76-4B42-B4C2-16A1BACDC1A3}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testtray", "tests\testtray\testtray.vcxproj", "{E2AE0C33-D9C6-4B8E-BB65-6F8AF2F9EBD1}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{1498F0CD-F4DA-4847-9CB2-FB18D48061D5}" ProjectSection(SolutionItems) = preProject examples\Directory.Build.props = examples\Directory.Build.props @@ -469,6 +471,18 @@ Global {C4E04D18-EF76-4B42-B4C2-16A1BACDC1A3}.Release|Win32.Build.0 = Release|Win32 {C4E04D18-EF76-4B42-B4C2-16A1BACDC1A3}.Release|x64.ActiveCfg = Release|x64 {C4E04D18-EF76-4B42-B4C2-16A1BACDC1A3}.Release|x64.Build.0 = Release|x64 + {E2AE0C33-D9C6-4B8E-BB65-6F8AF2F9EBD1}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {E2AE0C33-D9C6-4B8E-BB65-6F8AF2F9EBD1}.Debug|ARM64.Build.0 = Debug|ARM64 + {E2AE0C33-D9C6-4B8E-BB65-6F8AF2F9EBD1}.Debug|Win32.ActiveCfg = Debug|Win32 + {E2AE0C33-D9C6-4B8E-BB65-6F8AF2F9EBD1}.Debug|Win32.Build.0 = Debug|Win32 + {E2AE0C33-D9C6-4B8E-BB65-6F8AF2F9EBD1}.Debug|x64.ActiveCfg = Debug|x64 + {E2AE0C33-D9C6-4B8E-BB65-6F8AF2F9EBD1}.Debug|x64.Build.0 = Debug|x64 + {E2AE0C33-D9C6-4B8E-BB65-6F8AF2F9EBD1}.Release|ARM64.ActiveCfg = Release|ARM64 + {E2AE0C33-D9C6-4B8E-BB65-6F8AF2F9EBD1}.Release|ARM64.Build.0 = Release|ARM64 + {E2AE0C33-D9C6-4B8E-BB65-6F8AF2F9EBD1}.Release|Win32.ActiveCfg = Release|Win32 + {E2AE0C33-D9C6-4B8E-BB65-6F8AF2F9EBD1}.Release|Win32.Build.0 = Release|Win32 + {E2AE0C33-D9C6-4B8E-BB65-6F8AF2F9EBD1}.Release|x64.ActiveCfg = Release|x64 + {E2AE0C33-D9C6-4B8E-BB65-6F8AF2F9EBD1}.Release|x64.Build.0 = Release|x64 {EB448819-74BC-40C9-A61A-4D4ECD55F9D5}.Debug|ARM64.ActiveCfg = Debug|ARM64 {EB448819-74BC-40C9-A61A-4D4ECD55F9D5}.Debug|ARM64.Build.0 = Debug|ARM64 {EB448819-74BC-40C9-A61A-4D4ECD55F9D5}.Debug|Win32.ActiveCfg = Debug|Win32 @@ -930,6 +944,7 @@ Global {C4E04D18-EF76-4B42-B4C2-16A1BACDC0A4} = {D69D5741-611F-4E14-8541-1FEE94F50B5A} {70B894A9-E306-49E8-ABC2-932A952A5E5F} = {D69D5741-611F-4E14-8541-1FEE94F50B5A} {C4E04D18-EF76-4B42-B4C2-16A1BACDC1A3} = {D69D5741-611F-4E14-8541-1FEE94F50B5A} + {E2AE0C33-D9C6-4B8E-BB65-6F8AF2F9EBD1} = {D69D5741-611F-4E14-8541-1FEE94F50B5A} {1B61A1B7-92DE-4C37-9151-D2928D6449AB} = {1498F0CD-F4DA-4847-9CB2-FB18D48061D5} {EB448819-74BC-40C9-A61A-4D4ECD55F9D5} = {1B61A1B7-92DE-4C37-9151-D2928D6449AB} {6B710DFF-8A4A-40A2-BF2D-88D266F3D4F0} = {1B61A1B7-92DE-4C37-9151-D2928D6449AB} diff --git a/VisualC/tests/testtray/testtray.vcxproj b/VisualC/tests/testtray/testtray.vcxproj new file mode 100644 index 0000000000..a4f22ad594 --- /dev/null +++ b/VisualC/tests/testtray/testtray.vcxproj @@ -0,0 +1,345 @@ + + + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {E2AE0C33-D9C6-4B8E-BB65-6F8AF2F9EBD1} + testtray + 10.0 + + + + Application + $(DefaultPlatformToolset) + + + Application + $(DefaultPlatformToolset) + + + Application + $(DefaultPlatformToolset) + + + Application + $(DefaultPlatformToolset) + + + Application + $(DefaultPlatformToolset) + + + Application + $(DefaultPlatformToolset) + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + AllRules.ruleset + + + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + + + AllRules.ruleset + AllRules.ruleset + + + + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Debug/testtray.tlb + + + %(AdditionalOptions) /utf-8 + Disabled + $(SolutionDir)/../include;%(AdditionalIncludeDirectories) + %(AdditionalUsingDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + OldStyle + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + true + Windows + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + X64 + .\Debug/testtray.tlb + + + %(AdditionalOptions) /utf-8 + Disabled + $(SolutionDir)/../include;%(AdditionalIncludeDirectories) + %(AdditionalUsingDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + OldStyle + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + true + Windows + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\Debug/testtray.tlb + + + %(AdditionalOptions) /utf-8 + Disabled + $(SolutionDir)/../include;%(AdditionalIncludeDirectories) + %(AdditionalUsingDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + OldStyle + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + true + Windows + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Release/testtray.tlb + + + %(AdditionalOptions) /utf-8 + $(SolutionDir)/../include;%(AdditionalIncludeDirectories) + %(AdditionalUsingDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + Windows + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + X64 + .\Release/testtray.tlb + + + %(AdditionalOptions) /utf-8 + $(SolutionDir)/../include;%(AdditionalIncludeDirectories) + %(AdditionalUsingDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + Windows + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\Release/testtray.tlb + + + %(AdditionalOptions) /utf-8 + $(SolutionDir)/../include;%(AdditionalIncludeDirectories) + %(AdditionalUsingDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + Windows + + + + + $(TreatWarningsAsError) + + + + + {81ce8daf-ebb2-4761-8e45-b71abcca8c68} + false + false + true + + + {da956fd3-e143-46f2-9fe5-c77bebc56b1a} + false + false + true + + + + + Copying %(Filename)%(Extension) + copy "%(FullPath)" "$(ProjectDir)\" + + $(ProjectDir)\%(Filename)%(Extension);%(Outputs) + Copying %(Filename)%(Extension) + Copying %(Filename)%(Extension) + copy "%(FullPath)" "$(ProjectDir)\" + + copy "%(FullPath)" "$(ProjectDir)\" + + $(ProjectDir)\%(Filename)%(Extension);%(Outputs) + $(ProjectDir)\%(Filename)%(Extension);%(Outputs) + Copying %(Filename)%(Extension) + copy "%(FullPath)" "$(ProjectDir)\" + + $(ProjectDir)\%(Filename)%(Extension);%(Outputs) + Copying %(Filename)%(Extension) + Copying %(Filename)%(Extension) + copy "%(FullPath)" "$(ProjectDir)\" + + copy "%(FullPath)" "$(ProjectDir)\" + + $(ProjectDir)\%(Filename)%(Extension);%(Outputs) + $(ProjectDir)\%(Filename)%(Extension);%(Outputs) + + + Copying %(Filename)%(Extension) + copy "%(FullPath)" "$(ProjectDir)\" + + $(ProjectDir)\%(Filename)%(Extension);%(Outputs) + Copying %(Filename)%(Extension) + Copying %(Filename)%(Extension) + copy "%(FullPath)" "$(ProjectDir)\" + + copy "%(FullPath)" "$(ProjectDir)\" + + $(ProjectDir)\%(Filename)%(Extension);%(Outputs) + $(ProjectDir)\%(Filename)%(Extension);%(Outputs) + Copying %(Filename)%(Extension) + copy "%(FullPath)" "$(ProjectDir)\" + + $(ProjectDir)\%(Filename)%(Extension);%(Outputs) + Copying %(Filename)%(Extension) + Copying %(Filename)%(Extension) + copy "%(FullPath)" "$(ProjectDir)\" + + copy "%(FullPath)" "$(ProjectDir)\" + + $(ProjectDir)\%(Filename)%(Extension);%(Outputs) + $(ProjectDir)\%(Filename)%(Extension);%(Outputs) + + + + + + + + + + diff --git a/test/testtray.c b/test/testtray.c index e4c3fd02bf..3a4fabfc4d 100644 --- a/test/testtray.c +++ b/test/testtray.c @@ -3,6 +3,35 @@ #include #include +/* + * testtray - SDL system tray API test application + * + * This program creates two system tray icons to demonstrate and test the + * SDL tray API: + * + * 1. Control tray (sdl-test_round.png) - Provides a menu to: + * - Quit: Exit the application + * - Destroy trays: Remove both tray icons and show the window + * - Hide/Show window: Toggle the window visibility + * - Change icon: Change the example tray's icon via file dialog + * - Create button/checkbox/submenu/separator: Add menu items to the + * example tray, demonstrating dynamic menu construction + * + * 2. Example tray (speaker.png) - A target tray that can be manipulated + * through the control tray's menu. Menu items created here can be + * enabled, disabled, checked, unchecked, or removed via submenus that + * appear in the control tray. This tray is created with + * SDL_CreateTrayWithProperties to demonstrate click callbacks: + * - Left click: Logs a message and shows the menu (returns true) + * - Right click: Logs a message and suppresses the menu (returns false) + * + * Window behavior: + * - Closing the window (X button) hides it to the tray rather than exiting + * - The "Hide/Show window" menu item toggles visibility and updates its label + * - If trays are destroyed while the window is hidden, it is shown first + * - If trays are destroyed, closing the window exits the application + */ + static void SDLCALL tray_quit(void *ptr, SDL_TrayEntry *entry) { SDL_Event e; @@ -10,7 +39,21 @@ static void SDLCALL tray_quit(void *ptr, SDL_TrayEntry *entry) SDL_PushEvent(&e); } +static bool SDLCALL tray2_leftclick(void *userdata, SDL_Tray *tray) +{ + SDL_Log("Left click on example tray - menu shown"); + return true; +} + +static bool SDLCALL tray2_rightclick(void *userdata, SDL_Tray *tray) +{ + SDL_Log("Right click on example tray - menu suppressed"); + return false; +} + static bool trays_destroyed = false; +static SDL_Window *window = NULL; +static SDL_TrayEntry *entry_toggle = NULL; static void SDLCALL tray_close(void *ptr, SDL_TrayEntry *entry) { @@ -18,10 +61,25 @@ static void SDLCALL tray_close(void *ptr, SDL_TrayEntry *entry) trays_destroyed = true; + if (window) { + SDL_ShowWindow(window); + } + SDL_DestroyTray(trays[0]); SDL_DestroyTray(trays[1]); } +static void SDLCALL toggle_window(void *ptr, SDL_TrayEntry *entry) +{ + if (SDL_GetWindowFlags(window) & SDL_WINDOW_HIDDEN) { + SDL_ShowWindow(window); + SDL_SetTrayEntryLabel(entry, "Hide window"); + } else { + SDL_HideWindow(window); + SDL_SetTrayEntryLabel(entry, "Show window"); + } +} + static void SDLCALL apply_icon(void *ptr, const char * const *filelist, int filter) { if (!*filelist) { @@ -514,9 +572,9 @@ int main(int argc, char **argv) return 1; } - SDL_Window *w = SDL_CreateWindow("testtray", 640, 480, 0); + window = SDL_CreateWindow("testtray", 640, 480, 0); - if (!w) { + if (!window) { SDL_Log("Couldn't create window: %s", SDL_GetError()); goto quit; } @@ -544,7 +602,13 @@ int main(int argc, char **argv) goto clean_window; } - SDL_Tray *tray2 = SDL_CreateTray(icon2, "SDL Tray example"); + SDL_PropertiesID tray2_props = SDL_CreateProperties(); + SDL_SetPointerProperty(tray2_props, SDL_PROP_TRAY_CREATE_ICON_POINTER, icon2); + SDL_SetStringProperty(tray2_props, SDL_PROP_TRAY_CREATE_TOOLTIP_STRING, "SDL Tray example"); + SDL_SetPointerProperty(tray2_props, SDL_PROP_TRAY_CREATE_LEFTCLICK_CALLBACK_POINTER, tray2_leftclick); + SDL_SetPointerProperty(tray2_props, SDL_PROP_TRAY_CREATE_RIGHTCLICK_CALLBACK_POINTER, tray2_rightclick); + SDL_Tray *tray2 = SDL_CreateTrayWithProperties(tray2_props); + SDL_DestroyProperties(tray2_props); if (!tray2) { SDL_Log("Couldn't create example tray: %s", SDL_GetError()); @@ -569,7 +633,7 @@ int main(int argc, char **argv) SDL_TrayEntry *entry_quit = SDL_InsertTrayEntryAt(menu, -1, "Quit", SDL_TRAYENTRY_BUTTON); CHECK(entry_quit); - SDL_TrayEntry *entry_close = SDL_InsertTrayEntryAt(menu, -1, "Close", SDL_TRAYENTRY_BUTTON); + SDL_TrayEntry *entry_close = SDL_InsertTrayEntryAt(menu, -1, "Destroy trays", SDL_TRAYENTRY_BUTTON); CHECK(entry_close); /* TODO: Track memory! */ @@ -586,6 +650,13 @@ int main(int argc, char **argv) SDL_InsertTrayEntryAt(menu, -1, NULL, 0); + entry_toggle = SDL_InsertTrayEntryAt(menu, -1, "Hide window", SDL_TRAYENTRY_BUTTON); + CHECK(entry_toggle); + + SDL_SetTrayEntryCallback(entry_toggle, toggle_window, NULL); + + SDL_InsertTrayEntryAt(menu, -1, NULL, 0); + SDL_TrayEntry *entry_icon = SDL_InsertTrayEntryAt(menu, -1, "Change icon", SDL_TRAYENTRY_BUTTON); CHECK(entry_icon); @@ -620,8 +691,10 @@ int main(int argc, char **argv) if (e.type == SDL_EVENT_QUIT) { break; } else if (e.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED) { - SDL_DestroyWindow(w); - w = NULL; + if (trays_destroyed) { + break; + } + toggle_window(NULL, entry_toggle); } } @@ -637,8 +710,8 @@ clean_tray1: SDL_free(trays); clean_window: - if (w) { - SDL_DestroyWindow(w); + if (window) { + SDL_DestroyWindow(window); } quit: