Difference between revisions of "How to use a TrayIcon"

From Lazarus wiki
(Change Log)
(link to fix for Bullseye)
(47 intermediate revisions by 11 users not shown)
Line 2: Line 2:
  
 
=== About ===
 
=== About ===
 +
'''[[TTrayIcon]]''' is a multiplatform System Tray component. You can find TrayIcon on the [[Additional tab]] of the [[Component Palette]] (0.9.23+).
  
'''TrayIcon''' is a multiplatform System Tray component. You can find TrayIcon on the Addition tab of components on recent versions of Lazarus (0.9.23+).
+
TrayIcon used to be an optional component, but is part of LCL since Lazarus 0.9.23
 +
 
 +
To start quickly, please read [[TrayIcon#Example_1_-_Using_TIcon|the demonstration program]].
 +
 
 +
 
 +
=== Linux may not display the Icon ===
 +
 
 +
Some Linux systems will have trouble displaying the GTK TrayIcon, in general this relates to a move away from the System Tray model that Lazarus TrayIcon is based on. This problem is a particular issue with Gnome but some other Desktops may also suffer. There are workarounds that involve using another library, LibAppIndicator3 and in some cases other extra packages and specific configuration steps. Its important to note, and to advise your end users, that the problem is with the Linux Distribution and its Desktop. You, as the application's programmer cannot directly solve the problem.
 +
 
 +
At the time of writing, October 2019, Gnome desktop versions of Fedora, Red Hat, Suse and Mageia and Debian all require the library LibAppIndicator3 be installed and the Gnome Shell Extension, Top Icons Plus be installed.
 +
 
 +
Mageia Enlightenment also requires LibAppIndicator3 and enabling System Tray in Settings->Modules and the adding that System Tray to a Shelf (all terms familiar to Enlightenment users). Unfortunately, even that gets 'an' icon, not the one you carefully select for your application.
 +
 
 +
As of Lazarus 2.0.6, LCL will attempt to 'guess' the correct model to display a Tray Icon. However as distributions change over time, or with more obscure distributions you may need to override these guesses. For GTK apps, by setting an environment variable, LAZUSEAPPIND you can force an app to try to use LibAppIndicator3, prevent it from trying or just tell us which way it has guessed using YES, NO or INFO.  eg
 +
 
 +
<syntaxhighlight lang="bash">LAZUSEAPPIND=YES project1 <enter></syntaxhighlight>
 +
 
 +
Will force project1 to try to use LibAppindicator3. Obviously, it may not be available or it may not be suitable for the desktop in use but it will try. A line or two of text will be printed on stdout if the var is defined and not blank. Many systems will display the TrayIcon without using this environment variable.  If the desktop you are running does require LibAppIndicator3, then you must accept all it can ever do is trigger a menu, no OnClick event.
 +
 
 +
==== Why two models ? ====
 +
LibAppIndicator3 does not do as much as the older System Tray model. LibAppIndicator3 is an outgrowth of Unity's definition of a 'simpler' interface, it will display only a menu, it does not pass an event, OnClick, back to your app. Indeed, if you have not assigned a popup menu and LibAppIndicator3 is in use your Icon will not show up at all. So, applications that depend on getting a OnClick event will not work with LibAppIndicator3.
 +
 
 +
''Developers of new applications may well be advised to design their program around TrayIcon using only a popUpMenu !''
 +
 
 +
==== LibAppIndicator3 ====
 +
Can generally be installed from your distribution's normal package library. However, it is packaged with a number of different names. Sigh ...
 +
* libappindicator3 - Slackware, NetBSD
 +
* libappindicator3-1 - openSUSE and Debian [-based]
 +
* libappindicator-gtk3 - Arch, ALT, CentOS and Fedora, RedHat
 +
* libappindicator3_1 - all Mandrake/Mandriva derivatives -- Mageia,  OpenMandriva, PCLinuxOS, Rosa
 +
 +
 
 +
==== gnome-shell-extension-appindicator ====
 +
This seems to be a viable solution mid 2021 for Fedora Gnome and, perhaps Debian Bullseye Gnome. This plugin for Gnome is made by ubuntu to work like its old Unity AppIndicator model. So, in addition the the gnome plugin, you also need to install (eg on Fedora) the appindicator3 library. KNSI inspired so no fancy right clicks allowed, just assign it a menu.
 +
 
 +
On Fedora, you can do this (note you don't need gnome-tweaks on Fedora 34) -
 +
<syntaxhighlight lang="bash">sudo dnf install libappindicator-gtk3  gnome-shell-extension-appindicator gnome-tweaks [enter]</syntaxhighlight>
 +
Once installed, you need to restart the Desktop, just logout and back in. Then you must 'enable' the new plugin. On Fedora 33 thats easy, use the gnome-tweaks command, Extensions, enable "Kstatusnotifieritem/appindicator support". On Fedora 34, they have made it a bit harder by removing the Extensions section from Gnome Tweaks (too many happy users I expect). So, with Fedora 34, use the gnome-extensions command, it does not have a gui so issue the following command -
 +
<syntaxhighlight lang="bash"> gnome-extensions enable appindicatorsupport@rgcjonas.gmail.com [enter]</syntaxhighlight>
 +
Replace 'enable' with 'info' to get some diagnostic information.
  
TrayIcon used to be an optional component, but is part of LCL since Lazarus 0.9.23
+
Note, three steps, install, restart desktop, enable plugin.
 +
 
 +
While the same principle applies to '''Debian Bullseye''', its not quite so easy, See https://github.com/davidbannon/libappindicator3
 +
 
 +
==== TopIconsPlus ====
 +
 
 +
Sadly, the coming of Wayland seems to have killed TopIconsPlus. This section may be removed before long.
 +
 
 +
To install a Gnome Extension, you have to install, into (eg) Firefox an extension that allows you to control your collection of Gnome Extensions. Start your browser and search for "Gnome Extensions", read the instructions, maybe install and then use the same website to activate the extension. Awkward process but OK if you want to play with the wide range of extensions available. An alternative approach that works at present is to download the extension from github and install it, maybe not a good long term suggestion (?) -
 +
 
 +
As root -
 +
<syntaxhighlight lang="bash">dnf install make libappindicator-gtk3 gnome-tweak-tool</syntaxhighlight>
 +
 
 +
As yourself -
 +
<syntaxhighlight lang="bash">git clone https://github.com/phocean/TopIcons-plus.git
 +
cd TopIcons-plus
 +
make install
 +
</syntaxhighlight>
 +
 
 +
Logout and back in again.
 +
<syntaxhighlight lang="bash">gnome-tweaks</syntaxhighlight>
 +
In the app that runs, click Extensions, turn TopIcons-plus ON and click close
 +
 
 +
'''Remember - LibAppIndicator3 and possibly gnome-shell-extension-appindicator or TopIconsPlus may be needed on your end user's Linux machine !'''
 +
 
 +
==== Checking before invoking TrayIcon ====
 +
Because you app may show the user only its TrayIcon and if that's not visible the user cannot interact, you may like to test to see if its going to work. Firstly, you can, sort of determine if LCL will use the old System Tray (in which case it will probably be OK), look at code in lcl/interfaces/gtk2/UnityWSCtrl.pas.  If LCL is going to use LibAppIndicator3, you need to see if the library is available and, on a Gnome system, if TopIcons is enabled. The library is easy, try and load it, an error says its not there. To see if TopIcons is going to be available, the command "dconf read /org/gnome/shell/enabled-extensions" returns a few strings that may include "TopIcons". I expect there may also be an API ....
 +
 
 +
==== On GTK3 ====
 +
Trunk from October 2019 has a working GTK3 TrayIcon based, again, on LibAppIndicator3. The advice above relation to installing LibAppindicator3 and, where necessary TopIconsPlus applies to GTK3 as well. As the only way you can get a TrayIcon under GTK3 is the LibAppIndicator3, you can only use it to display a popup menu, don't expect to get a working OnClick event.
 +
 
 +
====QT5 on Linux====
 +
Some linux systems that won't display the GTK Tray Icon will display the Qt5 version, but only if they use XOrg. Any system using wayland apparently has other has issues with Qt5. Fedora and OpenSuse use wayland by default but users can choose to use XOrg instead at logon time.
 +
 
 +
=== Issue On the macOS 32 bit Carbon ===
 +
In October 2017 it was noted that a small problem existed on Sierra 10.12 when using the [[Carbon Interface|Carbon]] widget set. Attempts to update the caption of a menu item in a popup menu associated with a TrayIcon do not happen as expected. It is not uncommon to want to update the menu text at run time, for example, to display a list of recently opened files. This problem has been logged,  https://bugs.freepascal.org/view.php?id=32516 . A workaround that appears reliable is to call <syntaxhighlight inline lang="pascal">TrayIcon1.InternalUpdate;</syntaxhighlight> after making changes to the captions.  
 +
 
 +
This problem does not exist on Linux, Windows or on macOS when using the 64 bit [[Cocoa Interface|Cocoa]] widget set.
  
To start quickly, please read [[TrayIcon#Demonstration_program_1|the demonstration program]].
+
{{Warning|TrayIcon on macOS, using the 32 bit [[Carbon Interface|Carbon]] widget set has a memory leak.}}
  
 
=== Documentation ===
 
=== Documentation ===
 
+
Below is a list of all methods, properties and events of the component. They have the same names and work the same way on the visual component and on the non-visual object.
Bellow is a list of all methods, properties and events of the component. They have the same names and work the same way on the visual component and on the non-visual object.
 
  
 
A function works on all target platforms unless written otherwise.
 
A function works on all target platforms unless written otherwise.
  
 
==== Methods ====
 
==== Methods ====
 
 
<span style="color: teal">'''Show'''</span>
 
<span style="color: teal">'''Show'''</span>
  
Line 22: Line 97:
  
 
Shows the icon on the system tray.
 
Shows the icon on the system tray.
 
  
 
<span style="color: teal">'''Hide'''</span>
 
<span style="color: teal">'''Hide'''</span>
Line 29: Line 103:
  
 
Removes the icon from the system tray.
 
Removes the icon from the system tray.
 
  
 
<span style="color: teal">'''GetPosition'''</span>
 
<span style="color: teal">'''GetPosition'''</span>
Line 46: Line 119:
  
 
<span style="color: teal">'''PopUpMenu'''</span>
 
<span style="color: teal">'''PopUpMenu'''</span>
 
  
 
'''property''' PopUpMenu: TPopUpMenu;
 
'''property''' PopUpMenu: TPopUpMenu;
Line 53: Line 125:
  
 
==== Events ====
 
==== Events ====
 
 
<span style="color: teal">'''OnPaint'''</span>
 
<span style="color: teal">'''OnPaint'''</span>
  
Line 60: Line 131:
 
Use this to implement custom drawing to the icon. Draw using the canvas property of the icon.
 
Use this to implement custom drawing to the icon. Draw using the canvas property of the icon.
  
Note: Does not work on win32.
+
{{Note| Does not work on win32.}}
  
 +
{{Note| Following events not available on Linux if using the LibAppIndicator3 model, its menu only.}}
  
 
<span style="color: teal">'''OnClick'''</span>
 
<span style="color: teal">'''OnClick'''</span>
  
 
'''property''' OnClick: TNotifyEvent;
 
'''property''' OnClick: TNotifyEvent;
 
  
 
<span style="color: teal">'''OnDblClick'''</span>
 
<span style="color: teal">'''OnDblClick'''</span>
  
 
'''property''' OnDblClick: TNotifyEvent;
 
'''property''' OnDblClick: TNotifyEvent;
 
  
 
<span style="color: teal">'''OnMouseDown'''</span>
 
<span style="color: teal">'''OnMouseDown'''</span>
Line 81: Line 151:
  
 
'''property''' OnMouseUp: TMouseEvent;
 
'''property''' OnMouseUp: TMouseEvent;
 
  
 
<span style="color: teal">'''OnMouseMove'''</span>
 
<span style="color: teal">'''OnMouseMove'''</span>
  
 
'''property''' OnMouseMove: TMouseMoveEvent;
 
'''property''' OnMouseMove: TMouseMoveEvent;
 
=== Screenshot ===
 
 
  
 
=== Authors ===
 
=== Authors ===
 +
* [[User:Sekelsenmat|Felipe Monteiro de Carvalho]]
 +
* [[User:AndrewH|Andrew Haines]]
  
[[User:Sekelsenmat|Felipe Monteiro de Carvalho]]
+
{{Note| Windows: [[User:Ozznixon|Ozz Nixon]]}}
 
 
[[User:AndrewH|Andrew Haines]]
 
 
 
* Windows Notes: [[User:Ozznixon|Ozz Nixon]]
 
  
 
=== License ===
 
=== License ===
 
 
Modified LGPL.
 
Modified LGPL.
  
 
=== Download ===
 
=== Download ===
 
 
Status: Stable
 
Status: Stable
  
 
Can be located at Lazarus 0.9.22 or inferior at the directory: lazarus/components/trayicon
 
Can be located at Lazarus 0.9.22 or inferior at the directory: lazarus/components/trayicon
  
And on Lazaurs 0.9.23 or superior it is automatically installed with LCL
+
And on Lazarus 0.9.23 or superior it is automatically installed with LCL
 
 
 
 
 
 
=== Demonstration program 1 ===
 
  
 +
=== Example 1 - Using TIcon ===
 
As of Lazarus 0.9.26 TIcon has been fully implemented and it is no longer necessary to load the icon from a resource file on Windows. The icon can be loaded in the IDE or with usual code.
 
As of Lazarus 0.9.26 TIcon has been fully implemented and it is no longer necessary to load the icon from a resource file on Windows. The icon can be loaded in the IDE or with usual code.
  
Go to the Additional tab of components, and add a TTrayIcon to your form. Then change it's '''Name''' property to SystrayIcon
+
Go to the Additional tab of components, and add a TTrayIcon to your form. Then change its '''Name''' property to SystrayIcon
  
 
Next add a button to the form. Double click the button and add this code to it:
 
Next add a button to the form. Double click the button and add this code to it:
  
<pre>
+
<syntaxhighlight lang="pascal">
 
procedure MyForm.Button1Click(Sender: TObject);
 
procedure MyForm.Button1Click(Sender: TObject);
 
begin
 
begin
Line 131: Line 190:
 
   SystrayIcon.Show;
 
   SystrayIcon.Show;
 
end;
 
end;
</pre>
+
</syntaxhighlight>
 +
 
 +
=== Example 2 - Creating the icon with TLazIntfImage ===
 +
You can use TLazIntfImage to draw your icon quickly, as in the example code below:
 +
 
 +
<syntaxhighlight lang="pascal">
 +
procedure TForm1.DrawIcon;
 +
var
 +
  TempIntfImg: TLazIntfImage;
 +
  ImgHandle, ImgMaskHandle: HBitmap;
 +
  px, py: Integer;
 +
  TempBitmap: TBitmap;
 +
begin
 +
  try
 +
    TempIntfImg := TLazIntfImage.Create(16, 16);
 +
    TempBitmap := TBitmap.Create;
 +
    TempBitmap.Width := 16;
 +
    TempBitmap.Height := 16;
 +
    TempIntfImg.LoadFromBitmap(TempBitmap.Handle, TempBitmap.MaskHandle);
 +
 
 +
    // Set the pixels red
 +
    for py := 0 to TempIntfImg.Height - 1 do
 +
      for px := 0 to TempIntfImg.Width - 1 do
 +
        TempIntfImg.Colors[px, py] := colRed;
 +
 
 +
    // Copy it to a TBitmap
 +
    TempIntfImg.CreateBitmaps(ImgHandle,ImgMaskHandle, False);
 +
    TempBitmap.Handle := ImgHandle;
 +
    TempBitmap.MaskHandle := ImgMaskHandle;
 +
 
 +
    // And copy the TBitmap to your Icon
 +
    SystrayIcon.Icon.Assign(TempBitmap);
 +
    SystrayIcon.Show;
 +
 +
  finally
 +
    TempIntfImg.Free;
 +
    TempBitmap.Free;
 +
  end;
 +
end;</syntaxhighlight>
  
 
=== Subversion ===
 
=== Subversion ===
 
 
Located under components/trayicon/ on the latest subversion Lazarus.
 
Located under components/trayicon/ on the latest subversion Lazarus.
  
 
=== Help, Bug Reporting and Feature Request ===
 
=== Help, Bug Reporting and Feature Request ===
 
 
Please, post Bug Reports and Feature Requests on the [http://bugs.freepascal.org/main_page.php Lazarus Bugtracker].
 
Please, post Bug Reports and Feature Requests on the [http://bugs.freepascal.org/main_page.php Lazarus Bugtracker].
  
Help requests can be posted on the Lazarus mailling list or on the Lazarus [http://www.lazarus.freepascal.org/modules.php?op=modload&name=PNphpBB2&file=index Forum].
+
Help requests can be posted on the Lazarus mailing list or on the Lazarus [http://www.lazarus.freepascal.org/modules.php?op=modload&name=PNphpBB2&file=index Forum].
  
 
=== Change Log ===
 
=== Change Log ===
 
 
# 17/01/2006 - Available as a preview on the Lazarus subversion. Still under heavy construction, however.
 
# 17/01/2006 - Available as a preview on the Lazarus subversion. Still under heavy construction, however.
 
# 24/01/2006 - Stable under win32, gnome and gtk1, but still waiting for gtk2 support. Lazarus 0.9.12 was release with this version.
 
# 24/01/2006 - Stable under win32, gnome and gtk1, but still waiting for gtk2 support. Lazarus 0.9.12 was release with this version.
 
# 17/02/2006 - Added support for gtk2 on subversion.
 
# 17/02/2006 - Added support for gtk2 on subversion.
# As of 2010 Carbon and Qt are also supported
+
# July 2008 - Implements support for Qt 4
 +
# July 2008 - Implements support for Carbon through [[PasCocoa]]
  
 
=== Technical Details ===
 
=== Technical Details ===
 
 
A difficulty on the development of this component was the many differences on the system tray implementation on various OSes and even Window Managers on Linux. To solve this, the component tries to implement the minimal set of features common to all target platforms. Below is a list of the features implemented on each platform:
 
A difficulty on the development of this component was the many differences on the system tray implementation on various OSes and even Window Managers on Linux. To solve this, the component tries to implement the minimal set of features common to all target platforms. Below is a list of the features implemented on each platform:
  
 
'''Windows''' - Multiple system tray icons per application are supported. The image of the icon can be altered using a HICON handle. Events to the icon are sent via a special message on the user reserved space of messages (>= WM_USER) to the Window which owns the Icon. No paint events are sent to the Window.
 
'''Windows''' - Multiple system tray icons per application are supported. The image of the icon can be altered using a HICON handle. Events to the icon are sent via a special message on the user reserved space of messages (>= WM_USER) to the Window which owns the Icon. No paint events are sent to the Window.
  
* NOTE * for some odd reason the environment by default does not support WM_USER+ messages, you will need to add "-dPassWin32MessagesToLCL" (without quotations) to support the messaging code. The steps are, click Tools -> Configure "Build Lazarus"..., and add that compiler option to "Options". If you have any existing options, they are "space" delimited.
+
{{Note| for some odd reason the environment by default does not support WM_USER+ messages, you will need to add "-dPassWin32MessagesToLCL" (without quotations) to support the messaging code. The steps are, click Tools -> Configure "Build Lazarus"..., and add that compiler option to "Options". If you have any existing options, they are "space" delimited.}}
  
 
'''Linux (Gnome, KDE, IceWM, etc)''' - Multiple system tray icons per application are supported. The image of the icon is actually a very small Window, and can be painted and receive events just like any other TForm descendant.
 
'''Linux (Gnome, KDE, IceWM, etc)''' - Multiple system tray icons per application are supported. The image of the icon is actually a very small Window, and can be painted and receive events just like any other TForm descendant.
Line 162: Line 256:
 
'''Linux (WindowMaker, Openbox, etc)''' - Does not support system tray icons out-of-the-box. However, There are at least two softwares that provides support for it: [http://icculus.org/openbox/2/docker/ Docker] and [http://freshmeat.net/projects/wmsystray/ WMSystray]
 
'''Linux (WindowMaker, Openbox, etc)''' - Does not support system tray icons out-of-the-box. However, There are at least two softwares that provides support for it: [http://icculus.org/openbox/2/docker/ Docker] and [http://freshmeat.net/projects/wmsystray/ WMSystray]
  
'''Mac OS X''' - TTrayIcon support is implemented using the menu bar extras. Unfortunatelly the API to use menu bar extras is only available in Cocoa and not in Carbon, so we use the stable PasCocoa bindings in the Carbon interface to support menu bar extras even in older FPC compilers and in the Cocoa interface we will use the more modern Objective Pascal syntax.
+
'''macOS''' - TTrayIcon support is implemented using the menu bar extras. Unfortunately the API to use menu bar extras is only available in Cocoa and not in Carbon, so we use the stable PasCocoa bindings in the Carbon interface to support menu bar extras even in older FPC compilers and in the Cocoa interface we will use the more modern Objective Pascal syntax.
  
 
[[Image:Mn_menubaritems.jpg]]
 
[[Image:Mn_menubaritems.jpg]]
Line 168: Line 262:
 
To read more about menu bar extras:
 
To read more about menu bar extras:
  
# http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGMenus/chapter_16_section_6.html
+
# https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/StatusBar/StatusBar.html
# http://developer.apple.com/mac/library/documentation/UserExperience/Conceptual/AppleHIGuidelines/XHIGMenus/XHIGMenus.html
+
# https://developer.apple.com/design/human-interface-guidelines/macos/extensions/menu-bar-extras/
 +
# https://developer.apple.com/design/human-interface-guidelines/macos/menus/dock-menus/
 +
# https://developer.apple.com/design/human-interface-guidelines/macos/system-capabilities/dock/
 +
# https://developer.apple.com/design/human-interface-guidelines/macos/menus/menu-anatomy/
 
# http://en.wikipedia.org/wiki/Menu_extra
 
# http://en.wikipedia.org/wiki/Menu_extra
  
Line 177: Line 274:
  
 
The following extra features are already available or will be, but they won´t work on all platforms.
 
The following extra features are already available or will be, but they won´t work on all platforms.
 
 
* OnPaint event and Canvas property to draw the icon freely. Won´t work on Windows.
 
* OnPaint event and Canvas property to draw the icon freely. Won´t work on Windows.
  
 
=== External Links ===
 
=== External Links ===
 
 
* http://www.codeproject.com/shell/ctrayiconposition.asp - Code and theory to find the tray icon position under Windows
 
* http://www.codeproject.com/shell/ctrayiconposition.asp - Code and theory to find the tray icon position under Windows
 +
* http://cvs.gnome.org/viewcvs/gtk%2B/gtk/gtkstatusicon.c?rev=1.23&view=markup - Gtk2 code that implements gtkstatusicon
 +
* http://pasmontray.sourceforge.net - Open source program that uses TrayIcon to display CPU and memory utilisation in the system tray.
  
* http://cvs.gnome.org/viewcvs/gtk%2B/gtk/gtkstatusicon.c?rev=1.23&view=markup - Gtk2 code that implements gtkstatusicon
+
[[Category:Tutorials]]

Revision as of 11:23, 6 May 2021

English (en)

About

TTrayIcon is a multiplatform System Tray component. You can find TrayIcon on the Additional tab of the Component Palette (0.9.23+).

TrayIcon used to be an optional component, but is part of LCL since Lazarus 0.9.23

To start quickly, please read the demonstration program.


Linux may not display the Icon

Some Linux systems will have trouble displaying the GTK TrayIcon, in general this relates to a move away from the System Tray model that Lazarus TrayIcon is based on. This problem is a particular issue with Gnome but some other Desktops may also suffer. There are workarounds that involve using another library, LibAppIndicator3 and in some cases other extra packages and specific configuration steps. Its important to note, and to advise your end users, that the problem is with the Linux Distribution and its Desktop. You, as the application's programmer cannot directly solve the problem.

At the time of writing, October 2019, Gnome desktop versions of Fedora, Red Hat, Suse and Mageia and Debian all require the library LibAppIndicator3 be installed and the Gnome Shell Extension, Top Icons Plus be installed.

Mageia Enlightenment also requires LibAppIndicator3 and enabling System Tray in Settings->Modules and the adding that System Tray to a Shelf (all terms familiar to Enlightenment users). Unfortunately, even that gets 'an' icon, not the one you carefully select for your application.

As of Lazarus 2.0.6, LCL will attempt to 'guess' the correct model to display a Tray Icon. However as distributions change over time, or with more obscure distributions you may need to override these guesses. For GTK apps, by setting an environment variable, LAZUSEAPPIND you can force an app to try to use LibAppIndicator3, prevent it from trying or just tell us which way it has guessed using YES, NO or INFO. eg

LAZUSEAPPIND=YES project1 <enter>

Will force project1 to try to use LibAppindicator3. Obviously, it may not be available or it may not be suitable for the desktop in use but it will try. A line or two of text will be printed on stdout if the var is defined and not blank. Many systems will display the TrayIcon without using this environment variable. If the desktop you are running does require LibAppIndicator3, then you must accept all it can ever do is trigger a menu, no OnClick event.

Why two models ?

LibAppIndicator3 does not do as much as the older System Tray model. LibAppIndicator3 is an outgrowth of Unity's definition of a 'simpler' interface, it will display only a menu, it does not pass an event, OnClick, back to your app. Indeed, if you have not assigned a popup menu and LibAppIndicator3 is in use your Icon will not show up at all. So, applications that depend on getting a OnClick event will not work with LibAppIndicator3.

Developers of new applications may well be advised to design their program around TrayIcon using only a popUpMenu !

LibAppIndicator3

Can generally be installed from your distribution's normal package library. However, it is packaged with a number of different names. Sigh ...

  • libappindicator3 - Slackware, NetBSD
  • libappindicator3-1 - openSUSE and Debian [-based]
  • libappindicator-gtk3 - Arch, ALT, CentOS and Fedora, RedHat
  • libappindicator3_1 - all Mandrake/Mandriva derivatives -- Mageia, OpenMandriva, PCLinuxOS, Rosa


gnome-shell-extension-appindicator

This seems to be a viable solution mid 2021 for Fedora Gnome and, perhaps Debian Bullseye Gnome. This plugin for Gnome is made by ubuntu to work like its old Unity AppIndicator model. So, in addition the the gnome plugin, you also need to install (eg on Fedora) the appindicator3 library. KNSI inspired so no fancy right clicks allowed, just assign it a menu.

On Fedora, you can do this (note you don't need gnome-tweaks on Fedora 34) -

sudo dnf install libappindicator-gtk3  gnome-shell-extension-appindicator gnome-tweaks [enter]

Once installed, you need to restart the Desktop, just logout and back in. Then you must 'enable' the new plugin. On Fedora 33 thats easy, use the gnome-tweaks command, Extensions, enable "Kstatusnotifieritem/appindicator support". On Fedora 34, they have made it a bit harder by removing the Extensions section from Gnome Tweaks (too many happy users I expect). So, with Fedora 34, use the gnome-extensions command, it does not have a gui so issue the following command -

 gnome-extensions enable appindicatorsupport@rgcjonas.gmail.com [enter]

Replace 'enable' with 'info' to get some diagnostic information.

Note, three steps, install, restart desktop, enable plugin.

While the same principle applies to Debian Bullseye, its not quite so easy, See https://github.com/davidbannon/libappindicator3

TopIconsPlus

Sadly, the coming of Wayland seems to have killed TopIconsPlus. This section may be removed before long.

To install a Gnome Extension, you have to install, into (eg) Firefox an extension that allows you to control your collection of Gnome Extensions. Start your browser and search for "Gnome Extensions", read the instructions, maybe install and then use the same website to activate the extension. Awkward process but OK if you want to play with the wide range of extensions available. An alternative approach that works at present is to download the extension from github and install it, maybe not a good long term suggestion (?) -

As root -

dnf install make libappindicator-gtk3 gnome-tweak-tool

As yourself -

git clone https://github.com/phocean/TopIcons-plus.git
cd TopIcons-plus
make install

Logout and back in again.

gnome-tweaks

In the app that runs, click Extensions, turn TopIcons-plus ON and click close

Remember - LibAppIndicator3 and possibly gnome-shell-extension-appindicator or TopIconsPlus may be needed on your end user's Linux machine !

Checking before invoking TrayIcon

Because you app may show the user only its TrayIcon and if that's not visible the user cannot interact, you may like to test to see if its going to work. Firstly, you can, sort of determine if LCL will use the old System Tray (in which case it will probably be OK), look at code in lcl/interfaces/gtk2/UnityWSCtrl.pas. If LCL is going to use LibAppIndicator3, you need to see if the library is available and, on a Gnome system, if TopIcons is enabled. The library is easy, try and load it, an error says its not there. To see if TopIcons is going to be available, the command "dconf read /org/gnome/shell/enabled-extensions" returns a few strings that may include "TopIcons". I expect there may also be an API ....

On GTK3

Trunk from October 2019 has a working GTK3 TrayIcon based, again, on LibAppIndicator3. The advice above relation to installing LibAppindicator3 and, where necessary TopIconsPlus applies to GTK3 as well. As the only way you can get a TrayIcon under GTK3 is the LibAppIndicator3, you can only use it to display a popup menu, don't expect to get a working OnClick event.

QT5 on Linux

Some linux systems that won't display the GTK Tray Icon will display the Qt5 version, but only if they use XOrg. Any system using wayland apparently has other has issues with Qt5. Fedora and OpenSuse use wayland by default but users can choose to use XOrg instead at logon time.

Issue On the macOS 32 bit Carbon

In October 2017 it was noted that a small problem existed on Sierra 10.12 when using the Carbon widget set. Attempts to update the caption of a menu item in a popup menu associated with a TrayIcon do not happen as expected. It is not uncommon to want to update the menu text at run time, for example, to display a list of recently opened files. This problem has been logged, https://bugs.freepascal.org/view.php?id=32516 . A workaround that appears reliable is to call TrayIcon1.InternalUpdate; after making changes to the captions.

This problem does not exist on Linux, Windows or on macOS when using the 64 bit Cocoa widget set.

Warning-icon.png

Warning: TrayIcon on macOS, using the 32 bit Carbon widget set has a memory leak.

Documentation

Below is a list of all methods, properties and events of the component. They have the same names and work the same way on the visual component and on the non-visual object.

A function works on all target platforms unless written otherwise.

Methods

Show

procedure Show;

Shows the icon on the system tray.

Hide

procedure Hide;

Removes the icon from the system tray.

GetPosition

function GetPosition: TPoint;

Returns the position of the tray icon on the display. This function is utilized to show message boxes near the icon. Currently it´s only a stub, no implementations are available and TPoint(0, 0) is returned.

Properties

Hint

property Hint: string;

A Hint will be shown the string isn't empty

PopUpMenu

property PopUpMenu: TPopUpMenu;

A PopUp menu that appears when the user right-clicks the tray icon.

Events

OnPaint

property OnPaint: TNotifyEvent;

Use this to implement custom drawing to the icon. Draw using the canvas property of the icon.

Note-icon.png

Note: Does not work on win32.

Note-icon.png

Note: Following events not available on Linux if using the LibAppIndicator3 model, its menu only.

OnClick

property OnClick: TNotifyEvent;

OnDblClick

property OnDblClick: TNotifyEvent;

OnMouseDown

property OnMouseDown: TMouseEvent;


OnMouseUp

property OnMouseUp: TMouseEvent;

OnMouseMove

property OnMouseMove: TMouseMoveEvent;

Authors

Note-icon.png

Note: Windows: Ozz Nixon

License

Modified LGPL.

Download

Status: Stable

Can be located at Lazarus 0.9.22 or inferior at the directory: lazarus/components/trayicon

And on Lazarus 0.9.23 or superior it is automatically installed with LCL

Example 1 - Using TIcon

As of Lazarus 0.9.26 TIcon has been fully implemented and it is no longer necessary to load the icon from a resource file on Windows. The icon can be loaded in the IDE or with usual code.

Go to the Additional tab of components, and add a TTrayIcon to your form. Then change its Name property to SystrayIcon

Next add a button to the form. Double click the button and add this code to it:

procedure MyForm.Button1Click(Sender: TObject);
begin
  SystrayIcon.Icon.LoadFromFile('/path_to_icon/icon.ico');
  SystrayIcon.ShowHint := True;
  SystrayIcon.Hint := 'my tool tip';

  SystrayIcon.PopUpMenu := MyPopUpMenu;

  SystrayIcon.Show;
end;

Example 2 - Creating the icon with TLazIntfImage

You can use TLazIntfImage to draw your icon quickly, as in the example code below:

procedure TForm1.DrawIcon;
var
  TempIntfImg: TLazIntfImage;
  ImgHandle, ImgMaskHandle: HBitmap;
  px, py: Integer;
  TempBitmap: TBitmap;
begin
  try
    TempIntfImg := TLazIntfImage.Create(16, 16);
    TempBitmap := TBitmap.Create;
    TempBitmap.Width := 16;
    TempBitmap.Height := 16;
    TempIntfImg.LoadFromBitmap(TempBitmap.Handle, TempBitmap.MaskHandle);

    // Set the pixels red
    for py := 0 to TempIntfImg.Height - 1 do
      for px := 0 to TempIntfImg.Width - 1 do
        TempIntfImg.Colors[px, py] := colRed;

    // Copy it to a TBitmap
    TempIntfImg.CreateBitmaps(ImgHandle,ImgMaskHandle, False);
    TempBitmap.Handle := ImgHandle;
    TempBitmap.MaskHandle := ImgMaskHandle;

    // And copy the TBitmap to your Icon
    SystrayIcon.Icon.Assign(TempBitmap);
    SystrayIcon.Show;
 
  finally
    TempIntfImg.Free;
    TempBitmap.Free;
  end;
end;

Subversion

Located under components/trayicon/ on the latest subversion Lazarus.

Help, Bug Reporting and Feature Request

Please, post Bug Reports and Feature Requests on the Lazarus Bugtracker.

Help requests can be posted on the Lazarus mailing list or on the Lazarus Forum.

Change Log

  1. 17/01/2006 - Available as a preview on the Lazarus subversion. Still under heavy construction, however.
  2. 24/01/2006 - Stable under win32, gnome and gtk1, but still waiting for gtk2 support. Lazarus 0.9.12 was release with this version.
  3. 17/02/2006 - Added support for gtk2 on subversion.
  4. July 2008 - Implements support for Qt 4
  5. July 2008 - Implements support for Carbon through PasCocoa

Technical Details

A difficulty on the development of this component was the many differences on the system tray implementation on various OSes and even Window Managers on Linux. To solve this, the component tries to implement the minimal set of features common to all target platforms. Below is a list of the features implemented on each platform:

Windows - Multiple system tray icons per application are supported. The image of the icon can be altered using a HICON handle. Events to the icon are sent via a special message on the user reserved space of messages (>= WM_USER) to the Window which owns the Icon. No paint events are sent to the Window.

Note-icon.png

Note: for some odd reason the environment by default does not support WM_USER+ messages, you will need to add "-dPassWin32MessagesToLCL" (without quotations) to support the messaging code. The steps are, click Tools -> Configure "Build Lazarus"..., and add that compiler option to "Options". If you have any existing options, they are "space" delimited.

Linux (Gnome, KDE, IceWM, etc) - Multiple system tray icons per application are supported. The image of the icon is actually a very small Window, and can be painted and receive events just like any other TForm descendant.

Linux (WindowMaker, Openbox, etc) - Does not support system tray icons out-of-the-box. However, There are at least two softwares that provides support for it: Docker and WMSystray

macOS - TTrayIcon support is implemented using the menu bar extras. Unfortunately the API to use menu bar extras is only available in Cocoa and not in Carbon, so we use the stable PasCocoa bindings in the Carbon interface to support menu bar extras even in older FPC compilers and in the Cocoa interface we will use the more modern Objective Pascal syntax.

Mn menubaritems.jpg

To read more about menu bar extras:

  1. https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/StatusBar/StatusBar.html
  2. https://developer.apple.com/design/human-interface-guidelines/macos/extensions/menu-bar-extras/
  3. https://developer.apple.com/design/human-interface-guidelines/macos/menus/dock-menus/
  4. https://developer.apple.com/design/human-interface-guidelines/macos/system-capabilities/dock/
  5. https://developer.apple.com/design/human-interface-guidelines/macos/menus/menu-anatomy/
  6. http://en.wikipedia.org/wiki/Menu_extra

With this in mind an approach which supports all Platforms was created:

  • Painting is done via a TIcon object. (Required by Windows)

The following extra features are already available or will be, but they won´t work on all platforms.

  • OnPaint event and Canvas property to draw the icon freely. Won´t work on Windows.

External Links