Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
On Windows we use msys2 and ucrt64 to compile.
You need to prefix commands with `C:\msys64\msys2_shell.cmd -defterm -here -no-start -ucrt64 -c`.

Prefix build directories with `cmake-build-`.

The test executable is named `test_tray` and will be located inside the `tests` directory within
the build directory.

The project uses gtest as a test framework.

Always follow the style guidelines defined in .clang-format for c/c++ code.
66 changes: 57 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,18 @@ jobs:
build-essential \
cmake \
${{ matrix.appindicator }} \
imagemagick \
libglib2.0-dev \
libnotify-dev \
ninja-build \
xvfb

- name: Setup virtual desktop
if: runner.os == 'Linux'
uses: LizardByte/actions/actions/setup_virtual_desktop@feat/actions/linux-display # todo: pin version
with:
environment: mate

- name: Setup Dependencies macOS
if: runner.os == 'macOS'
run: |
Expand All @@ -67,6 +74,7 @@ jobs:
cmake \
doxygen \
graphviz \
imagemagick \
ninja \
node

Expand All @@ -81,6 +89,7 @@ jobs:
mingw-w64-ucrt-x86_64-binutils
mingw-w64-ucrt-x86_64-cmake
mingw-w64-ucrt-x86_64-graphviz
mingw-w64-ucrt-x86_64-imagemagick
mingw-w64-ucrt-x86_64-ninja
mingw-w64-ucrt-x86_64-nodejs
mingw-w64-ucrt-x86_64-toolchain
Expand All @@ -103,7 +112,7 @@ jobs:

# step output
echo "python-path=${python_path}"
echo "python-path=${python_path}" >> $GITHUB_OUTPUT
echo "python-path=${python_path}" >> "${GITHUB_OUTPUT}"

- name: Build
run: |
Expand All @@ -124,18 +133,57 @@ jobs:
-S .
ninja -C build

- name: Init tray icon (Windows)
if: runner.os == 'Windows'
working-directory: build/tests
run: ./test_tray --gtest_color=yes --gtest_filter=TrayTest.TestTrayInit

- name: Configure Windows
if: runner.os == 'Windows'
shell: pwsh
run: |
echo "::group::Enable all tray icons"
Invoke-WebRequest `
-Uri "https://raw.githubusercontent.com/paulmann/windows-show-all-tray-icons/main/Enable-AllTrayIcons.ps1" `
-OutFile "Enable-AllTrayIcons.ps1"
.\Enable-AllTrayIcons.ps1 -Action Enable -Force # Enable with comprehensive method (resets ALL icon settings)
echo "::endgroup::"

echo "::group::Disable Do Not Disturb"
Add-Type -AssemblyName System.Windows.Forms
Start-Process "ms-settings:notifications"
Start-Sleep -Seconds 2
[System.Windows.Forms.SendKeys]::SendWait("{TAB}")
[System.Windows.Forms.SendKeys]::SendWait("{TAB}")
[System.Windows.Forms.SendKeys]::SendWait(" ")
echo "::endgroup::"

echo "::group::Minimize all windows"
$shell = New-Object -ComObject Shell.Application
$shell.MinimizeAll()
echo "::endgroup::"

echo "::group::Set Date - Hack for Quiet Time"
$newDate = (Get-Date).AddHours(2)
Set-Date -Date $newDate
echo "::endgroup::"

- name: Run tests
id: test
# TODO: tests randomly hang on Linux, https://github.com/LizardByte/tray/issues/45
timeout-minutes: 1
timeout-minutes: 3
working-directory: build/tests
run: |
if [ "${{ runner.os }}" = "Linux" ]; then
export DISPLAY=:1
Xvfb ${DISPLAY} -screen 0 1024x768x24 &
fi
run: ./test_tray --gtest_color=yes --gtest_output=xml:test_results.xml

./test_tray --gtest_color=yes --gtest_output=xml:test_results.xml
- name: Upload screenshots
if: >-
always() &&
(steps.test.outcome == 'success' || steps.test.outcome == 'failure')
uses: actions/upload-artifact@v6
with:
name: tray-screenshots-${{ runner.os }}${{ matrix.appindicator && format('-{0}', matrix.appindicator) || '' }}
path: build/tests/screenshots
if-no-files-found: error

- name: Generate gcov report
id: test_report
Expand Down Expand Up @@ -164,7 +212,7 @@ jobs:
if [ -n "${{ matrix.appindicator }}" ]; then
flags="${flags},${{ matrix.appindicator }}"
fi
echo "flags=${flags}" >> $GITHUB_OUTPUT
echo "flags=${flags}" >> "${GITHUB_OUTPUT}"

- name: Upload coverage
# any except canceled or skipped
Expand Down
58 changes: 58 additions & 0 deletions .github/workflows/publish-screenshots.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
name: Publish Screenshots

