Atlas - testtray.c
Home / ext / SDL / test Lines: 1 | Size: 21596 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1#include "testutils.h" 2#include <SDL3/SDL.h> 3#include <SDL3/SDL_main.h> 4#include <SDL3/SDL_test.h> 5 6/* 7 * testtray - SDL system tray API test application 8 * 9 * This program creates two system tray icons to demonstrate and test the 10 * SDL tray API: 11 * 12 * 1. Control tray (sdl-test_round.png) - Provides a menu to: 13 * - Quit: Exit the application 14 * - Destroy trays: Remove both tray icons and show the window 15 * - Hide/Show window: Toggle the window visibility 16 * - Change icon: Change the example tray's icon via file dialog 17 * - Create button/checkbox/submenu/separator: Add menu items to the 18 * example tray, demonstrating dynamic menu construction 19 * 20 * 2. Example tray (speaker.png) - A target tray that can be manipulated 21 * through the control tray's menu. Menu items created here can be 22 * enabled, disabled, checked, unchecked, or removed via submenus that 23 * appear in the control tray. This tray is created with 24 * SDL_CreateTrayWithProperties to demonstrate click callbacks: 25 * - Left click: Logs a message and shows the menu (returns true) 26 * - Right click: Logs a message and suppresses the menu (returns false) 27 * - Middle click: Logs a message (menu never shows for middle click) 28 * 29 * Window behavior: 30 * - Closing the window (X button) hides it to the tray rather than exiting 31 * - The "Hide/Show window" menu item toggles visibility and updates its label 32 * - If trays are destroyed while the window is hidden, it is shown first 33 * - If trays are destroyed, closing the window exits the application 34 */ 35 36static void SDLCALL tray_quit(void *ptr, SDL_TrayEntry *entry) 37{ 38 SDL_Event e; 39 e.type = SDL_EVENT_QUIT; 40 SDL_PushEvent(&e); 41} 42 43static bool SDLCALL tray2_leftclick(void *userdata, SDL_Tray *tray) 44{ 45 SDL_Log("Left click on example tray - menu shown"); 46 return true; 47} 48 49static bool SDLCALL tray2_rightclick(void *userdata, SDL_Tray *tray) 50{ 51 SDL_Log("Right click on example tray - menu suppressed"); 52 return false; 53} 54 55static bool SDLCALL tray2_middleclick(void *userdata, SDL_Tray *tray) 56{ 57 SDL_Log("Middle click on example tray - menu doesn't show for middle click"); 58 return false; 59} 60 61static bool trays_destroyed = false; 62static SDL_Window *window = NULL; 63static SDL_TrayEntry *entry_toggle = NULL; 64 65static void SDLCALL tray_close(void *ptr, SDL_TrayEntry *entry) 66{ 67 SDL_Tray **trays = (SDL_Tray **) ptr; 68 69 trays_destroyed = true; 70 71 if (window) { 72 SDL_ShowWindow(window); 73 } 74 75 SDL_DestroyTray(trays[0]); 76 SDL_DestroyTray(trays[1]); 77} 78 79static void SDLCALL toggle_window(void *ptr, SDL_TrayEntry *entry) 80{ 81 if (SDL_GetWindowFlags(window) & SDL_WINDOW_HIDDEN) { 82 SDL_ShowWindow(window); 83 SDL_SetTrayEntryLabel(entry, "Hide window"); 84 } else { 85 SDL_HideWindow(window); 86 SDL_SetTrayEntryLabel(entry, "Show window"); 87 } 88} 89 90static void SDLCALL apply_icon(void *ptr, const char * const *filelist, int filter) 91{ 92 if (!*filelist) { 93 return; 94 } 95 96 SDL_Surface *icon = SDL_LoadPNG(*filelist); 97 98 if (!icon) { 99 SDL_Log("Couldn't load icon '%s': %s", *filelist, SDL_GetError()); 100 return; 101 } 102 103 SDL_Tray *tray = (SDL_Tray *) ptr; 104 SDL_SetTrayIcon(tray, icon); 105 106 SDL_DestroySurface(icon); 107} 108 109static void SDLCALL change_icon(void *ptr, SDL_TrayEntry *entry) 110{ 111 SDL_DialogFileFilter filters[] = { 112 { "PNG image files", "png" }, 113 { "All files", "*" }, 114 }; 115 116 SDL_ShowOpenFileDialog(apply_icon, ptr, NULL, filters, 2, NULL, 0); 117} 118 119static void SDLCALL print_entry(void *ptr, SDL_TrayEntry *entry) 120{ 121 SDL_Log("Clicked on button '%s'", SDL_GetTrayEntryLabel(entry)); 122} 123 124static void SDLCALL set_entry_enabled(void *ptr, SDL_TrayEntry *entry) 125{ 126 SDL_TrayEntry *target = (SDL_TrayEntry *) ptr; 127 SDL_SetTrayEntryEnabled(target, true); 128} 129 130static void SDLCALL set_entry_disabled(void *ptr, SDL_TrayEntry *entry) 131{ 132 SDL_TrayEntry *target = (SDL_TrayEntry *) ptr; 133 SDL_SetTrayEntryEnabled(target, false); 134} 135 136static void SDLCALL set_entry_checked(void *ptr, SDL_TrayEntry *entry) 137{ 138 SDL_TrayEntry *target = (SDL_TrayEntry *) ptr; 139 SDL_SetTrayEntryChecked(target, true); 140} 141 142static void SDLCALL set_entry_unchecked(void *ptr, SDL_TrayEntry *entry) 143{ 144 SDL_TrayEntry *target = (SDL_TrayEntry *) ptr; 145 SDL_SetTrayEntryChecked(target, false); 146} 147 148static void SDLCALL remove_entry(void *ptr, SDL_TrayEntry *entry) 149{ 150 SDL_TrayEntry *target = (SDL_TrayEntry *) ptr; 151 SDL_RemoveTrayEntry(target); 152 153 SDL_TrayMenu *ctrl_submenu = SDL_GetTrayEntryParent(entry); 154 SDL_TrayEntry *ctrl_entry = SDL_GetTrayMenuParentEntry(ctrl_submenu); 155 156 if (!ctrl_entry) { 157 SDL_Log("Attempt to remove a menu that isn't a submenu. This shouldn't happen."); 158 return; 159 } 160 161 SDL_RemoveTrayEntry(ctrl_entry); 162} 163 164static void SDLCALL append_button_to(void *ptr, SDL_TrayEntry *entry) 165{ 166 SDL_TrayMenu *menu = (SDL_TrayMenu *) ptr; 167 SDL_TrayMenu *submenu; 168 SDL_TrayEntry *new_ctrl; 169 SDL_TrayEntry *new_ctrl_remove; 170 SDL_TrayEntry *new_ctrl_enabled; 171 SDL_TrayEntry *new_ctrl_disabled; 172 SDL_TrayEntry *new_example; 173 174 new_ctrl = SDL_InsertTrayEntryAt(SDL_GetTrayEntryParent(entry), -1, "New button", SDL_TRAYENTRY_SUBMENU); 175 176 if (!new_ctrl) { 177 SDL_Log("Couldn't insert entry in control tray: %s", SDL_GetError()); 178 return; 179 } 180 181 /* ---------- */ 182 183 submenu = SDL_CreateTraySubmenu(new_ctrl); 184 185 if (!new_ctrl) { 186 SDL_Log("Couldn't create control tray entry submenu: %s", SDL_GetError()); 187 SDL_RemoveTrayEntry(new_ctrl); 188 return; 189 } 190 191 /* ---------- */ 192 193 new_example = SDL_InsertTrayEntryAt(menu, -1, "New button", SDL_TRAYENTRY_BUTTON); 194 195 if (new_example == NULL) { 196 SDL_Log("Couldn't insert entry in example tray: %s", SDL_GetError()); 197 SDL_RemoveTrayEntry(new_ctrl); 198 return; 199 } 200 201 SDL_SetTrayEntryCallback(new_example, print_entry, NULL); 202 203 /* ---------- */ 204 205 new_ctrl_remove = SDL_InsertTrayEntryAt(submenu, -1, "Remove", SDL_TRAYENTRY_BUTTON); 206 207 if (new_ctrl_remove == NULL) { 208 SDL_Log("Couldn't insert new_ctrl_remove: %s", SDL_GetError()); 209 SDL_RemoveTrayEntry(new_ctrl); 210 SDL_RemoveTrayEntry(new_example); 211 return; 212 } 213 214 SDL_SetTrayEntryCallback(new_ctrl_remove, remove_entry, new_example); 215 216 /* ---------- */ 217 218 new_ctrl_enabled = SDL_InsertTrayEntryAt(submenu, -1, "Enable", SDL_TRAYENTRY_BUTTON); 219 220 if (new_ctrl_enabled == NULL) { 221 SDL_Log("Couldn't insert new_ctrl_enabled: %s", SDL_GetError()); 222 SDL_RemoveTrayEntry(new_ctrl); 223 SDL_RemoveTrayEntry(new_example); 224 return; 225 } 226 227 SDL_SetTrayEntryCallback(new_ctrl_enabled, set_entry_enabled, new_example); 228 229 /* ---------- */ 230 231 new_ctrl_disabled = SDL_InsertTrayEntryAt(submenu, -1, "Disable", SDL_TRAYENTRY_BUTTON); 232 233 if (new_ctrl_disabled == NULL) { 234 SDL_Log("Couldn't insert new_ctrl_disabled: %s", SDL_GetError()); 235 SDL_RemoveTrayEntry(new_ctrl); 236 SDL_RemoveTrayEntry(new_example); 237 return; 238 } 239 240 SDL_SetTrayEntryCallback(new_ctrl_disabled, set_entry_disabled, new_example); 241} 242 243static void SDLCALL append_checkbox_to(void *ptr, SDL_TrayEntry *entry) 244{ 245 SDL_TrayMenu *menu = (SDL_TrayMenu *) ptr; 246 SDL_TrayMenu *submenu; 247 SDL_TrayEntry *new_ctrl; 248 SDL_TrayEntry *new_ctrl_remove; 249 SDL_TrayEntry *new_ctrl_enabled; 250 SDL_TrayEntry *new_ctrl_disabled; 251 SDL_TrayEntry *new_ctrl_checked; 252 SDL_TrayEntry *new_ctrl_unchecked; 253 SDL_TrayEntry *new_example; 254 255 new_ctrl = SDL_InsertTrayEntryAt(SDL_GetTrayEntryParent(entry), -1, "New checkbox", SDL_TRAYENTRY_SUBMENU); 256 257 if (!new_ctrl) { 258 SDL_Log("Couldn't insert entry in control tray: %s", SDL_GetError()); 259 return; 260 } 261 262 /* ---------- */ 263 264 submenu = SDL_CreateTraySubmenu(new_ctrl); 265 266 if (!new_ctrl) { 267 SDL_Log("Couldn't create control tray entry submenu: %s", SDL_GetError()); 268 SDL_RemoveTrayEntry(new_ctrl); 269 return; 270 } 271 272 /* ---------- */ 273 274 new_example = SDL_InsertTrayEntryAt(menu, -1, "New checkbox", SDL_TRAYENTRY_CHECKBOX); 275 276 if (new_example == NULL) { 277 SDL_Log("Couldn't insert entry in example tray: %s", SDL_GetError()); 278 SDL_RemoveTrayEntry(new_ctrl); 279 return; 280 } 281 282 SDL_SetTrayEntryCallback(new_example, print_entry, NULL); 283 284 /* ---------- */ 285 286 new_ctrl_remove = SDL_InsertTrayEntryAt(submenu, -1, "Remove", SDL_TRAYENTRY_BUTTON); 287 288 if (new_ctrl_remove == NULL) { 289 SDL_Log("Couldn't insert new_ctrl_remove: %s", SDL_GetError()); 290 SDL_RemoveTrayEntry(new_ctrl); 291 SDL_RemoveTrayEntry(new_example); 292 return; 293 } 294 295 SDL_SetTrayEntryCallback(new_ctrl_remove, remove_entry, new_example); 296 297 /* ---------- */ 298 299 new_ctrl_enabled = SDL_InsertTrayEntryAt(submenu, -1, "Enable", SDL_TRAYENTRY_BUTTON); 300 301 if (new_ctrl_enabled == NULL) { 302 SDL_Log("Couldn't insert new_ctrl_enabled: %s", SDL_GetError()); 303 SDL_RemoveTrayEntry(new_ctrl); 304 SDL_RemoveTrayEntry(new_example); 305 return; 306 } 307 308 SDL_SetTrayEntryCallback(new_ctrl_enabled, set_entry_enabled, new_example); 309 310 /* ---------- */ 311 312 new_ctrl_disabled = SDL_InsertTrayEntryAt(submenu, -1, "Disable", SDL_TRAYENTRY_BUTTON); 313 314 if (new_ctrl_disabled == NULL) { 315 SDL_Log("Couldn't insert new_ctrl_disabled: %s", SDL_GetError()); 316 SDL_RemoveTrayEntry(new_ctrl); 317 SDL_RemoveTrayEntry(new_example); 318 return; 319 } 320 321 SDL_SetTrayEntryCallback(new_ctrl_disabled, set_entry_disabled, new_example); 322 323 /* ---------- */ 324 325 new_ctrl_checked = SDL_InsertTrayEntryAt(submenu, -1, "Check", SDL_TRAYENTRY_BUTTON); 326 327 if (new_ctrl_checked == NULL) { 328 SDL_Log("Couldn't insert new_ctrl_checked: %s", SDL_GetError()); 329 SDL_RemoveTrayEntry(new_ctrl); 330 SDL_RemoveTrayEntry(new_example); 331 return; 332 } 333 334 SDL_SetTrayEntryCallback(new_ctrl_checked, set_entry_checked, new_example); 335 336 /* ---------- */ 337 338 new_ctrl_unchecked = SDL_InsertTrayEntryAt(submenu, -1, "Uncheck", SDL_TRAYENTRY_BUTTON); 339 340 if (new_ctrl_unchecked == NULL) { 341 SDL_Log("Couldn't insert new_ctrl_unchecked: %s", SDL_GetError()); 342 SDL_RemoveTrayEntry(new_ctrl); 343 SDL_RemoveTrayEntry(new_example); 344 return; 345 } 346 347 SDL_SetTrayEntryCallback(new_ctrl_unchecked, set_entry_unchecked, new_example); 348} 349 350static void SDLCALL append_separator_to(void *ptr, SDL_TrayEntry *entry) 351{ 352 SDL_TrayMenu *menu = (SDL_TrayMenu *) ptr; 353 SDL_TrayMenu *submenu; 354 SDL_TrayEntry *new_ctrl; 355 SDL_TrayEntry *new_ctrl_remove; 356 SDL_TrayEntry *new_example; 357 358 new_ctrl = SDL_InsertTrayEntryAt(SDL_GetTrayEntryParent(entry), -1, "[Separator]", SDL_TRAYENTRY_SUBMENU); 359 360 if (!new_ctrl) { 361 SDL_Log("Couldn't insert entry in control tray: %s", SDL_GetError()); 362 return; 363 } 364 365 /* ---------- */ 366 367 submenu = SDL_CreateTraySubmenu(new_ctrl); 368 369 if (!new_ctrl) { 370 SDL_Log("Couldn't create control tray entry submenu: %s", SDL_GetError()); 371 SDL_RemoveTrayEntry(new_ctrl); 372 return; 373 } 374 375 /* ---------- */ 376 377 new_example = SDL_InsertTrayEntryAt(menu, -1, NULL, SDL_TRAYENTRY_BUTTON); 378 379 if (new_example == NULL) { 380 SDL_Log("Couldn't insert separator in example tray: %s", SDL_GetError()); 381 SDL_RemoveTrayEntry(new_ctrl); 382 return; 383 } 384 385 /* ---------- */ 386 387 new_ctrl_remove = SDL_InsertTrayEntryAt(submenu, -1, "Remove", SDL_TRAYENTRY_BUTTON); 388 389 if (new_ctrl_remove == NULL) { 390 SDL_Log("Couldn't insert new_ctrl_remove: %s", SDL_GetError()); 391 SDL_RemoveTrayEntry(new_ctrl); 392 SDL_RemoveTrayEntry(new_example); 393 return; 394 } 395 396 SDL_SetTrayEntryCallback(new_ctrl_remove, remove_entry, new_example); 397} 398 399static void SDLCALL append_submenu_to(void *ptr, SDL_TrayEntry *entry) 400{ 401 SDL_TrayMenu *menu = (SDL_TrayMenu *) ptr; 402 SDL_TrayMenu *submenu; 403 SDL_TrayMenu *entry_submenu; 404 SDL_TrayEntry *new_ctrl; 405 SDL_TrayEntry *new_ctrl_remove; 406 SDL_TrayEntry *new_ctrl_enabled; 407 SDL_TrayEntry *new_ctrl_disabled; 408 SDL_TrayEntry *new_example; 409 410 new_ctrl = SDL_InsertTrayEntryAt(SDL_GetTrayEntryParent(entry), -1, "New submenu", SDL_TRAYENTRY_SUBMENU); 411 412 if (!new_ctrl) { 413 SDL_Log("Couldn't insert entry in control tray: %s", SDL_GetError()); 414 return; 415 } 416 417 /* ---------- */ 418 419 submenu = SDL_CreateTraySubmenu(new_ctrl); 420 421 if (!new_ctrl) { 422 SDL_Log("Couldn't create control tray entry submenu: %s", SDL_GetError()); 423 SDL_RemoveTrayEntry(new_ctrl); 424 return; 425 } 426 427 /* ---------- */ 428 429 new_example = SDL_InsertTrayEntryAt(menu, -1, "New submenu", SDL_TRAYENTRY_SUBMENU); 430 431 if (new_example == NULL) { 432 SDL_Log("Couldn't insert entry in example tray: %s", SDL_GetError()); 433 SDL_RemoveTrayEntry(new_ctrl); 434 return; 435 } 436 437 SDL_SetTrayEntryCallback(new_example, print_entry, NULL); 438 439 /* ---------- */ 440 441 entry_submenu = SDL_CreateTraySubmenu(new_example); 442 443 if (entry_submenu == NULL) { 444 SDL_Log("Couldn't create new entry submenu: %s", SDL_GetError()); 445 SDL_RemoveTrayEntry(new_ctrl); 446 SDL_RemoveTrayEntry(new_example); 447 return; 448 } 449 450 /* ---------- */ 451 452 new_ctrl_remove = SDL_InsertTrayEntryAt(submenu, -1, "Remove", SDL_TRAYENTRY_BUTTON); 453 454 if (new_ctrl_remove == NULL) { 455 SDL_Log("Couldn't insert new_ctrl_remove: %s", SDL_GetError()); 456 SDL_RemoveTrayEntry(new_ctrl); 457 SDL_RemoveTrayEntry(new_example); 458 return; 459 } 460 461 SDL_SetTrayEntryCallback(new_ctrl_remove, remove_entry, new_example); 462 463 /* ---------- */ 464 465 new_ctrl_enabled = SDL_InsertTrayEntryAt(submenu, -1, "Enable", SDL_TRAYENTRY_BUTTON); 466 467 if (new_ctrl_enabled == NULL) { 468 SDL_Log("Couldn't insert new_ctrl_enabled: %s", SDL_GetError()); 469 SDL_RemoveTrayEntry(new_ctrl); 470 SDL_RemoveTrayEntry(new_example); 471 return; 472 } 473 474 SDL_SetTrayEntryCallback(new_ctrl_enabled, set_entry_enabled, new_example); 475 476 /* ---------- */ 477 478 new_ctrl_disabled = SDL_InsertTrayEntryAt(submenu, -1, "Disable", SDL_TRAYENTRY_BUTTON); 479 480 if (new_ctrl_disabled == NULL) { 481 SDL_Log("Couldn't insert new_ctrl_disabled: %s", SDL_GetError()); 482 SDL_RemoveTrayEntry(new_ctrl); 483 SDL_RemoveTrayEntry(new_example); 484 return; 485 } 486 487 SDL_SetTrayEntryCallback(new_ctrl_disabled, set_entry_disabled, new_example); 488 489 /* ---------- */ 490 491 SDL_InsertTrayEntryAt(submenu, -1, NULL, 0); 492 493 /* ---------- */ 494 495 SDL_TrayEntry *entry_newbtn = SDL_InsertTrayEntryAt(submenu, -1, "Create button", SDL_TRAYENTRY_BUTTON); 496 497 if (entry_newbtn == NULL) { 498 SDL_Log("Couldn't insert entry_newbtn: %s", SDL_GetError()); 499 SDL_RemoveTrayEntry(new_ctrl); 500 SDL_RemoveTrayEntry(new_example); 501 return; 502 } 503 504 SDL_SetTrayEntryCallback(entry_newbtn, append_button_to, entry_submenu); 505 506 /* ---------- */ 507 508 SDL_TrayEntry *entry_newchk = SDL_InsertTrayEntryAt(submenu, -1, "Create checkbox", SDL_TRAYENTRY_BUTTON); 509 510 if (entry_newchk == NULL) { 511 SDL_Log("Couldn't insert entry_newchk: %s", SDL_GetError()); 512 SDL_RemoveTrayEntry(new_ctrl); 513 SDL_RemoveTrayEntry(new_example); 514 return; 515 } 516 517 SDL_SetTrayEntryCallback(entry_newchk, append_checkbox_to, entry_submenu); 518 519 /* ---------- */ 520 521 SDL_TrayEntry *entry_newsub = SDL_InsertTrayEntryAt(submenu, -1, "Create submenu", SDL_TRAYENTRY_BUTTON); 522 523 if (entry_newsub == NULL) { 524 SDL_Log("Couldn't insert entry_newsub: %s", SDL_GetError()); 525 SDL_RemoveTrayEntry(new_ctrl); 526 SDL_RemoveTrayEntry(new_example); 527 return; 528 } 529 530 SDL_SetTrayEntryCallback(entry_newsub, append_submenu_to, entry_submenu); 531 532 /* ---------- */ 533 534 SDL_TrayEntry *entry_newsep = SDL_InsertTrayEntryAt(submenu, -1, "Create separator", SDL_TRAYENTRY_BUTTON); 535 536 if (entry_newsep == NULL) { 537 SDL_Log("Couldn't insert entry_newsep: %s", SDL_GetError()); 538 SDL_RemoveTrayEntry(new_ctrl); 539 SDL_RemoveTrayEntry(new_example); 540 return; 541 } 542 543 SDL_SetTrayEntryCallback(entry_newsep, append_separator_to, entry_submenu); 544 545 /* ---------- */ 546 547 SDL_InsertTrayEntryAt(submenu, -1, NULL, 0); 548} 549 550int main(int argc, char **argv) 551{ 552 SDL_Tray **trays = NULL; 553 SDLTest_CommonState *state; 554 int i; 555 556 /* Initialize test framework */ 557 state = SDLTest_CommonCreateState(argv, 0); 558 if (state == NULL) { 559 return 1; 560 } 561 562 /* Parse commandline */ 563 for (i = 1; i < argc;) { 564 int consumed; 565 566 consumed = SDLTest_CommonArg(state, i); 567 568 if (consumed <= 0) { 569 static const char *options[] = { NULL }; 570 SDLTest_CommonLogUsage(state, argv[0], options); 571 return 1; 572 } 573 574 i += consumed; 575 } 576 577 if (!SDL_Init(SDL_INIT_VIDEO)) { 578 SDL_Log("SDL_Init failed (%s)", SDL_GetError()); 579 return 1; 580 } 581 582 window = SDL_CreateWindow("testtray", 640, 480, 0); 583 584 if (!window) { 585 SDL_Log("Couldn't create window: %s", SDL_GetError()); 586 goto quit; 587 } 588 589 char *icon1filename = GetResourceFilename(NULL, "sdl-test_round.png"); 590 SDL_Surface *icon = SDL_LoadPNG(icon1filename); 591 SDL_free(icon1filename); 592 593 if (!icon) { 594 SDL_Log("Couldn't load icon 1, proceeding without: %s", SDL_GetError()); 595 } 596 597 char *icon2filename = GetResourceFilename(NULL, "speaker.png"); 598 SDL_Surface *icon2 = SDL_LoadPNG(icon2filename); 599 SDL_free(icon2filename); 600 601 if (!icon2) { 602 SDL_Log("Couldn't load icon 2, proceeding without: %s", SDL_GetError()); 603 } 604 605 SDL_Tray *tray = SDL_CreateTray(icon, "SDL Tray control menu"); 606 607 if (!tray) { 608 SDL_Log("Couldn't create control tray: %s", SDL_GetError()); 609 goto clean_window; 610 } 611 612 SDL_PropertiesID tray2_props = SDL_CreateProperties(); 613 SDL_SetPointerProperty(tray2_props, SDL_PROP_TRAY_CREATE_ICON_POINTER, icon2); 614 SDL_SetStringProperty(tray2_props, SDL_PROP_TRAY_CREATE_TOOLTIP_STRING, "SDL Tray example"); 615 SDL_SetPointerProperty(tray2_props, SDL_PROP_TRAY_CREATE_LEFTCLICK_CALLBACK_POINTER, tray2_leftclick); 616 SDL_SetPointerProperty(tray2_props, SDL_PROP_TRAY_CREATE_RIGHTCLICK_CALLBACK_POINTER, tray2_rightclick); 617 SDL_SetPointerProperty(tray2_props, SDL_PROP_TRAY_CREATE_MIDDLECLICK_CALLBACK_POINTER, tray2_middleclick); 618 SDL_Tray *tray2 = SDL_CreateTrayWithProperties(tray2_props); 619 SDL_DestroyProperties(tray2_props); 620 621 if (!tray2) { 622 SDL_Log("Couldn't create example tray: %s", SDL_GetError()); 623 goto clean_tray1; 624 } 625 626 SDL_DestroySurface(icon); 627 SDL_DestroySurface(icon2); 628 629#define CHECK(name) \ 630 if (!name) { \ 631 SDL_Log("Couldn't create " #name ": %s", SDL_GetError()); \ 632 goto clean_all; \ 633 } 634 635 SDL_TrayMenu *menu = SDL_CreateTrayMenu(tray); 636 CHECK(menu); 637 638 SDL_TrayMenu *menu2 = SDL_CreateTrayMenu(tray2); 639 CHECK(menu2); 640 641 SDL_TrayEntry *entry_quit = SDL_InsertTrayEntryAt(menu, -1, "Quit", SDL_TRAYENTRY_BUTTON); 642 CHECK(entry_quit); 643 644 SDL_TrayEntry *entry_close = SDL_InsertTrayEntryAt(menu, -1, "Destroy trays", SDL_TRAYENTRY_BUTTON); 645 CHECK(entry_close); 646 647 /* TODO: Track memory! */ 648 trays = SDL_malloc(sizeof(SDL_Tray *) * 2); 649 if (!trays) { 650 goto clean_all; 651 } 652 653 trays[0] = tray; 654 trays[1] = tray2; 655 656 SDL_SetTrayEntryCallback(entry_quit, tray_quit, NULL); 657 SDL_SetTrayEntryCallback(entry_close, tray_close, trays); 658 659 SDL_InsertTrayEntryAt(menu, -1, NULL, 0); 660 661 entry_toggle = SDL_InsertTrayEntryAt(menu, -1, "Hide window", SDL_TRAYENTRY_BUTTON); 662 CHECK(entry_toggle); 663 664 SDL_SetTrayEntryCallback(entry_toggle, toggle_window, NULL); 665 666 SDL_InsertTrayEntryAt(menu, -1, NULL, 0); 667 668 SDL_TrayEntry *entry_icon = SDL_InsertTrayEntryAt(menu, -1, "Change icon", SDL_TRAYENTRY_BUTTON); 669 CHECK(entry_icon); 670 671 SDL_SetTrayEntryCallback(entry_icon, change_icon, tray2); 672 673 SDL_InsertTrayEntryAt(menu, -1, NULL, 0); 674 675 SDL_TrayEntry *entry_newbtn = SDL_InsertTrayEntryAt(menu, -1, "Create button", SDL_TRAYENTRY_BUTTON); 676 CHECK(entry_newbtn); 677 678 SDL_SetTrayEntryCallback(entry_newbtn, append_button_to, menu2); 679 680 SDL_TrayEntry *entry_newchk = SDL_InsertTrayEntryAt(menu, -1, "Create checkbox", SDL_TRAYENTRY_BUTTON); 681 CHECK(entry_newchk); 682 683 SDL_SetTrayEntryCallback(entry_newchk, append_checkbox_to, menu2); 684 685 SDL_TrayEntry *entry_newsub = SDL_InsertTrayEntryAt(menu, -1, "Create submenu", SDL_TRAYENTRY_BUTTON); 686 CHECK(entry_newsub); 687 688 SDL_SetTrayEntryCallback(entry_newsub, append_submenu_to, menu2); 689 690 SDL_TrayEntry *entry_newsep = SDL_InsertTrayEntryAt(menu, -1, "Create separator", SDL_TRAYENTRY_BUTTON); 691 CHECK(entry_newsep); 692 693 SDL_SetTrayEntryCallback(entry_newsep, append_separator_to, menu2); 694 695 SDL_InsertTrayEntryAt(menu, -1, NULL, 0); 696 697 SDL_Event e; 698 while (SDL_WaitEvent(&e)) { 699 if (e.type == SDL_EVENT_QUIT) { 700 break; 701 } else if (e.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED) { 702 if (trays_destroyed) { 703 break; 704 } 705 toggle_window(NULL, entry_toggle); 706 } 707 } 708 709clean_all: 710 if (!trays_destroyed) { 711 SDL_DestroyTray(tray2); 712 } 713 714clean_tray1: 715 if (!trays_destroyed) { 716 SDL_DestroyTray(tray); 717 } 718 SDL_free(trays); 719 720clean_window: 721 if (window) { 722 SDL_DestroyWindow(window); 723 } 724 725quit: 726 SDL_Quit(); 727 SDLTest_CommonDestroyState(state); 728 729 return 0; 730} 731[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.