Coder Social home page Coder Social logo

dmikushin / tray Goto Github PK

View Code? Open in Web Editor NEW

This project forked from zserge/tray

81.0 3.0 15.0 1.83 MB

Cross-platform, super tiny C99 implementation of a system tray icon with a popup menu.

License: MIT License

C 45.82% CMake 17.76% Objective-C 14.47% C++ 21.95%

tray's Introduction

System Tray / Menu Bar / Indicator Icon

MacOS screenshot

Windows screenshot

Linux screenshot

Cross-platform, super tiny1 C99-based implementation of a system tray/menu bar icon with popup menu.

The optional primary-click callback can hide/show a window while secondary-click shows a menu, or if
no callback is specified, either click will show the menu. The system can be dynamically updated; icon, tooltip, menu item text and status (checked/unchecked & enabled/disabled) can all be both queried and changed at runtime.

Code is C++ friendly and will compile fine in C99 or C++98 and up on Windows, Objective-C on Mac but C++20 on Linux.

Focussed PRs are welcome, especially improvements to the Linux implementation. The goal is to keep the code as simple as possible, so functionality beyond presenting a tray icon and menu is out of scope.

Cross-platform

Works well on:

  • Windows XP or newer (shellapi.h)
  • MacOS (Cocoa/AppKit)
  • Linux/Gtk (Qt6)

