Skip to content

System tray

1
2
3
4
5
6
FetchContent_Declare(
        tray
        GIT_REPOSITORY https://github.com/wormyrocks/tray.git
        GIT_TAG 3e4a1447bff413e6907c5e43ac8d65e36866fdfd
)
FetchContent_GetProperties(tray)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
if (NOT tray_POPULATED)
    FetchContent_Populate(tray)
    add_library(tray INTERFACE)
    target_sources(tray INTERFACE ${tray_SOURCE_DIR}/tray.h)
    target_include_directories(tray INTERFACE ${tray_SOURCE_DIR})
    if (WIN32)
        target_compile_definitions(tray INTERFACE TRAY_WINAPI)
    elseif (APPLE)
        target_compile_definitions(tray INTERFACE TRAY_APPKIT)
        target_link_libraries(tray INTERFACE "-framework Cocoa")
        # Some warnings the library doesn't deal with
        target_compile_options(tray INTERFACE -Wno-unused-parameter)
        target_compile_options(tray INTERFACE -Wno-unused-variable)
        target_compile_options(tray INTERFACE -Wno-writable-strings)
        target_compile_options(tray INTERFACE -Wno-misleading-indentation)
    elseif (UNIX)
        target_compile_definitions(tray INTERFACE TRAY_APPINDICATOR)
        target_link_libraries(tray INTERFACE "$(shell pkg-config --cflags appindicator3-0.1 --libs appindicator3-0.1)")
        # Some warnings the library doesn't deal with
        target_compile_options(tray INTERFACE -Wno-unused-parameter)
        target_compile_options(tray INTERFACE -Wno-unused-variable)
        target_compile_options(tray INTERFACE -Wno-writable-strings)
        target_compile_options(tray INTERFACE -Wno-misleading-indentation)
    endif ()
endif ()

1
2
add_executable(tray_helloworld tray_hello.cpp)
target_link_libraries(tray_helloworld tray)

1
2
3
4
5
if (WIN32)
    file(COPY ${tray_SOURCE_DIR}/icon.ico DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
elseif (APPLE)
    file(COPY ${tray_SOURCE_DIR}/icon.png DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
endif ()

Share Snippets


1
#include <tray.h>

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
class tray_and_menu {
  public:
    tray_and_menu() {
        // Setup arrays with tray items
        if (tray_.menu != nullptr) {
            return;
        }

        tray_.menu = new tray_menu[8];
        tray_.menu[0] = {.text = "Hello", .cb = hello_cb, .submenu = nullptr};
        tray_.menu[1] = {
            .text = "Checked", .cb = toggle_cb, .submenu = nullptr};
        tray_.menu[2] = {.text = "Disabled", .disabled = 1, .submenu = nullptr};
        tray_.menu[3] = {.text = "-", .submenu = nullptr};
        tray_.menu[4] = {.text = "SubMenu", .submenu = new tray_menu[3]};
        tray_.menu[5] = {.text = "-", .submenu = nullptr};
        tray_.menu[6] = {.text = "Quit", .cb = quit_cb, .submenu = nullptr};
        tray_.menu[7] = {.text = nullptr, .submenu = nullptr};

        tray_.menu[4].submenu[0] = {.text = "FIRST",
                                    .checked = 1,
                                    .cb = submenu_cb,
                                    .submenu = nullptr};
        tray_.menu[4].submenu[1] = {.text = "SECOND",
                                    .submenu = new tray_menu[6]};
        tray_.menu[4].submenu[2] = {.text = nullptr, .submenu = nullptr};

        tray_.menu[4].submenu[1].submenu[0] = {.text = "THIRD",
                                               .submenu = new tray_menu[4]};
        tray_.menu[4].submenu[1].submenu[1] = {.text = "FOUR",
                                               .submenu = new tray_menu[3]};
        tray_.menu[4].submenu[1].submenu[2] = {.text = nullptr,
                                               .submenu = nullptr};

        tray_.menu[4].submenu[1].submenu[0].submenu[0] = {
            .text = "7", .cb = submenu_cb, .submenu = nullptr};
        tray_.menu[4].submenu[1].submenu[0].submenu[1] = {.text = "-",
                                                          .submenu = nullptr};
        tray_.menu[4].submenu[1].submenu[0].submenu[2] = {
            .text = "8", .cb = submenu_cb, .submenu = nullptr};
        tray_.menu[4].submenu[1].submenu[0].submenu[3] = {.text = nullptr,
                                                          .submenu = nullptr};

        tray_.menu[4].submenu[1].submenu[1].submenu[0] = {
            .text = "5", .cb = submenu_cb, .submenu = nullptr};
        tray_.menu[4].submenu[1].submenu[1].submenu[1] = {
            .text = "6", .cb = submenu_cb, .submenu = nullptr};
        tray_.menu[4].submenu[1].submenu[1].submenu[2] = {
            .text = nullptr, .cb = submenu_cb, .submenu = nullptr};

        if (tray_init(&tray_) < 0) {
            std::runtime_error("failed to create tray_");
        }
    }

    ~tray_and_menu() {
        delete[] tray_.menu[4].submenu[1].submenu[1].submenu;
        delete[] tray_.menu[4].submenu[1].submenu[0].submenu;
        delete[] tray_.menu[4].submenu[1].submenu;
        delete[] tray_.menu[4].submenu;
        delete[] tray_.menu[3].submenu;
        delete[] tray_.menu->submenu;
        tray_.menu->submenu = nullptr;
    }

    static void run_tray() {
        while (tray_loop(1) == 0) {
            std::cout << "Iteration" << std::endl;
        }
    }

  private:
    static void toggle_cb(struct tray_menu *item) {
        std::cout << "toggle cb" << std::endl;
        item->checked = !item->checked;
        tray_update(&tray_);
    }

    static void hello_cb(struct tray_menu *item) {
        (void)item;
        std::cout << "hello cb" << std::endl;
        // NOLINTNEXTLINE(bugprone-branch-clone)
        if (strcmp(tray_.icon, TRAY_ICON1) == 0) {
            tray_.icon = TRAY_ICON2;
        } else {
            tray_.icon = TRAY_ICON1;
        }
        tray_update(&tray_);
    }

    static void quit_cb(struct tray_menu *item) {
        (void)item;
        std::cout << "quit cb" << std::endl;
        tray_exit();
    }

    static void submenu_cb(struct tray_menu *item) {
        (void)item;
        std::cout << "submenu: clicked on " << item->text << std::endl;
        tray_update(&tray_);
    }

  private /* members */:
    // Tray with pointers to menu
    static tray tray_;
};

1
tray tray_and_menu::tray_{.icon = TRAY_ICON1, .menu = nullptr};

1
2
tray_and_menu t;
tray_and_menu::run_tray();

Share Snippets