Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tray icon does not appear on Mac #8229

Closed
qstokkink opened this issue Oct 22, 2024 · 0 comments · Fixed by #8231
Closed

Tray icon does not appear on Mac #8229

qstokkink opened this issue Oct 22, 2024 · 0 comments · Fixed by #8231
Assignees
Milestone

Comments

@qstokkink
Copy link
Contributor

The pystray tray icon does not appear on Mac. This happens both when running from source and when running from the build. I uncovered that the following line is to blame:

threading.Thread(target=icon.run).start()

Only on Mac, icon.run() cannot be run on anything other than the main thread.

BUT if you do run icon.run() on the main thread, it blocks the main thread until the application exits. The run_detached function exists but this doesn't work without extra effort. In particular, we need to run an event loop or, rather, something that consumes and runs events on the main Python thread.

I made a proof-of-concept of an asyncio-compatible consuming "event loop" (the meat is in runEventLoop and main is essentially our run_tribler.py with two changed lines):

import asyncio
import sys
from asyncio import run, sleep

import pystray
from PIL import Image

from AppKit import NSApp, NSEventMaskAny
from Foundation import NSDate, NSDefaultRunLoopMode

import tribler

async def runEventLoop():
    while True:
        event = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_(NSEventMaskAny, NSDate.now(), NSDefaultRunLoopMode, True)
        NSApp().sendEvent_(event)
        await sleep(0)


async def main():
    image_path = tribler.get_webui_root() / "public" / "tribler.png"
    image = Image.open(image_path.absolute().resolve())
    menu = (pystray.MenuItem('Open', lambda: print("open")),
            pystray.MenuItem('Quit', lambda: sys.exit(0)))
    icon: pystray._darwin.Icon = pystray.Icon("Tribler", icon=image, title="Tribler", menu=menu)

    icon.run_detached(None)  # <---
    asyncio.ensure_future(runEventLoop())  # <---

    for i in range(10):
        print(10-i, "...")
        await asyncio.sleep(1)
    icon.stop()


if __name__ == "__main__":
    run(main())

We may want to beautify this a bit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging a pull request may close this issue.

1 participant