Skip to content

Commit 358485b

Browse files
committed
Add JFace snippet for a notification popup that follows its shell
Snippet086 keeps a NotificationPopup anchored to the bottom-right corner of a top-level shell by re-positioning it from a ControlListener whenever the shell is moved or resized.
1 parent c0809a9 commit 358485b

2 files changed

Lines changed: 92 additions & 0 deletions

File tree

docs/JFaceSnippets.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ Demonstrates a `NotificationPopup` with interactive content — a label and a bu
6767

6868
![Snippet085.png](images/Snippet085NotificationPopupWithUserInteraction.png)
6969

70+
### [Snippet086 - Notification Popup that Follows its Shell](https://github.com/eclipse-platform/eclipse.platform.ui/blob/master/examples/org.eclipse.jface.snippets/Eclipse%20JFace%20Snippets/org/eclipse/jface/snippets/notifications/Snippet086NotificationPopupFollowsShell.java)
71+
72+
Shows how to keep a `NotificationPopup` anchored to the bottom-right corner of a top-level shell by re-positioning it from a `ControlListener` when the shell is moved or resized.
73+
7074

7175
Layout
7276
------
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2026 Eclipse Platform contributors.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v. 2.0 which is available at
6+
* https://www.eclipse.org/legal/epl-2.0
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*******************************************************************************/
10+
package org.eclipse.jface.snippets.notifications;
11+
12+
import org.eclipse.jface.notifications.NotificationPopup;
13+
import org.eclipse.swt.events.ControlAdapter;
14+
import org.eclipse.swt.events.ControlEvent;
15+
import org.eclipse.swt.events.ControlListener;
16+
import org.eclipse.swt.graphics.Point;
17+
import org.eclipse.swt.graphics.Rectangle;
18+
import org.eclipse.swt.widgets.Display;
19+
import org.eclipse.swt.widgets.Shell;
20+
21+
/**
22+
* Shows a {@link NotificationPopup} that stays anchored to the bottom-right
23+
* corner of a top-level shell. Moving or resizing the shell repositions the
24+
* popup, so it appears to be attached to the window.
25+
*/
26+
public class Snippet086NotificationPopupFollowsShell {
27+
28+
/** Same edge padding the popup uses for its initial placement. */
29+
private static final int PADDING_EDGE = 5;
30+
31+
public static void main(String[] args) {
32+
Display display = new Display();
33+
Shell shell = new Shell(display);
34+
shell.setText("Move or resize me"); //$NON-NLS-1$
35+
shell.setSize(500, 350);
36+
shell.open();
37+
38+
NotificationPopup popup = NotificationPopup.forShell(shell) //
39+
.text("I follow the window. Drag the shell around!") //$NON-NLS-1$
40+
.title("Anchored notification", true) //$NON-NLS-1$
41+
.delay(0) // 0 disables the auto-close so the popup stays while you move the shell
42+
.build();
43+
popup.open();
44+
45+
Shell popupShell = popup.getShell();
46+
47+
// Re-anchor the popup whenever the parent shell moves or is resized.
48+
ControlListener follower = new ControlAdapter() {
49+
@Override
50+
public void controlMoved(ControlEvent e) {
51+
anchorToBottomRight(shell, popupShell);
52+
}
53+
54+
@Override
55+
public void controlResized(ControlEvent e) {
56+
anchorToBottomRight(shell, popupShell);
57+
}
58+
};
59+
shell.addControlListener(follower);
60+
61+
// Stop tracking once the popup is gone (e.g. closed via its close button).
62+
popupShell.addDisposeListener(e -> {
63+
if (!shell.isDisposed()) {
64+
shell.removeControlListener(follower);
65+
}
66+
});
67+
68+
while (!shell.isDisposed()) {
69+
if (!display.readAndDispatch()) {
70+
display.sleep();
71+
}
72+
}
73+
74+
display.dispose();
75+
}
76+
77+
private static void anchorToBottomRight(Shell parent, Shell popupShell) {
78+
if (popupShell == null || popupShell.isDisposed()) {
79+
return;
80+
}
81+
Rectangle clientArea = parent.getClientArea();
82+
Point clientOrigin = parent.toDisplay(0, 0);
83+
Point size = popupShell.getSize();
84+
int x = clientOrigin.x + clientArea.width - size.x - PADDING_EDGE;
85+
int y = clientOrigin.y + clientArea.height - size.y - PADDING_EDGE;
86+
popupShell.setLocation(x, y);
87+
}
88+
}

0 commit comments

Comments
 (0)