mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-13 07:17:13 -06:00
Native window decorations: when window is initially shown, fill background with window background color (instead of white), which avoids flickering in dark themes (issue #339)
This commit is contained in:
11
CHANGELOG.md
11
CHANGELOG.md
@@ -11,9 +11,14 @@ FlatLaf Change Log
|
|||||||
maximized windows. (issue #358)
|
maximized windows. (issue #358)
|
||||||
- Native window decorations (Windows 10 only):
|
- Native window decorations (Windows 10 only):
|
||||||
- Fixed occasional application crash in `flatlaf-windows.dll`. (issue #357)
|
- Fixed occasional application crash in `flatlaf-windows.dll`. (issue #357)
|
||||||
- When resizing a window to the right or to the bottom, then first fill the
|
- When window is initially shown, fill background with window background color
|
||||||
new space with the window background color (instead of black) before the
|
(instead of white), which avoids flickering in dark themes. (issue 339)
|
||||||
layout is updated.
|
- When resizing a window at the right/bottom edge, then first fill the new
|
||||||
|
space with the window background color (instead of black) before the layout
|
||||||
|
is updated.
|
||||||
|
- When resizing a window at the left/top edge, then first fill the new space
|
||||||
|
with the window background color (instead of garbage) before the layout is
|
||||||
|
updated.
|
||||||
|
|
||||||
|
|
||||||
## 1.4
|
## 1.4
|
||||||
|
|||||||
@@ -60,7 +60,6 @@ import com.sun.jna.platform.win32.WinDef.LRESULT;
|
|||||||
import com.sun.jna.platform.win32.WinDef.RECT;
|
import com.sun.jna.platform.win32.WinDef.RECT;
|
||||||
import com.sun.jna.platform.win32.WinDef.UINT_PTR;
|
import com.sun.jna.platform.win32.WinDef.UINT_PTR;
|
||||||
import com.sun.jna.platform.win32.WinDef.WPARAM;
|
import com.sun.jna.platform.win32.WinDef.WPARAM;
|
||||||
import com.sun.jna.platform.win32.WinNT.HANDLE;
|
|
||||||
import com.sun.jna.platform.win32.WinUser.HMONITOR;
|
import com.sun.jna.platform.win32.WinUser.HMONITOR;
|
||||||
import com.sun.jna.platform.win32.WinUser.WindowProc;
|
import com.sun.jna.platform.win32.WinUser.WindowProc;
|
||||||
import com.sun.jna.win32.W32APIOptions;
|
import com.sun.jna.win32.W32APIOptions;
|
||||||
@@ -291,6 +290,7 @@ public class FlatWindowsNativeWindowBorder
|
|||||||
private static final int GWLP_WNDPROC = -4;
|
private static final int GWLP_WNDPROC = -4;
|
||||||
|
|
||||||
private static final int
|
private static final int
|
||||||
|
WM_ERASEBKGND = 0x0014,
|
||||||
WM_NCCALCSIZE = 0x0083,
|
WM_NCCALCSIZE = 0x0083,
|
||||||
WM_NCHITTEST = 0x0084,
|
WM_NCHITTEST = 0x0084,
|
||||||
WM_NCRBUTTONUP = 0x00A5,
|
WM_NCRBUTTONUP = 0x00A5,
|
||||||
@@ -330,6 +330,7 @@ public class FlatWindowsNativeWindowBorder
|
|||||||
private final HWND hwnd;
|
private final HWND hwnd;
|
||||||
private final BaseTSD.LONG_PTR defaultWndProc;
|
private final BaseTSD.LONG_PTR defaultWndProc;
|
||||||
private int wmSizeWParam = -1;
|
private int wmSizeWParam = -1;
|
||||||
|
private HBRUSH background;
|
||||||
|
|
||||||
private int titleBarHeight;
|
private int titleBarHeight;
|
||||||
private Rectangle[] hitTestSpots;
|
private Rectangle[] hitTestSpots;
|
||||||
@@ -368,6 +369,8 @@ public class FlatWindowsNativeWindowBorder
|
|||||||
updateFrame( 0 );
|
updateFrame( 0 );
|
||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
|
if( background != null )
|
||||||
|
GDI32.INSTANCE.DeleteObject( background );
|
||||||
window = null;
|
window = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,13 +408,11 @@ public class FlatWindowsNativeWindowBorder
|
|||||||
|
|
||||||
private void setWindowBackground( int r, int g, int b ) {
|
private void setWindowBackground( int r, int g, int b ) {
|
||||||
// delete old background brush
|
// delete old background brush
|
||||||
ULONG_PTR oldBrush = User32.INSTANCE.GetClassLongPtr( hwnd, GCLP_HBRBACKGROUND );
|
if( background != null )
|
||||||
if( oldBrush != null && oldBrush.longValue() != 0 )
|
GDI32.INSTANCE.DeleteObject( background );
|
||||||
GDI32.INSTANCE.DeleteObject( new HANDLE( oldBrush.toPointer() ) );
|
|
||||||
|
|
||||||
// create new background brush
|
// create new background brush
|
||||||
HBRUSH brush = GDI32Ex.INSTANCE.CreateSolidBrush( RGB( r, g, b ) );
|
background = GDI32Ex.INSTANCE.CreateSolidBrush( RGB( r, g, b ) );
|
||||||
User32Ex.INSTANCE.SetClassLongPtr( hwnd, GCLP_HBRBACKGROUND, brush );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -440,6 +441,9 @@ public class FlatWindowsNativeWindowBorder
|
|||||||
wParam = new WPARAM( wmSizeWParam );
|
wParam = new WPARAM( wmSizeWParam );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case WM_ERASEBKGND:
|
||||||
|
return WmEraseBkgnd( hwnd, uMsg, wParam, lParam );
|
||||||
|
|
||||||
case WM_DESTROY:
|
case WM_DESTROY:
|
||||||
return WmDestroy( hwnd, uMsg, wParam, lParam );
|
return WmDestroy( hwnd, uMsg, wParam, lParam );
|
||||||
}
|
}
|
||||||
@@ -464,11 +468,30 @@ public class FlatWindowsNativeWindowBorder
|
|||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
windowsMap.remove( window );
|
windowsMap.remove( window );
|
||||||
|
if( background != null )
|
||||||
|
GDI32.INSTANCE.DeleteObject( background );
|
||||||
window = null;
|
window = null;
|
||||||
|
|
||||||
return lResult;
|
return lResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle WM_ERASEBKGND
|
||||||
|
*
|
||||||
|
* https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-erasebkgnd
|
||||||
|
*/
|
||||||
|
LRESULT WmEraseBkgnd( HWND hwnd, int uMsg, WPARAM wParam, LPARAM lParam ) {
|
||||||
|
if( background == null )
|
||||||
|
return new LRESULT( 0 );
|
||||||
|
|
||||||
|
// fill background
|
||||||
|
HDC hdc = new HDC( wParam.toPointer() );
|
||||||
|
RECT rect = new RECT();
|
||||||
|
User32.INSTANCE.GetClientRect( hwnd, rect );
|
||||||
|
User32Ex.INSTANCE.FillRect( hdc, rect, background );
|
||||||
|
return new LRESULT( 1 );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle WM_NCCALCSIZE
|
* Handle WM_NCCALCSIZE
|
||||||
*
|
*
|
||||||
@@ -729,7 +752,7 @@ public class FlatWindowsNativeWindowBorder
|
|||||||
LONG_PTR SetWindowLong( HWND hWnd, int nIndex, LONG_PTR wndProc );
|
LONG_PTR SetWindowLong( HWND hWnd, int nIndex, LONG_PTR wndProc );
|
||||||
LRESULT CallWindowProc( LONG_PTR lpPrevWndFunc, HWND hWnd, int uMsg, WPARAM wParam, LPARAM lParam );
|
LRESULT CallWindowProc( LONG_PTR lpPrevWndFunc, HWND hWnd, int uMsg, WPARAM wParam, LPARAM lParam );
|
||||||
|
|
||||||
LONG_PTR SetClassLongPtr( HWND hWnd, int nIndex, HANDLE wndProc );
|
int FillRect( HDC hDC, RECT lprc, HBRUSH hbr );
|
||||||
|
|
||||||
int GetDpiForWindow( HWND hwnd );
|
int GetDpiForWindow( HWND hwnd );
|
||||||
int GetSystemMetricsForDpi( int nIndex, int dpi );
|
int GetSystemMetricsForDpi( int nIndex, int dpi );
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ FlatWndProc::FlatWndProc() {
|
|||||||
hwnd = NULL;
|
hwnd = NULL;
|
||||||
defaultWndProc = NULL;
|
defaultWndProc = NULL;
|
||||||
wmSizeWParam = -1;
|
wmSizeWParam = -1;
|
||||||
|
background = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
HWND FlatWndProc::install( JNIEnv *env, jobject obj, jobject window ) {
|
HWND FlatWndProc::install( JNIEnv *env, jobject obj, jobject window ) {
|
||||||
@@ -135,6 +136,8 @@ void FlatWndProc::uninstall( JNIEnv *env, jobject obj, HWND hwnd ) {
|
|||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
env->DeleteGlobalRef( fwp->obj );
|
env->DeleteGlobalRef( fwp->obj );
|
||||||
|
if( fwp->background != NULL )
|
||||||
|
::DeleteObject( fwp->background );
|
||||||
delete fwp;
|
delete fwp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,14 +185,16 @@ void FlatWndProc::updateFrame( HWND hwnd, int state ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FlatWndProc::setWindowBackground( HWND hwnd, int r, int g, int b ) {
|
void FlatWndProc::setWindowBackground( HWND hwnd, int r, int g, int b ) {
|
||||||
|
FlatWndProc* fwp = (FlatWndProc*) hwndMap->get( hwnd );
|
||||||
|
if( fwp == NULL )
|
||||||
|
return;
|
||||||
|
|
||||||
// delete old background brush
|
// delete old background brush
|
||||||
HBRUSH oldBrush = (HBRUSH) ::GetClassLongPtr( hwnd, GCLP_HBRBACKGROUND );
|
if( fwp->background != NULL )
|
||||||
if( oldBrush != NULL )
|
::DeleteObject( fwp->background );
|
||||||
::DeleteObject( oldBrush );
|
|
||||||
|
|
||||||
// create new background brush
|
// create new background brush
|
||||||
HBRUSH brush = ::CreateSolidBrush( RGB( r, g, b ) );
|
fwp->background = ::CreateSolidBrush( RGB( r, g, b ) );
|
||||||
::SetClassLongPtr( hwnd, GCLP_HBRBACKGROUND, (LONG_PTR) brush );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT CALLBACK FlatWndProc::StaticWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {
|
LRESULT CALLBACK FlatWndProc::StaticWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {
|
||||||
@@ -224,12 +229,16 @@ LRESULT CALLBACK FlatWndProc::WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, L
|
|||||||
wParam = wmSizeWParam;
|
wParam = wmSizeWParam;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case WM_ERASEBKGND:
|
||||||
|
return WmEraseBkgnd( hwnd, uMsg, wParam, lParam );
|
||||||
|
|
||||||
case WM_DESTROY:
|
case WM_DESTROY:
|
||||||
return WmDestroy( hwnd, uMsg, wParam, lParam );
|
return WmDestroy( hwnd, uMsg, wParam, lParam );
|
||||||
}
|
}
|
||||||
|
|
||||||
return ::CallWindowProc( defaultWndProc, hwnd, uMsg, wParam, lParam );
|
return ::CallWindowProc( defaultWndProc, hwnd, uMsg, wParam, lParam );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle WM_DESTROY
|
* Handle WM_DESTROY
|
||||||
*
|
*
|
||||||
@@ -243,6 +252,8 @@ LRESULT FlatWndProc::WmDestroy( HWND hwnd, int uMsg, WPARAM wParam, LPARAM lPara
|
|||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
getEnv()->DeleteGlobalRef( obj );
|
getEnv()->DeleteGlobalRef( obj );
|
||||||
|
if( background != NULL )
|
||||||
|
::DeleteObject( background );
|
||||||
hwndMap->remove( hwnd );
|
hwndMap->remove( hwnd );
|
||||||
delete this;
|
delete this;
|
||||||
|
|
||||||
@@ -250,6 +261,23 @@ LRESULT FlatWndProc::WmDestroy( HWND hwnd, int uMsg, WPARAM wParam, LPARAM lPara
|
|||||||
return ::CallWindowProc( defaultWndProc2, hwnd, uMsg, wParam, lParam );
|
return ::CallWindowProc( defaultWndProc2, hwnd, uMsg, wParam, lParam );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle WM_ERASEBKGND
|
||||||
|
*
|
||||||
|
* https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-erasebkgnd
|
||||||
|
*/
|
||||||
|
LRESULT FlatWndProc::WmEraseBkgnd( HWND hwnd, int uMsg, WPARAM wParam, LPARAM lParam ) {
|
||||||
|
if( background == NULL )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
// fill background
|
||||||
|
HDC hdc = (HDC) wParam;
|
||||||
|
RECT rect;
|
||||||
|
::GetClientRect( hwnd, &rect );
|
||||||
|
::FillRect( hdc, &rect, background );
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle WM_NCCALCSIZE
|
* Handle WM_NCCALCSIZE
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ private:
|
|||||||
HWND hwnd;
|
HWND hwnd;
|
||||||
WNDPROC defaultWndProc;
|
WNDPROC defaultWndProc;
|
||||||
int wmSizeWParam;
|
int wmSizeWParam;
|
||||||
|
HBRUSH background;
|
||||||
|
|
||||||
FlatWndProc();
|
FlatWndProc();
|
||||||
static void initIDs( JNIEnv *env, jobject obj );
|
static void initIDs( JNIEnv *env, jobject obj );
|
||||||
@@ -49,6 +50,7 @@ private:
|
|||||||
static LRESULT CALLBACK StaticWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
|
static LRESULT CALLBACK StaticWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
|
||||||
LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
|
LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
|
||||||
LRESULT WmDestroy( HWND hwnd, int uMsg, WPARAM wParam, LPARAM lParam );
|
LRESULT WmDestroy( HWND hwnd, int uMsg, WPARAM wParam, LPARAM lParam );
|
||||||
|
LRESULT WmEraseBkgnd( HWND hwnd, int uMsg, WPARAM wParam, LPARAM lParam );
|
||||||
LRESULT WmNcCalcSize( HWND hwnd, int uMsg, WPARAM wParam, LPARAM lParam );
|
LRESULT WmNcCalcSize( HWND hwnd, int uMsg, WPARAM wParam, LPARAM lParam );
|
||||||
LRESULT WmNcHitTest( HWND hwnd, int uMsg, WPARAM wParam, LPARAM lParam );
|
LRESULT WmNcHitTest( HWND hwnd, int uMsg, WPARAM wParam, LPARAM lParam );
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user