Skip to content

Commit 74614be

Browse files
committed
Adapt size of Dialogs with default size upon zoom change
When moved between monitors of different zoom, Dialogs may not show their full contents anymore. This is caused by their shell and the used fonts being linearly scaled in size according to the zoom, even though font size and required area for a font of a size are not linearly related. I.e., a font of double the size required more than double of the width and height. Since there are many ways to customize Dialogs and their sizes/layouts during and after initialization, it's difficult to solve that problem in general. It is, however, most severe for Dialogs that use the default calculated size and are not resizable, as those Dialogs do not have sophisticated layouts that adapt to the limited space and may easily lead to cut offs the user cannot work around by resizing. Thus, this change adds according zoom change and resize listeners to identify if a Window uses the default computed size and, in that case, recomputes it upon zoom change.
1 parent 68371cb commit 74614be

File tree

1 file changed

+55
-0
lines changed
  • bundles/org.eclipse.jface/src/org/eclipse/jface/dialogs

1 file changed

+55
-0
lines changed

bundles/org.eclipse.jface/src/org/eclipse/jface/dialogs/Dialog.java

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import java.util.Arrays;
1818
import java.util.HashMap;
19+
import java.util.concurrent.atomic.AtomicReference;
1920

2021
import org.eclipse.core.runtime.IProgressMonitor;
2122
import org.eclipse.core.runtime.IStatus;
@@ -40,6 +41,7 @@
4041
import org.eclipse.swt.widgets.Composite;
4142
import org.eclipse.swt.widgets.Control;
4243
import org.eclipse.swt.widgets.Display;
44+
import org.eclipse.swt.widgets.Listener;
4345
import org.eclipse.swt.widgets.Shell;
4446

4547
/**
@@ -1086,9 +1088,62 @@ protected static boolean dialogFontIsDefault() {
10861088
@Override
10871089
public void create() {
10881090
super.create();
1091+
hookZoomChangeListenerForDefaultSizedDialogs();
10891092
applyDialogFont(buttonBar);
10901093
}
10911094

1095+
/*
1096+
* There is no linear relation between font size and containing control size
1097+
* scaled according to some zoom value. In consequence, text with a scaled font
1098+
* size may not fit into a control/shell with a size scaled by the same zoom. To
1099+
* adhere for this in case of Windows using the default computed size, ensure
1100+
* that on zoom change the new proper size is computed and applied. This will
1101+
* not affect Windows that have a custom size, either programmatically or
1102+
* manually applied.
1103+
*/
1104+
private void hookZoomChangeListenerForDefaultSizedDialogs() {
1105+
boolean hasCustomSize = !getShell().getSize().equals(getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT, true));
1106+
boolean isEmpty = getShell().getChildren().length == 0;
1107+
if (resizeHasOccurred || hasCustomSize || isEmpty || isResizable()) {
1108+
return;
1109+
}
1110+
1111+
AtomicReference<Listener> customResizeListener = new AtomicReference<>();
1112+
Listener adaptDefaultSizeListener = event -> {
1113+
Shell shell = getShell();
1114+
if (shell == null || shell.isDisposed()) {
1115+
return;
1116+
}
1117+
Point size = shell.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
1118+
shell.setSize(size);
1119+
};
1120+
AtomicReference<Listener> zoomChangeListener = new AtomicReference<>();
1121+
zoomChangeListener.set(event -> {
1122+
Shell shell = getShell();
1123+
if (shell == null || shell.isDisposed()) {
1124+
return;
1125+
}
1126+
shell.addListener(SWT.Resize, adaptDefaultSizeListener);
1127+
shell.removeListener(SWT.Resize, customResizeListener.get());
1128+
shell.getChildren()[0].removeListener(SWT.ZoomChanged, zoomChangeListener.get());
1129+
});
1130+
customResizeListener.set(event -> {
1131+
Shell shell = getShell();
1132+
if (shell == null || shell.isDisposed()) {
1133+
return;
1134+
}
1135+
shell.getChildren()[0].removeListener(SWT.ZoomChanged, zoomChangeListener.get());
1136+
});
1137+
1138+
// We need to detect the zoom change event before the resize triggered by the
1139+
// zoom change happened, which is why we cannot listen to the zoom change at the
1140+
// shell but must use one of its children
1141+
getShell().getChildren()[0].addListener(SWT.ZoomChanged, zoomChangeListener.get());
1142+
// If custom resize happens before first zoom change, the dialog is custom sized
1143+
// and should not be auto-resized on zoom change
1144+
getShell().addListener(SWT.Resize, customResizeListener.get());
1145+
}
1146+
10921147
/**
10931148
* Get the IDialogBlockedHandler to be used by WizardDialogs and
10941149
* ModalContexts.

0 commit comments

Comments
 (0)