mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2025-12-06 05:50:53 +03:00
Windows: fixed wrong layout in maximized frame after changing screen scale factor (issue #904)
Some checks failed
CI / build (11, ) (push) Has been cancelled
CI / build (17, ) (push) Has been cancelled
CI / build (21, ) (push) Has been cancelled
CI / build (23, ) (push) Has been cancelled
CI / build (8, ) (push) Has been cancelled
Native Libraries / Natives (macos) (push) Has been cancelled
Native Libraries / Natives (ubuntu) (push) Has been cancelled
Native Libraries / Natives (windows) (push) Has been cancelled
CI / snapshot (push) Has been cancelled
CI / release (push) Has been cancelled
Some checks failed
CI / build (11, ) (push) Has been cancelled
CI / build (17, ) (push) Has been cancelled
CI / build (21, ) (push) Has been cancelled
CI / build (23, ) (push) Has been cancelled
CI / build (8, ) (push) Has been cancelled
Native Libraries / Natives (macos) (push) Has been cancelled
Native Libraries / Natives (ubuntu) (push) Has been cancelled
Native Libraries / Natives (windows) (push) Has been cancelled
CI / snapshot (push) Has been cancelled
CI / release (push) Has been cancelled
Windows binaries built and signed locally in clean workspace
This commit is contained in:
@@ -10,6 +10,8 @@ FlatLaf Change Log
|
||||
- FlatLaf window decorations:
|
||||
- Windows: Fixed possible deadlock with TabbedPane in window title area in
|
||||
"full window content" mode. (issue #909)
|
||||
- Windows: Fixed wrong layout in maximized frame after changing screen scale
|
||||
factor. (issue #904)
|
||||
- Linux: Fixed continuous cursor toggling between resize and standard cursor
|
||||
when resizing window. (issue #907)
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -309,6 +309,8 @@ public class FlatWindowsNativeWindowBorder
|
||||
WM_ENTERSIZEMOVE = 0x0231,
|
||||
WM_EXITSIZEMOVE = 0x0232,
|
||||
|
||||
WM_DPICHANGED = 0x02E0,
|
||||
|
||||
WM_DWMCOLORIZATIONCOLORCHANGED = 0x0320;
|
||||
|
||||
// WM_SIZE wParam
|
||||
@@ -501,6 +503,22 @@ public class FlatWindowsNativeWindowBorder
|
||||
isMoving = true;
|
||||
break;
|
||||
|
||||
case WM_DPICHANGED:
|
||||
LRESULT lResult = User32Ex.INSTANCE.CallWindowProc( defaultWndProc, hwnd, uMsg, wParam, lParam );
|
||||
|
||||
// if window is maximized and DPI/scaling changed, then Windows
|
||||
// does not send a subsequent WM_SIZE message and Java window bounds,
|
||||
// which depend on scale factor, are not updated
|
||||
boolean isMaximized = User32Ex.INSTANCE.IsZoomed( hwnd );
|
||||
if( isMaximized ) {
|
||||
MyRECT r = new MyRECT( new Pointer( lParam.longValue() ) );
|
||||
int width = r.right - r.left;
|
||||
int height = r.bottom - r.top;
|
||||
User32Ex.INSTANCE.CallWindowProc( defaultWndProc, hwnd, WM_SIZE, new WPARAM( SIZE_MAXIMIZED ), MAKELPARAM( width, height ) );
|
||||
}
|
||||
|
||||
return lResult;
|
||||
|
||||
case WM_ERASEBKGND:
|
||||
// do not erase background while the user is moving the window,
|
||||
// otherwise there may be rendering artifacts on HiDPI screens with Java 9+
|
||||
@@ -818,6 +836,13 @@ public class FlatWindowsNativeWindowBorder
|
||||
return (low & 0xffff) | ((high & 0xffff) << 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same implementation as MAKELPARAM(l, h) macro in winuser.h.
|
||||
*/
|
||||
private LPARAM MAKELPARAM( int low, int high ) {
|
||||
return new LPARAM( MAKELONG( low, high ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Same implementation as RGB(r,g,b) macro in wingdi.h.
|
||||
*/
|
||||
@@ -937,6 +962,23 @@ public class FlatWindowsNativeWindowBorder
|
||||
}
|
||||
}
|
||||
|
||||
//---- class MyRECT -------------------------------------------------------
|
||||
|
||||
@FieldOrder( { "left", "top", "right", "bottom" } )
|
||||
public static class MyRECT
|
||||
extends Structure
|
||||
{
|
||||
public int left;
|
||||
public int top;
|
||||
public int right;
|
||||
public int bottom;
|
||||
|
||||
public MyRECT( Pointer pointer ) {
|
||||
super( pointer );
|
||||
read();
|
||||
}
|
||||
}
|
||||
|
||||
//---- class MENUITEMINFO -------------------------------------------------
|
||||
|
||||
@FieldOrder( { "cbSize", "fMask", "fType", "fState", "wID", "hSubMenu",
|
||||
|
||||
@@ -19,3 +19,32 @@ The DLLs were built on a GitHub server with the help of GitHub Actions. See:
|
||||
[Native Libraries](https://github.com/JFormDesigner/FlatLaf/actions/workflows/natives.yml)
|
||||
workflow. Then the produced Artifacts ZIP was downloaded, signed DLLs with
|
||||
FormDev Software code signing certificate and committed the DLLs to Git.
|
||||
|
||||
|
||||
## Development
|
||||
|
||||
To build the library on Windows using Gradle, (parts of)
|
||||
[Visual Studio Community
|
||||
2022](https://visualstudio.microsoft.com/downloads/)
|
||||
needs to be installed. After downloading and running `VisualStudioSetup.exe` the
|
||||
**Visual Studio Installer** is installed and started. Once running, it shows the
|
||||
**Workloads** tab that allows you to install additional packages. Either choose
|
||||
**Desktop development with C++**, or to save some disk space switch to the
|
||||
**Single Components** tab and choose following components (newest versions):
|
||||
|
||||
- MSVC v143 - VS 2022 C++ x64/x86 Buildtools
|
||||
- MSVC v143 - VS 2022 C++ ARM64/ARM64EC Buildtools
|
||||
- Windows 11 SDK
|
||||
|
||||
Note that the Visual Studio Installer shows many similar named components for
|
||||
MSVC. Make sure to choose exactly those components listed above.
|
||||
|
||||
Using
|
||||
[Build Tools for Visual Studio 2022](https://visualstudio.microsoft.com/downloads/#remote-tools-for-visual-studio-2022)
|
||||
(installs only compiler and SDKs) instead of
|
||||
[Visual Studio Community
|
||||
2022](https://visualstudio.microsoft.com/downloads/)
|
||||
does not work with Gradle.
|
||||
|
||||
[Visual Studio Code](https://code.visualstudio.com/) with **C/C++** extension
|
||||
can be used for C++ code editing.
|
||||
|
||||
@@ -288,6 +288,23 @@ LRESULT CALLBACK FlatWndProc::WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, L
|
||||
isMoving = true;
|
||||
break;
|
||||
|
||||
case WM_DPICHANGED: {
|
||||
LRESULT lResult = ::CallWindowProc( defaultWndProc, hwnd, uMsg, wParam, lParam );
|
||||
|
||||
// if window is maximized and DPI/scaling changed, then Windows
|
||||
// does not send a subsequent WM_SIZE message and Java window bounds,
|
||||
// which depend on scale factor, are not updated
|
||||
bool isMaximized = ::IsZoomed( hwnd );
|
||||
if( isMaximized ) {
|
||||
RECT* r = reinterpret_cast<RECT*>( lParam );
|
||||
int width = r->right - r->left;
|
||||
int height = r->bottom - r->top;
|
||||
::CallWindowProc( defaultWndProc, hwnd, WM_SIZE, SIZE_MAXIMIZED, MAKELPARAM( width, height ) );
|
||||
}
|
||||
|
||||
return lResult;
|
||||
}
|
||||
|
||||
case WM_ERASEBKGND:
|
||||
// do not erase background while the user is moving the window,
|
||||
// otherwise there may be rendering artifacts on HiDPI screens with Java 9+
|
||||
|
||||
@@ -25,6 +25,8 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.TitledBorder;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
@@ -74,6 +76,7 @@ public class FlatWindowDecorationsTest
|
||||
}
|
||||
|
||||
private List<Image> images;
|
||||
private Timer refreshStateTimer;
|
||||
|
||||
FlatWindowDecorationsTest() {
|
||||
initComponents();
|
||||
@@ -132,6 +135,49 @@ public class FlatWindowDecorationsTest
|
||||
fullWindowContentButtonsBoundsField.setEnabled( bounds != null );
|
||||
} );
|
||||
}
|
||||
|
||||
if( window instanceof Frame ) {
|
||||
AtomicInteger lastState = new AtomicInteger( -1 );
|
||||
AtomicReference<Window> lastFullScreenWindow = new AtomicReference<>();
|
||||
refreshStateTimer = new Timer( 500, e -> {
|
||||
Frame frame = (Frame) window;
|
||||
int state = frame.getExtendedState();
|
||||
Window fullScreenWindow = window.getGraphicsConfiguration().getDevice().getFullScreenWindow();
|
||||
if( state != lastState.get() || fullScreenWindow != lastFullScreenWindow.get() ) {
|
||||
lastState.set( state );
|
||||
lastFullScreenWindow.set( fullScreenWindow );
|
||||
|
||||
String s = "";
|
||||
if( (state & Frame.ICONIFIED) != 0 )
|
||||
s += "iconified ";
|
||||
if( (state & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH )
|
||||
s += "maximized ";
|
||||
else {
|
||||
if( (state & Frame.MAXIMIZED_HORIZ) != 0 )
|
||||
s += "maximized-horizontal ";
|
||||
if( (state & Frame.MAXIMIZED_VERT) != 0 )
|
||||
s += "maximized-vertical ";
|
||||
}
|
||||
if( fullScreenWindow == window )
|
||||
s += "full-screen ";
|
||||
if( s.isEmpty() )
|
||||
s = "normal";
|
||||
|
||||
frameStateField.setText( s );
|
||||
}
|
||||
} );
|
||||
refreshStateTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotify() {
|
||||
super.removeNotify();
|
||||
|
||||
if( refreshStateTimer != null ) {
|
||||
refreshStateTimer.stop();
|
||||
refreshStateTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDecorationStyleRadioButtons( JRootPane rootPane ) {
|
||||
@@ -653,6 +699,9 @@ debug*/
|
||||
typeUtilityRadioButton = new JRadioButton();
|
||||
typeSmallRadioButton = new JRadioButton();
|
||||
showRectanglesCheckBox = new JCheckBox();
|
||||
JPanel hSpacer1 = new JPanel(null);
|
||||
JLabel frameStateLabel = new JLabel();
|
||||
frameStateField = new JLabel();
|
||||
menuBar = new JMenuBar();
|
||||
JMenu fileMenu = new JMenu();
|
||||
JMenuItem newMenuItem = new JMenuItem();
|
||||
@@ -1092,6 +1141,16 @@ debug*/
|
||||
showRectanglesCheckBox.setSelected(true);
|
||||
showRectanglesCheckBox.addActionListener(e -> showRectangles());
|
||||
add(showRectanglesCheckBox, "cell 0 3");
|
||||
add(hSpacer1, "cell 2 3 2 1");
|
||||
|
||||
//---- frameStateLabel ----
|
||||
frameStateLabel.setText("Frame state:");
|
||||
add(frameStateLabel, "cell 2 3 2 1,alignx right,growx 0");
|
||||
|
||||
//---- frameStateField ----
|
||||
frameStateField.setText("n/a");
|
||||
frameStateField.setFont(frameStateField.getFont().deriveFont(frameStateField.getFont().getStyle() | Font.BOLD));
|
||||
add(frameStateField, "cell 2 3 2 1,alignx right,growx 0");
|
||||
|
||||
//======== menuBar ========
|
||||
{
|
||||
@@ -1341,6 +1400,7 @@ debug*/
|
||||
private JRadioButton typeUtilityRadioButton;
|
||||
private JRadioButton typeSmallRadioButton;
|
||||
private JCheckBox showRectanglesCheckBox;
|
||||
private JLabel frameStateField;
|
||||
private JMenuBar menuBar;
|
||||
// JFormDesigner - End of variables declaration //GEN-END:variables
|
||||
}
|
||||
|
||||
@@ -637,6 +637,27 @@ new FormModel {
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 3"
|
||||
} )
|
||||
add( new FormComponent( "com.jformdesigner.designer.wrapper.HSpacer" ) {
|
||||
name: "hSpacer1"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 2 3 2 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "frameStateLabel"
|
||||
"text": "Frame state:"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 2 3 2 1,alignx right,growx 0"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "frameStateField"
|
||||
"text": "n/a"
|
||||
"font": new com.jformdesigner.model.SwingDerivedFont( null, 1, 0, false )
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 2 3 2 1,alignx right,growx 0"
|
||||
} )
|
||||
}, new FormLayoutConstraints( null ) {
|
||||
"location": new java.awt.Point( 0, 0 )
|
||||
"size": new java.awt.Dimension( 960, 570 )
|
||||
|
||||
@@ -46,8 +46,8 @@ glazedlists = "com.glazedlists:glazedlists:1.11.0"
|
||||
netbeans-api-awt = "org.netbeans.api:org-openide-awt:RELEASE112"
|
||||
|
||||
# flatlaf-natives-jna
|
||||
jna = "net.java.dev.jna:jna:5.12.1"
|
||||
jna-platform = "net.java.dev.jna:jna-platform:5.12.1"
|
||||
jna = "net.java.dev.jna:jna:5.15.0"
|
||||
jna-platform = "net.java.dev.jna:jna-platform:5.15.0"
|
||||
|
||||
# junit
|
||||
junit = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }
|
||||
|
||||
Reference in New Issue
Block a user