Sign in Join
Wiki copytemporary

How to use a TrayIcon: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11### About
22
33**[[TTrayIcon]]** is a multiplatform System Tray component. You can find TrayIcon on the [[Additional tab]] of the [[Component Palette]] (0.9.23+).
44
55It works reliably on Windows, MacOS and Linux (and similar) with all desktops except the Gnome Desktop. It can be made work with Gnome but perhaps that's despite the Gnome Developers efforts.
66
77In use, drag the TrayIcon onto your form, assign an icon to it, assign a popup menu (with at least one menu item) to it and call its Show method
88
99To start quickly, please read [[TrayIcon|the demonstration program]].
1010
1111### Linux may not display the Icon
1212
1313Some 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 now two ways the GTK2 SysTray component tries to show its icon, the traditional System Tray and an AppIndicator library.
1414
1515Lazarus 2.2 (or fixes, main), now looks for an AppIndicator first and uses that if it it finds one. Only if that fails will it try for a traditional System Tray. This has several consequences -
1616
1717- The AppIndicator is intentionally a much simpler user interface. One click and it shows up a Popup Menu. **No double click, no drag, no right click, no hint.** If your app depends on one of those secondary responses, and you don't have a Gnome Desktop, you may try to force Lazarus to use the traditional SysTray, see below.
1818
1919- An AppIndicator library must be installed, until recently, that was libappindicator3 but now many distros are moving to libayatana. A number of prominent distributions appear to be pre installing a AppIndicator but you cannot assume.
2020
2121- On Gnome desktops, an additional item is needed, gnome-shell-extension-appindicator must be installed and **enabled**. See below.
2222
2323- Developers of new (Linux) applications are advised to design their program around TrayIcon using only a popUpMenu !
2424
2525Mageia Enlightenment also requires an AppIndicator library and enabling System Tray in Settings-\>Modules and then 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.
2626
2727#### Force traditional SysTray GTK2 ONLY
2828
2929This is a purely GTK2 behavior, not for GTK3, QT5 nor any non Linux widget set.
3030
3131As some systems do still have a functional traditional SysTray and it does offer a richer interface, you may wish to still use it. As of Lazarus 2.0.6, GTK2 LCL apps will look at an environment variable, LAZUSEAPPIND before deciding to use the AppIndicator, if its set to NO then the traditional SysTray will be used but no error is reported (or even detectable) if its not available. If set to INFO (or anything else than NO) it will report, to the console, what it is trying to do. (The YES option became irrelevant with Lazarus 2.2.)
3232
3333``` bash
3434LAZUSEAPPIND=NO myapp <enter>
3535```
3636
3737#### UnityWSCtrls.GlobalUseAppInd GTK2 ONLY
3838
3939Lazarus version 3.0 and later have an additional way to predetermine which of the two TrayIcon models will be used. This has been made necessary because of the growing inconsistency of TrayIcon models in Linux Distributions. For example, at present, apparently, no 32bit Linux will work with AppIndicator model and any Gnome based distro will only work with the AppIndicator. You can set UnityWSCtrls.GlobalUseAppInd depending on some checks about the system or config file setting in the startup code of your app.
4040
4141To use UnityWSCtrls.GlobalUseAppInd you must include 'UnityCtrls' in the uses section of a unit, it can be set to one of the UnityWSCtrls.TUseAppIndInstruction values, (UseAppIndYes, UseAppIndNo, UseAppIndAuto). It MUST be set before your TrayIcon is created, so, put your code in the project's LPR file ahead of Application.CreateForm(TMainForm, MainForm) line, or, if you prefer, manually create your TrayIcon later in the startup process.
4242
4343For example, this might appear in your LPR file -
4444
4545``` pascal
4646uses
4747 .....
4848 {$ifdef LCLGTK2}
4949 , unitywsctrls
5050 {$endif};
5151
5252{$R *.res}
5353
5454// ----------------------------------------------------------------------------
5555// This about reading the command line and env for instructions re TrayIcon
5656// It applies to ONLY gtk2 and Lazarus >= 3.0.0 !
5757// ----------------------------------------------------------------------------
5858{$ifdef LCLGTK2}
5959 function GetUseAppInd() : UnityWSCtrls.TUseAppIndInstruction;
6060 var
6161 EnvVar : string;
6262 begin
6363 Result := UnityWSCtrls.GlobalUseAppInd;
6464 if Application.HasOption('useappind') then begin // Command line
6565 if Application.GetOptionValue('useappind') = 'yes' then // if not set, leave it alone.
6666 Result := UseAppIndYes
6767 else if Application.GetOptionValue('useappind') = 'no' then
6868 Result := UseAppIndNo; // Anything other than yes or no is ignored
6969 end else begin
7070 EnvVar := Application.EnvironmentVariable['LAZUSEAPPIND']; // EnvironmentVariable
7171 if EnvVar = 'YES' then
7272 Result := UseAppIndYes
7373 else if EnvVar = 'NO' then
7474 Result := UseAppIndNo;
7575 end;
7676end;
7777{$endif}
7878
7979begin
8080 Application.Scaled := True;
8181 Application.Title := 'tomboy-ng';
8282 RequireDerivedFormResource:=True;
8383 Application.Initialize;
8484 {$ifdef LCLGTK2 }
8585 {$ifdef CPUi386} // Note: unless Ayatana fix their problem, no option for Gnome users
8686 // https://github.com/AyatanaIndicators/libayatana-appindicator/issues/76
8787 UnityWSCtrls.GlobalUseAppInd := UnityWSCtrls.UseAppIndNo; // 32bit must be a 'no'.
8888 {$endif}
8989 UnityWSCtrls.GlobalUseAppInd := GetUseAppInd(); // Set before creating TrayIcon
9090 {$endif}
9191 Application.CreateForm(TMainForm, MainForm);
9292 ....
9393```
9494
9595You most certainly do not have to set UnityWSCtrls.GlobalUseAppInd, in many case, its default settings will work. But it may not work for everyone, it does give you, the programmer, some control over the situation.
9696
9797> **Note:** At present, late 2023, every 32bit Linux I tested would generate an Access Violation when calling a GTK2 TrayIcon.Show setup to use the AppIndicator. So, better wrap it with a Try .. Except on E: EAccessViolation do...
9898
9999#### AppIndicator Libraries
100100
101101There are currently two possible AppIndicator libraries, Canonical's LibAppIndicator3-1 or libayatana-appindicator3-1, some systems have both, Bullseye has only the Ayatana one. Lazarus trunk supports Ayatana after 22 May 2021, r65122 and in 2.2.0. See External Links, below about the shift to Ayatana.
102102
103103One or the other library can generally be installed from your distribution's normal package library. However, it is packaged with a number of different names. Sigh ...
104104
105105- libappindicator3 - Slackware, NetBSD
106106- libappindicator3-1 - openSUSE and earlier Debian \[-based\]
107107- libappindicator-gtk3 - Arch, ALT, CentOS and Fedora, RedHat
108108- libappindicator3_1 - all Mandrake/Mandriva derivatives -- Mageia, OpenMandriva, PCLinuxOS, Rosa
109109- libayatana-appindicator3-1 - Debian Bullseye and most other Linuxs that offer Ayatana.
110110
111111#### gnome-shell-extension-appindicator
112112
113113This plugin is necessary for all current Gnome based systems. It is pre installed on some Gnome Desktops and only works with the an AppIndicator (not traditional SysTray). It is KNSI inspired so no fancy right clicks allowed, just assign it a menu.
114114
115115On Fedora, you can do this (note you don't need gnome-tweaks on Fedora 34) -
116116
117117``` bash
118118sudo dnf install libappindicator-gtk3 gnome-shell-extension-appindicator gnome-tweaks [enter]
119119```
120120
121121Once 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 -
122122
123123``` bash
124124 gnome-extensions enable appindicatorsupport@rgcjonas.gmail.com [enter]
125125```
126126
127127Replace 'enable' with 'info' to get some diagnostic information.
128128
129129Note, three steps, install, restart desktop, enable plugin !
130130
131131**Debian Bullseye** appears to arrive with the Ayatana library pre installed but the Gnome version still requires gnome-shell-extension-appindicator, install as above.
132132
133133Your application can enable the extension (after a desktop restart), if you are feeling brave see <https://github.com/tomboy-notes/tomboy-ng/blob/master/source/mainunit.pas>
134134
135135**Note :** *Adding the plugin as a dependency of your application might seem attractive but do not do so ! On desktops other than Gnome, it will pull in, as dependencies, the full Gnome desktop. Your end users will not thank you.*
136136
137137#### Checking before invoking TrayIcon
138138
139139Because your 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. Sadly a test previously recommend here has now proved to be unreliable (in Ubuntu 21.10) and its been removed from Lazarus.
140140
141141<https://github.com/tomboy-notes/tomboy-ng/blob/master/source/mainunit.pas> function TMainForm.CheckGnomeExtras() has code that asks the Gnome plugin manager if if the plugin is installed and enabled. And it enables it if necessary. And we really should not have to do things like that !
142142
143143#### On GTK3
144144
145145Trunk from October 2019 has a working GTK3 TrayIcon based, again, on the AppIndicator. The advice above relating to installing LibAppindicator3 applies to GTK3 as well. As the only way you can get a TrayIcon under GTK3 is the an AppIndicator, you can only use it to display a popup menu, don't expect to get a working OnClick event.
146146
147147#### QT5 on Linux
148148
149149Some 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. Most Gnome desktops and some others use wayland by default but users can choose to use XOrg instead at logon time.
150150
151151#### Showing the Icon before establishing its Menu
152152
153153It has long been known that the System Tray Icon, on Linux at least, will not show if its .show function is called before it's popup menu has been assigned. No error shown, just no Icon to be seen.
154154
155155However, in 2023 with the release of Ubuntu using Gnome Desktop 44.0, a new aspect appeared. If the popup menu assigned has, itself, no menu items when .show is called, the menu is never shown even after menu items are added. In the case of gtk2, we do get an error message (complete with spelling mistake) but we see no menu. With Qt5, no error message, we get a menu but in the wrong part of the screen, and, after a being displayed a few times, we loose even that. We do not see this issue on any other OS or even any other Linux Desktop. How very Gnome-ish !
156156
157157So, in summary, if you are managing menu items dynamically, make sure you have at least one menu item added to the popup menu and that popup menu assigned to the TrayIcon BEFORE calling TrayIcon.show.
158158
159159note: chapter about 32bit carbon removed as irreverent.
160160
161161### Documentation
162162
163163Below 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.
164164
165165A function works on all target platforms unless written otherwise.
166166
167167#### Methods
168168
169-<span style="color: teal">**Show**</span>
169+**Show**
170170
171171**procedure** Show;
172172
173173Shows the icon on the system tray.
174174
175-<span style="color: teal">**Hide**</span>
175+**Hide**
176176
177177**procedure** Hide;
178178
179179Removes the icon from the system tray.
180180
181-<span style="color: teal">**GetPosition**</span>
181+**GetPosition**
182182
183183**function** GetPosition: TPoint;
184184
185185Returns 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.
186186
187187#### Properties
188188
189-<span style="color: teal">**Hint**</span>
189+**Hint**
190190
191191**property** Hint: string;
192192
193193A Hint will be shown the string isn't empty
194194
195-<span style="color: teal">**PopUpMenu**</span>
195+**PopUpMenu**
196196
197197**property** PopUpMenu: TPopUpMenu;
198198
199199A PopUp menu that appears when the user right-clicks the tray icon.
200200
201201#### Events
202202
203-<span style="color: teal">**OnPaint**</span>
203+**OnPaint**
204204
205205**property** OnPaint: TNotifyEvent;
206206
207207Use this to implement custom drawing to the icon. Draw using the canvas property of the icon.
208208
209209> **Note:** Does not work on win32.
210210
211211> **Note:** Following events not available on Linux if using the LibAppIndicator3 model, its menu only.
212212
213-<span style="color: teal">**OnClick**</span>
213+**OnClick**
214214
215215**property** OnClick: TNotifyEvent;
216216
217-<span style="color: teal">**OnDblClick**</span>
217+**OnDblClick**
218218
219219**property** OnDblClick: TNotifyEvent;
220220
221-<span style="color: teal">**OnMouseDown**</span>
221+**OnMouseDown**
222222
223223**property** OnMouseDown: TMouseEvent;
224224
225-<span style="color: teal">**OnMouseUp**</span>
225+**OnMouseUp**
226226
227227**property** OnMouseUp: TMouseEvent;
228228
229-<span style="color: teal">**OnMouseMove**</span>
229+**OnMouseMove**
230230
231231**property** OnMouseMove: TMouseMoveEvent;
232232
233233### Authors
234234
235235- Felipe Monteiro de Carvalho
236236- Andrew Haines
237237
238238> **Note:** Windows: Ozz Nixon
239239
240240### License
241241
242242Modified LGPL.
243243
244244### Download
245245
246246Status: Stable
247247
248248Can be located at Lazarus 0.9.22 or inferior at the directory: lazarus/components/trayicon
249249
250250And on Lazarus 0.9.23 or superior it is automatically installed with LCL
251251
252252### Example 1 - Using TIcon
253253
254254As 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.
255255
256256Go to the Additional tab of components, and add a TTrayIcon to your form. Then change its **Name** property to SystrayIcon
257257
258258Next add a button to the form. Double click the button and add this code to it:
259259
260260``` pascal
261261procedure MyForm.Button1Click(Sender: TObject);
262262begin
263263 SystrayIcon.Icon.LoadFromFile('/path_to_icon/icon.ico');
264264 SystrayIcon.ShowHint := True;
265265 SystrayIcon.Hint := 'my tool tip';
266266
267267 SystrayIcon.PopUpMenu := MyPopUpMenu;
268268
269269 SystrayIcon.Show;
270270end;
271271```
272272
273273### Example 2 - Creating the icon with TLazIntfImage
274274
275275You can use TLazIntfImage to draw your icon quickly, as in the example code below:
276276
277277``` pascal
278278procedure TForm1.DrawIcon;
279279var
280280 TempIntfImg: TLazIntfImage;
281281 ImgHandle, ImgMaskHandle: HBitmap;
282282 px, py: Integer;
283283 TempBitmap: TBitmap;
284284begin
285285 try
286286 TempIntfImg := TLazIntfImage.Create(16, 16);
287287 TempBitmap := TBitmap.Create;
288288 TempBitmap.Width := 16;
289289 TempBitmap.Height := 16;
290290 TempIntfImg.LoadFromBitmap(TempBitmap.Handle, TempBitmap.MaskHandle);
291291
292292 // Set the pixels red
293293 for py := 0 to TempIntfImg.Height - 1 do
294294 for px := 0 to TempIntfImg.Width - 1 do
295295 TempIntfImg.Colors[px, py] := colRed;
296296
297297 // Copy it to a TBitmap
298298 TempIntfImg.CreateBitmaps(ImgHandle,ImgMaskHandle, False);
299299 TempBitmap.Handle := ImgHandle;
300300 TempBitmap.MaskHandle := ImgMaskHandle;
301301
302302 // And copy the TBitmap to your Icon
303303 SystrayIcon.Icon.Assign(TempBitmap);
304304 SystrayIcon.Show;
305305
306306 finally
307307 TempIntfImg.Free;
308308 TempBitmap.Free;
309309 end;
310310end;
311311```
312312
313313### Subversion
314314
315315Located under components/trayicon/ on the latest subversion Lazarus.
316316
317317### Help, Bug Reporting and Feature Request
318318
319319Please, post Bug Reports and Feature Requests on the [Lazarus Bugtracker](http://bugs.freepascal.org/main_page.php).
320320
321321Help requests can be posted on the Lazarus mailing list or on the Lazarus [Forum](http://www.lazarus.freepascal.org/modules.php?op=modload&name=PNphpBB2&file=index).
322322
323323### Change Log
324324
3253251. 17/01/2006 - Available as a preview on the Lazarus subversion. Still under heavy construction, however.
3263262. 24/01/2006 - Stable under win32, gnome and gtk1, but still waiting for gtk2 support. Lazarus 0.9.12 was release with this version.
3273273. 17/02/2006 - Added support for gtk2 on subversion.
3283284. July 2008 - Implements support for Qt 4
3293295. July 2008 - Implements support for Carbon through [[PasCocoa]]
330330
331331### Technical Details
332332
333333A 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:
334334
335335**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.
336336
337337> **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.
338338
339339**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. Note that this does not apply to TrayIcons that are using the OS's AppIndicator interface. Certainly not Gnome, maybe not of desktops as time goes by.
340340
341341**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](http://icculus.org/openbox/2/docker/) and [WMSystray](http://freshmeat.net/projects/wmsystray/)
342342
343343**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.
344344
345-<figure>
346-<img src="Mn_menubaritems.jpg" title="Mn_menubaritems.jpg" />
347-<figcaption>Mn_menubaritems.jpg</figcaption>
348-</figure>
345+![](/wiki-images/9/97/Mn_menubaritems.jpg)
349346
350347To read more about menu bar extras:
351348
3523491. <https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/StatusBar/StatusBar.html>
3533502. <https://developer.apple.com/design/human-interface-guidelines/macos/extensions/menu-bar-extras/>
3543513. <https://developer.apple.com/design/human-interface-guidelines/macos/menus/dock-menus/>
3553524. <https://developer.apple.com/design/human-interface-guidelines/macos/system-capabilities/dock/>
3563535. <https://developer.apple.com/design/human-interface-guidelines/macos/menus/menu-anatomy/>
3573546. <http://en.wikipedia.org/wiki/Menu_extra>
358355
359356With this in mind an approach which supports all Platforms was created:
360357
361358- Painting is done via a TIcon object. (Required by Windows)
362359
363360The following extra features are already available or will be, but they won´t work on all platforms.
364361
365362- OnPaint event and Canvas property to draw the icon freely. Won´t work on Windows.
366363
367364### External Links
368365
369366- <http://www.codeproject.com/shell/ctrayiconposition.asp> - Code and theory to find the tray icon position under Windows
370367- <http://cvs.gnome.org/viewcvs/gtk%2B/gtk/gtkstatusicon.c?rev=1.23&view=markup> - Gtk2 code that implements gtkstatusicon
371368- <http://pasmontray.sourceforge.net> - Open source program that uses TrayIcon to display CPU and memory utilisation in the system tray.
372369- [Background to Debian's switch from libappindicator to Ayatana](https://lists.debian.org/debian-devel/2018/03/msg00506.html)
373370- [Ayatana App Indicator](https://github.com/AyatanaIndicators/libayatana-appindicator)
374371
375372---
376373*From the Free Pascal wiki, page "How to use a TrayIcon", as it stood on 2023-12-09 after a change by Dbannon, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
377374Category: Tutorials

Back to history