Simple library for desktop notifications from Java on Windows, Mac OS X and Linux.
- One-line of code to show a notification for most cases.
- Tries to find the best implementation available to give the best looking and most integrated experience..
- No hard dependencies, although can be augmented with AWT, Swing, SWT or JavaFX to provide further options.
- Supports NONE, INFO, ERROR and WARNING notifications types, each with it's own icon.
- Depending on provider, can support custom icons, images and actions.
- Can integrate with your existing system tray icon if required (SWT and Swing/AWT)
- Cross platform and custom JavaFX and SWT popup notifications included.
All platforms support Growls GNTP protocol. If you have have Growl for Mac OS X, Linux or Windows installed, and it is listening on the default port, it will be used in preference to all platform specific notification systems.
All platforms can use one of the Java GUI toolkit specific implementations, such as JavaFX or SWT. If these toolkit libraries are available, those will be chosen if the experience is superior to the native implementation.
Additionally on all platforms, if no notifier implementation can be found, the last resort fallback will be to display the messages on System.out.
In all cases, you can override the chosen provider using ToasterSettings.setPreferredToasterClassName
, see below.
Windows support is currently provided in the following order :-
- JavaFX. If JavaFX and ControlsFX is on the CLASSPATH, ControlsFX based notification popups will be used.
- SWT. If SWT is on the CLASSPATH, the custom SWT popup component will be used. The alternative System Tray based support and balloon tooltip can be used by explicitly requesting it.
- AWT. If no SWT is available, the built-in AWT System Tray support will be used.
Mac OS X support will be provided in the following order :-
- If native notification centre support is available (Mountain Lion and above), it will be used first.
- Growl (via AppleScript). If Growl via AppleScript is available, it will be used.
- If there is no growl, but osascript is an available command, the default Notification Centre will be used
- JavaFX. If JavaFX and ControlsFX is on the CLASSPATH, ControlsFX based notification
- SWT. If SWT is on the CLASSPATH, the custom SWT popup component will be used. The alternative System Tray based support and balloon tooltip can be used by explicitly requesting it.
- AWT. If no SWT is available, the built-in AWT System Tray support will be used.
Linux support will be provided in the following order :-
- If
dbus-java
is available, native DBus notifications will be used. - notify-send. If this is an available command, the default desktop notifications will be used
- JavaFX. If JavaFX and ControlsFX is on the CLASSPATH, ControlsFX based notification
- SWT. If SWT is on the CLASSPATH, the custom SWT popup component will be used. The alternative System Tray based support and balloon tooltip can be used by explicitly requesting it.
- AWT. If no SWT is available, the built-in AWT System Tray support will be used.
The library is available in Maven Central, so configure your project according to the build system you use. For example, for Maven itself :-
<dependencies>
<dependency>
<groupId>com.sshtools</groupId>
<artifactId>two-slices</artifactId>
<version>0.9.4</version>
</dependency>
</dependencies>
Development builds may be available in the snapshots repository
<repositories>
<repository>
<id>oss-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
..
<dependencies>
<dependency>
<groupId>com.sshtools</groupId>
<artifactId>two-slices</artifactId>
<version>0.9.5-SNAPSHOT</version>
</dependency>
</dependencies>
At time of writing this, the SWT artifacts that are available on Maven Central are incompatible with having a cross-platform and fully JPMS compliant library or application. This is due to the module naming scheme chosen by the SWT packagers.
Two Slices is fully JPMS compliant otherwise, and including SWT as in the primary artifact would degrade this support.
For this reason, if you wish to use SWT you must also add the separate SWT artifact.
This is not modular, other than having an Automatic-Module-Name
. If you are using
SWT, you probably do not care about this as you'll have other problems with JPMS
anyway.
<dependencies>
<dependency>
<groupId>com.sshtools</groupId>
<artifactId>two-slices-swt</artifactId>
<version>0.9.4</version>
</dependency>
</dependencies>
For the simplest use, call Toast.toast() :-
Toast.toast(ToastType.INFO, "Information", "Here is some information you cannot do without.");
You can pass in the full path to an icon too (requires support for this in selected platform)
Toast.toast(ToastType.INFO, "/usr/share/pixmaps/mypic.png", "Boo!", "See my image?");
An alternative way to build more complex messages is using ToastBuilder
.
var builder = Toast.builder();
builder.title("My Title");
builder.content("Some content");
builder.toast();
You can prematurely close messages if the toaster implementation supports it.
var builder = Toast.builder();
builder.title("My Title");
builder.content("Some content");
var slice = builder.toast();
// ...
slice.close();
If you want to be notified when a message is closed, e.g. dismissed by the user. Set a listener on the builder.
var builder = Toast.builder();
builder.content("Some content");
builder.closed(() -> {
System.out.println("Message closed.");
});
builder.toast();
If the toaster implementation supports them, Actions may be added. An action would usually be represented as a button on a notification message.
There is a special action, the defaultAction()
. This is usually invoked when the whole notification message is clicked, or it may simply be presented as another button.
Be aware different implementations have different restrictions on how many actions can be presented.
var builder = Toast.builder();
builder.content("Some content");
builder.action("Action 1", () -> System.out.println("Do Action 1"));
builder.action("Action 2", () -> System.out.println("Do Action 2"));
builder.defaultAction(System.out.println("Do Default Action"));
builder.toast();
Some settings may be provided to alter the behaviour of the toasters. These are only hints, and specific toasters can ignore any and all of them.
ToasterFactory.setSettings(new ToasterSettings().setAppName("My App Name"));
Some toaster implementations have additional hints that can be passed. These hints are only generally only supported by individual toolkits. For example, to resize icons or images in the SWT implementation, you would do the following.
ToasterSettings settings = new ToasterSettings();
settings.getHints().put(BasicToastHint.ICON_SIZE, 64);
ToasterFactory.setSettings(settings);
BasicToastHint
contains a generic list of hints that a provider may or may not support. See
the class documentation for more detail.
Hints may also be set on individual toast, see ToastBuilder.hints()
.
Some implementations will require and/or show an icon in your system tray. This will be where the notification messages are anchored to. You can set a hint as to how to treat this icon via the configuration.
ToasterSettings settings = new ToasterSettings();
settings.setAppName("My App Name");
settings.setSystemTrayIconMode(SystemTrayIconMode.HIDDEN);
ToasterFactory.setSettings(settings);
The options for system tray icon mode are :-
- HIDDEN. The icon will be hidden at all times. This may require the use of a transparent image depending on the platform.
- SHOW_TOAST_TYPE_WHEN_ACTIVE. When active, the icon in the system tray will reflect the type of the current message that is being displayed.
- SHOW_DEFAULT_WHEN_ACTIVE. When a message is shown, the default tray icon will be show (see
ToasterSettings.setDefaultImage()
). - SHW_DEFAULT_ALWAYS. The default image (see above) will always be visible as soon as the first notification message is sent.
When you are providing a 'parent' tray item, the icon mode above may be ignored.
If you have an SWT application that already has an icon on the tray, you can re-use this for your notification settings when the SWT notifier is used.
For SWT, you must already be running an event loop (see SWT toolkit documentation). At the moment it is not possible to automatically start a loop mainly due to restrictions on OS X where SWT must be on the main thread.
TrayItem myTrayItem = ..... // this is the reference to your org.eclipse.swt.widgets.TrayItem
ToasterFactory.setSettings(new ToasterSettings().setParent(myTrayItem));
Then, whenever the SWT notifier is used, the balloon message will be anchored to your tray item.
If you have a Swing/AWT application that already has an icon on the tray, you can re-use this for your notification settings when the AWT notifier is used.
TrayIcon myTrayIcon = ..... // this is the reference to your java.awt.TrayIcon
ToasterFactory.setSettings(new ToasterSettings().setParent(myTrayIcon));
Then, whenever the AWT notifier is used, the balloon message will be anchored to your tray item.
You can add your own notifier implementations and customise the factory if you have any special requirements.
Implement the Toaster
interface. An abstract implementation AbstractToaster
is provided for your convenience and should be used where possible. By convention, all Toasters take a ToasterSettings
in their constructor.
In the constructor of your implementation, you should test if this implementation is for the current enviroment. E.g. if you were writing an OS X specific notifier, then you would test for running on that platform and the availability of any libraries or external tools you might need. By convention, if the environment is not sufficient, an UnsupportedOperationException
should be thrown.
Before your new Toaster
implementation can be used, you must provide a ToasterService
implementation that creates it based on the given configuration. By convention, you place this as an inner class inside the Toaster implementation.
public class MyToaster extends AbstractToaster {
public static class Service implements ToasterService {
@Override
public Toaster create(ToasterSettings settings) {
return new MyToaster(settings);
}
}
public MyToaster(ToasterSettings configuration) {
super(configuration);
}
@Override
public Slice toast(ToastBuilder builder) {
// TODO
}
}
For Java to automatically find this service, you must add it's full class name, e.g. com.mypackage.MyToaster$Service
to a file in META-INF/services/com.sshtools.twoslices.ToasterService
, and/or add it to module-info.java
using the appropriate syntax for Java services.
If you do not wish to use Java's ServiceLoader
feature to locate toaster implementations, you can extend ToasterFactory
and provide your own toaster()
method. This will be registered as the default factory the first time you instantiate it (so make sure you do this before ever asking for toast) :-
new ToasterFactory() {
@Override
public Toaster toaster() {
return new MyToaster();
}
};
Just call Toast.toast
as you normally would.