on:
workflow_run:
workflows: ["CI"]
types:
- completed

permissions:
contents: write
pull-requests: write

jobs:
publish:
if: github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-latest
steps:
- name: Download Artifacts
uses: actions/download-artifact@v7
with:
path: screenshots
pattern: tray-screenshots-*
run-id: ${{ github.event.workflow_run.id }}

- name: Debug screenshots
run: ls -R screenshots

- name: Determine Branch and Path
id: determine
env:
PULL_REQUEST_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number }}
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
run: |
if [ -n "${PULL_REQUEST_NUMBER}" ]; then
PR_NUMBER=${PULL_REQUEST_NUMBER}
BRANCH_PATH="PR-${PULL_REQUEST_NUMBER}"
is_pr=true
else
BRANCH_NAME=$(echo "${HEAD_BRANCH}" | sed 's/\//-/g')
BRANCH_PATH="${BRANCH_NAME}"
is_pr=false
fi

{
echo "branch_path=${BRANCH_PATH}"
echo "is_pr=${is_pr}"
echo "pr_number=${PR_NUMBER}"
} >> "${GITHUB_OUTPUT}"

# debug outputs
cat "${GITHUB_OUTPUT}"

- name: Checkout Screenshots Branch
uses: actions/checkout@v6
with:
ref: screenshots
path: screenshots-repo
1 change: 1 addition & 0 deletions docs/Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ PROJECT_NAME = tray
DOT_GRAPH_MAX_NODES = 50
IMAGE_PATH = ../docs/images
INCLUDE_PATH =
PREDEFINED += TRAY_WINAPI

# files and directories to process
USE_MDFILE_AS_MAINPAGE = ../README.md
Expand Down
17 changes: 17 additions & 0 deletions src/tray.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
#ifndef TRAY_H
#define TRAY_H

#if defined(TRAY_WINAPI)
#include <Windows.h>
#endif

#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -64,11 +68,24 @@ extern "C" {
*/
void tray_update(struct tray *tray);

/**
* @brief Force show the tray menu (for testing purposes).
*/
void tray_show_menu(void);

/**
* @brief Terminate UI loop.
*/
void tray_exit(void);

#if defined(TRAY_WINAPI)
/**
* @brief Get the tray window handle.
* @return The window handle.
*/
HWND tray_get_hwnd(void);
#endif

#ifdef __cplusplus
} // extern "C"
#endif
Expand Down
28 changes: 26 additions & 2 deletions src/tray_darwin.m
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,26 @@ - (IBAction)menuCallback:(id)sender {
static NSApplication *app;
static NSStatusBar *statusBar;
static NSStatusItem *statusItem;
static int loopResult = 0;

#define QUIT_EVENT_SUBTYPE 0x0DED ///< NSEvent subtype used to signal exit.

static void drain_quit_events(void) {
while (YES) {
NSEvent *event = [app nextEventMatchingMask:ULONG_MAX
untilDate:[NSDate distantPast]
inMode:[NSString stringWithUTF8String:"kCFRunLoopDefaultMode"]
dequeue:TRUE];
if (event == nil) {
break;
}
if (event.type == NSEventTypeApplicationDefined && event.subtype == QUIT_EVENT_SUBTYPE) {
continue;
}
[app sendEvent:event];
}
}

static NSMenu *_tray_menu(struct tray_menu *m) {
NSMenu *menu = [[NSMenu alloc] init];
[menu setAutoenablesItems:FALSE];
Expand All @@ -67,13 +84,15 @@ - (IBAction)menuCallback:(id)sender {
}

int tray_init(struct tray *tray) {
loopResult = 0;
AppDelegate *delegate = [[AppDelegate alloc] init];
app = [NSApplication sharedApplication];
[app setDelegate:delegate];
statusBar = [NSStatusBar systemStatusBar];
statusItem = [statusBar statusItemWithLength:NSVariableStatusItemLength];
tray_update(tray);
[app activateIgnoringOtherApps:TRUE];
drain_quit_events();
return 0;
}

Expand All @@ -85,12 +104,13 @@ int tray_loop(int blocking) {
dequeue:TRUE];
if (event) {
if (event.type == NSEventTypeApplicationDefined && event.subtype == QUIT_EVENT_SUBTYPE) {
return -1;
loopResult = -1;
return loopResult;
}

[app sendEvent:event];
}
return 0;
return loopResult;
}

void tray_update(struct tray *tray) {
Expand All @@ -101,6 +121,10 @@ void tray_update(struct tray *tray) {
[statusItem setMenu:_tray_menu(tray->menu)];
}

void tray_show_menu(void) {
[statusItem popUpStatusItemMenu:statusItem.menu];
}

void tray_exit(void) {
NSEvent *event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined
location:NSMakePoint(0, 0)
Expand Down
Loading
Loading