Skip to content

Instantly share code, notes, and snippets.

@nathan-osman
Last active September 8, 2023 08:05
Show Gist options
  • Select an option

  • Save nathan-osman/57a560a85783ebaa0b12b86fd4b04b61 to your computer and use it in GitHub Desktop.

Select an option

Save nathan-osman/57a560a85783ebaa0b12b86fd4b04b61 to your computer and use it in GitHub Desktop.

Revisions

  1. nathan-osman revised this gist Sep 8, 2023. 1 changed file with 0 additions and 0 deletions.
    Binary file added wintray.ico
    Binary file not shown.
  2. nathan-osman created this gist Sep 8, 2023.
    14 changes: 14 additions & 0 deletions CMakeLists.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,14 @@
    project(wintray)

    add_executable(wintray WIN32
    main.cpp
    resource.rc
    wintray.exe.manifest
    )

    set_target_properties(wintray PROPERTIES
    CXX_STANDARD 11
    CXX_STANDARD_REQUIRED ON
    )

    target_link_libraries(wintray Comctl32)
    30 changes: 30 additions & 0 deletions config.h
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,30 @@
    /*
    * The MIT License (MIT)
    *
    * Copyright (c) 2023 Nathan Osman
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy
    * of this software and associated documentation files (the "Software"), to
    * deal in the Software without restriction, including without limitation the
    * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
    * sell copies of the Software, and to permit persons to whom the Software is
    * furnished to do so, subject to the following conditions:
    *
    * The above copyright notice and this permission notice shall be included in
    * all copies or substantial portions of the Software.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
    * IN THE SOFTWARE.
    */

    #ifndef CONFIG_H
    #define CONFIG_H

    #define IDI_ICON 101

    #endif // CONFIG_H
    169 changes: 169 additions & 0 deletions main.cpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,169 @@
    /*
    * The MIT License (MIT)
    *
    * Copyright (c) 2023 Nathan Osman
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy
    * of this software and associated documentation files (the "Software"), to
    * deal in the Software without restriction, including without limitation the
    * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
    * sell copies of the Software, and to permit persons to whom the Software is
    * furnished to do so, subject to the following conditions:
    *
    * The above copyright notice and this permission notice shall be included in
    * all copies or substantial portions of the Software.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
    * IN THE SOFTWARE.
    */

    #ifndef UNICODE
    #define UNICODE
    #endif

    #include <windows.h>
    #include <windowsx.h>

    #include <commctrl.h>
    #include <shellapi.h>
    #include <strsafe.h>

    #include "config.h"

    #define ID_QUIT 101

    const UINT WMAPP_NOTIFYCALLBACK = WM_APP + 1;

    LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

    int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
    {
    // Create and register the window class
    const wchar_t CLASS_NAME[] = L"WndClass";

    WNDCLASS wc = { };

    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = CLASS_NAME;

    RegisterClass(&wc);

    // Create a window only for notifications
    CreateWindowEx(
    0,
    CLASS_NAME,
    L"System Tray Window",
    0,
    0,
    0,
    0,
    0,
    HWND_MESSAGE,
    NULL,
    hInstance,
    NULL
    );

    // Event loop
    MSG msg = { };
    while (GetMessage(&msg, NULL, 0, 0)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    }

    return 0;
    }

    void createPopup(HWND hwnd, POINT pt)
    {
    // Create the popup
    HMENU hmenu = CreatePopupMenu();

    // Create the menu item
    MENUITEMINFO mii = { };
    mii.cbSize = sizeof(mii);
    mii.fMask = MIIM_STRING | MIIM_ID;
    mii.wID = ID_QUIT;
    mii.dwTypeData = L"&Quit";
    mii.cch = wcslen(mii.dwTypeData);

    // Insert it
    InsertMenuItem(hmenu, 0, TRUE, &mii);

    // Show the menu
    int id = TrackPopupMenu(
    hmenu,
    TPM_RETURNCMD,
    pt.x,
    pt.y,
    0,
    hwnd,
    NULL
    );

    switch (id) {
    case ID_QUIT:
    PostQuitMessage(0);
    break;
    }

    DestroyMenu(hmenu);
    }

    LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
    switch (uMsg) {

    case WM_CREATE:
    {
    // Prepare the struct
    NOTIFYICONDATA nid = { };
    nid.hWnd = hwnd;
    nid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;
    nid.uCallbackMessage = WMAPP_NOTIFYCALLBACK;

    // Load the icon
    LoadIconMetric(
    GetModuleHandle(nullptr),
    MAKEINTRESOURCE(IDI_ICON),
    LIM_SMALL,
    &(nid.hIcon)
    );

    // Load the tooltip
    StringCchCopy(nid.szTip, ARRAYSIZE(nid.szTip), L"Tray Icon");

    Shell_NotifyIcon(NIM_ADD, &nid);

    // Set the version
    nid.uVersion = NOTIFYICON_VERSION_4;
    Shell_NotifyIcon(NIM_SETVERSION, &nid);

    return 0;
    }

    case WMAPP_NOTIFYCALLBACK:
    {
    if (LOWORD(lParam) == WM_CONTEXTMENU) {

    // Determine the offset
    POINT pt = {
    GET_X_LPARAM(wParam),
    GET_Y_LPARAM(wParam)
    };

    createPopup(hwnd, pt);
    }

    return 0;
    }
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    5 changes: 5 additions & 0 deletions resource.rc
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,5 @@
    #include <windows.h>

    #include "config.h"

    IDI_ICON ICON DISCARDABLE "wintray.ico"
    14 changes: 14 additions & 0 deletions wintray.exe.manifest
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,14 @@
    <?xml version='1.0' encoding='UTF-8' standalone='yes'?>
    <assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0' xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
    <dependency>
    <dependentAssembly>
    <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" language="*" processorArchitecture="*" version="6.0.0.0" publicKeyToken="6595b64144ccf1df"/>
    </dependentAssembly>
    </dependency>
    <asmv3:application>
    <asmv3:windowsSettings>
    <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
    <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
    </asmv3:windowsSettings>
    </asmv3:application>
    </assembly>