GNOME has decided to deprecate the tray icon as a concept, except for system indicators. They have not only deprecated the tray-handling code but removed it entirely. Extensive investigation has failed to produce a reliable way to display tray icons, even using low-level X11 calls. Qt has worked out a way to do it, so we are currently using their implementation on Linux, which unfortunately requires C++ and much larger dependencies. All of the Qt code is isolated in the library, so use of Qt is not required in application code (although it will use the application's QApplication instance, should one exist).

PRs that resolve this situation are very welcome!

API

The tray structure defines the tray and a nested menu of NULL-terminated array of entries. tray_menu_item defines each menu entry text, menu checked and disabled (grayed) flags.

The tray and tray_menu_item each have an optional callback if they are selected.

struct tray {
  const char *icon_filepath;
  char *tooltip;
  void (*cb)(struct tray *); // called on left click, leave null to just open menu
  struct tray_menu_item *menu; // NULL-terminated array of menu items
};

struct tray_menu_item {
  char *text;
  int disabled;
  int checked;
  void (*cb)(struct tray_menu_item *);
  struct tray_menu_item *submenu; // NULL-terminated array of submenu items
};
  • int tray_init(struct tray *) - creates tray icon. Returns -1 if tray icon/menu can't be created.
  • struct tray * tray_get_instance() - returns the tray instance.
  • void tray_update(struct tray *) - updates tray icon and menu.
  • int tray_loop(int blocking) - runs one iteration of the UI loop. Returns -1 if tray_exit() has been called.
  • void tray_exit() - terminates UI loop.

All functions are meant to be called from the UI thread only.

Menu arrays must be terminated with a NULL item, e.g. the last item in the array must have text field set to NULL.

Icons

Icons are platform-specific but generally should have transparent backgrounds and be simple (since they are tiny).

Tray does not provide any theming or icon management. It is up to the application to respond to theme changes and supply appropriate icons e.g. dark mode.

Platform Icon format
Windows .ICO with 16x16 & 32x32 sizes included
MacOS .PNG with a notional 22pt height or vector-based .PDF (recommend black or white images)
Linux .PNG 24x24 pixels

Prerequisites

  • CMake
  • Ninja, in order to have the same build commands on all platforms
  • Qt6 on Linux: sudo apt install build-essential libgl1-mesa-dev qt6-base-dev

Building

mkdir build
cd build
cmake -G Ninja ..
ninja

Demo

Build & execute the tray_example application:

./tray_example

History

This fork brings together the original work of Serge Zaitsev and the most interesting forks and PRs of respectable contributors including:

Footnotes

  1. It's super tiny on both Mac & Windows. โ†ฉ

tray's People

Contributors

angelskieglazki avatar arabine avatar cgutman avatar dmikushin avatar intika avatar jesselawson avatar jslegendre avatar longhronshen avatar madera avatar nburrus avatar rjvs avatar s-h-a-d-o-w avatar spacepluk avatar theelixzammuto avatar tyoungsl avatar zserge avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

tray's Issues

Does this library actually work?

When I tried to compile this library with command cmake .., it reported a CMP0002 error:
CMake Error at CMakeLists.txt:50 (add_library): add_library cannot create target "tray" because another target with the same name already exists. The existing target is an interface library created in source directory "[Project Root Dir]". See documentation for policy CMP0002 for more details.

However, after I renamed the tray library to another name, a huge amount of errors came when I run ninja,
showing that there maybe some wrong in the code.
These errors contain:

  • Undefined type errors
    This is something like tray_windows.c:42:15: error: invalid use of undefined type 'struct tray_menu'',
    This kind of errors is solved after I added #include "tray.h" on the top of tray_windows.c(This problems may also exist in tray_linux.c and tray_darwin.m)
  • static method errors
    Something like example.c:(.text+0x11d): undefined reference to tray_exit'It comes out that methods defined intray_windows.care static methods, so thatexample.c` cannot call them.

According to those I explained above, I don't understand why those errors happen in this library.
Thank you for answering my question.
Apologize for my poor English.

Left mouse button support on kde

May I ask, can this library support this function?
I checked several libraries, and none of them did not realize the support of the left mouse button.

must create tray icon in main thread on macOS

It appears that macOS requires the tray icon to be created/updated from the main thread of an application. I've seen something similar in this python library (https://pystray.readthedocs.io/en/latest/reference.html?highlight=macos#pystray.Icon.run_detached). I have tried the following, but not having any luck. This code runs, but no icon is created on macOS.

#include <thread>

// tray icon macros and includes
#if defined SYSTEM_TRAY && SYSTEM_TRAY >= 1
#if defined(_WIN32) || defined(_WIN64)
#define TRAY_ICON WEB_DIR "images/favicon.ico"
#elif defined(__linux__) || defined(linux) || defined(__linux)
#define TRAY_ICON "tray-icon"
#elif defined(__APPLE__) || defined(__MACH__)
#define TRAY_ICON WEB_DIR "images/tray-icon-16.png"
#include <dispatch/dispatch.h>
#endif
#include "tray/tray.h"
#endif

#if defined SYSTEM_TRAY && SYSTEM_TRAY >= 1
void tray_cb(struct tray_menu *item) {
  // code
}

// Tray menu
static struct tray tray = {
  .icon = TRAY_ICON,
#if defined(_WIN32) || defined(_WIN64)
  .tooltip = const_cast<char *>("Tooltip"), // cast the string literal to a non-const char* pointer
#endif
  .menu =
    (struct tray_menu[]) {
      { .text = "Open", .cb = tray_cb },
      { .text = nullptr } },
};

// function to create system tray, run in detached thread
int create_tray() {
  if(tray_init(&tray) < 0) {
    // logging
    return 1;
  }
  else {
    // logging
  }

  while(tray_loop(1) == 0) {
    // logging
  }

  return 0;
}
#endif

int main(int argc, char *argv[]) {
  // some code

#if defined SYSTEM_TRAY && SYSTEM_TRAY >= 1
  // create tray thread and detach it
#if defined(__APPLE__) || defined(__MACH__)
  // on macOS we need to create the tray on the main thread
  dispatch_async(dispatch_get_main_queue(), ^{
    create_tray();
  });
#else
  std::thread tray_thread(create_tray);
  tray_thread.detach();
#endif
#endif

  // more code

  // stop system tray
#if defined SYSTEM_TRAY && SYSTEM_TRAY >= 1
  tray_exit();
#if !defined(__APPLE__) || !defined(__MACH__)
  if(tray_thread.joinable()) {
    tray_thread.join();
  }
#endif
#endif

  // even more code

  return 0;
}

The most relevant part being

#if defined SYSTEM_TRAY && SYSTEM_TRAY >= 1
  // create tray thread and detach it
#if defined(__APPLE__) || defined(__MACH__)
  // on macOS we need to create the tray on the main thread
  dispatch_async(dispatch_get_main_queue(), ^{
    create_tray();
  });
#else
  std::thread tray_thread(create_tray);
  tray_thread.detach();
#endif
#endif

If I use create_tray(); directly, instead of within the dispatch_async the icon is created, but of course the remainder of the code does not execute due to the endless while loop.

Using the separate tray_thread is working great on Windows and Linux.

I'd be happy to provide more of the code if it will help.

Could you offer any workaround or guidance?

libayatana-appindicator not available on Red Hat distros

#include <libayatana-appindicator/app-indicator.h>

This library is not available on Fedora (or probably any Red Hat distro).

The previous library used (before this commit: 7c34b5b) is more common and available on a wider range of Linux distros.

I would suggest something like this in CMakeLists, then set the includes based on the value of TRAY_VERSION

set(TRAY_VERSION 0)
pkg_check_modules(APPINDICATOR appindicator3-0.1)
if(NOT APPINDICATOR_FOUND)
    set(TRAY_VERSION 2)
    pkg_check_modules(APPINDICATOR ayatana-appindicator3-0.1)
else()
    set(TRAY_VERSION 1)
endif()

Build failed on MSYS2

This library build failed again on MSYS2.
I think that the reason of this problem may be that you hard-coded flags
which are only recognized by Microsoft C++ Compiler.(Source is here)

Build log is below this time :)
(Some private path is hidden)

$ mkdir build
$ cmake ..
-- Building for: Ninja
-- The C compiler identification is GNU 11.2.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: [PRIVATE]/MSYS2/mingw64/bin/cc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: [PRIVATE]/tray/build
$ ninja
[1/3] Building C object CMakeFiles/tray.dir/tray_windows.c.obj
FAILED: CMakeFiles/tray.dir/tray_windows.c.obj
[PRIVATE]\MSYS2\mingw64\bin\cc.exe -DNOMINMAX -DTRAY_WINAPI=1 -DWIN32_LEAN_AND_MEAN  /MT -std=gnu99 -MD -MT CMakeFiles/tray.dir/tray_windows.c.obj -MF CMakeFiles\tray.dir\tray_windows.c.obj.d -o CMakeFiles/tray.dir/tray_windows.c.obj -c [PRIVATE]/tray/tray_windows.c
cc.exe: warning: /MT: linker input file unused because linking not done
cc.exe: error: /MT: linker input file not found: No such file or directory
ninja: build stopped: subcommand failed.

Sorry for the inconvenience.

No tray icon on KDE

Hello,

There is no tray icon visible on KDE. I don't know where to start but I can propose a patch if someone has some hints.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.