mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2025-12-06 05:50:53 +03:00
Native window decorations: avoid using C-runtime, which reduces the DLL size from 100kb to 8kb
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -9,3 +9,5 @@ out/
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.vs/
|
||||
.vscode/
|
||||
|
||||
@@ -55,7 +55,7 @@ library {
|
||||
compilerArgs.addAll( toolChain.map {
|
||||
when( it ) {
|
||||
is Gcc, is Clang -> listOf( "-O2" )
|
||||
is VisualCpp -> listOf( "/O2" )
|
||||
is VisualCpp -> listOf( "/O2", "/Zl", "/GS-" )
|
||||
else -> emptyList()
|
||||
}
|
||||
} )
|
||||
@@ -70,8 +70,8 @@ library {
|
||||
val jawt = "${org.gradle.internal.jvm.Jvm.current().javaHome}/lib/jawt"
|
||||
linkerArgs.addAll( toolChain.map {
|
||||
when( it ) {
|
||||
is Gcc, is Clang -> listOf( "-l${jawt}", "-lUser32", "-lshell32", "-lAdvAPI32" )
|
||||
is VisualCpp -> listOf( "${jawt}.lib", "User32.lib", "shell32.lib", "AdvAPI32.lib" )
|
||||
is Gcc, is Clang -> listOf( "-l${jawt}", "-lUser32", "-lshell32", "-lAdvAPI32", "-lKernel32" )
|
||||
is VisualCpp -> listOf( "${jawt}.lib", "User32.lib", "shell32.lib", "AdvAPI32.lib", "Kernel32.lib", "/NODEFAULTLIB" )
|
||||
else -> emptyList()
|
||||
}
|
||||
} )
|
||||
|
||||
@@ -14,12 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// avoid inlining of printf()
|
||||
#define _NO_CRT_STDIO_INLINE
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <shellapi.h>
|
||||
#include <jawt.h>
|
||||
#include <jawt_md.h>
|
||||
#include <map>
|
||||
#include "FlatWndProc.h"
|
||||
#include "com_formdev_flatlaf_ui_FlatWindowsNativeWindowBorder_WndProc.h"
|
||||
|
||||
@@ -50,7 +52,7 @@ jmethodID FlatWndProc::onNcHitTestMID;
|
||||
jmethodID FlatWndProc::isFullscreenMID;
|
||||
jmethodID FlatWndProc::fireStateChangedLaterOnceMID;
|
||||
|
||||
std::map<HWND, FlatWndProc*> FlatWndProc::hwndMap = std::map<HWND, FlatWndProc*>();
|
||||
HWNDMap* FlatWndProc::hwndMap;
|
||||
|
||||
//---- class FlatWndProc methods ----------------------------------------------
|
||||
|
||||
@@ -63,21 +65,25 @@ FlatWndProc::FlatWndProc() {
|
||||
}
|
||||
|
||||
HWND FlatWndProc::install( JNIEnv *env, jobject obj, jobject window ) {
|
||||
initIDs( env, obj );
|
||||
initIDs( env, obj );
|
||||
|
||||
if( initialized < 0 )
|
||||
return 0;
|
||||
if( initialized < 0 )
|
||||
return 0;
|
||||
|
||||
// create HWND map
|
||||
if( hwndMap == NULL )
|
||||
hwndMap = new HWNDMap();
|
||||
|
||||
// get window handle
|
||||
HWND hwnd = getWindowHandle( env, window );
|
||||
if( hwnd == NULL || hwndMap.count( hwnd ) > 0 )
|
||||
if( hwnd == NULL || hwndMap->get( hwnd ) != NULL )
|
||||
return 0;
|
||||
|
||||
FlatWndProc* fwp = new FlatWndProc();
|
||||
env->GetJavaVM( &fwp->jvm );
|
||||
fwp->obj = env->NewGlobalRef( obj );
|
||||
fwp->hwnd = hwnd;
|
||||
hwndMap[hwnd] = fwp;
|
||||
hwndMap->put( hwnd, fwp );
|
||||
|
||||
// replace window procedure
|
||||
fwp->defaultWndProc = reinterpret_cast<WNDPROC>(
|
||||
@@ -90,11 +96,14 @@ HWND FlatWndProc::install( JNIEnv *env, jobject obj, jobject window ) {
|
||||
}
|
||||
|
||||
void FlatWndProc::uninstall( JNIEnv *env, jobject obj, HWND hwnd ) {
|
||||
if( hwnd == NULL || hwndMap.count( hwnd ) == 0 )
|
||||
return;
|
||||
if( hwnd == NULL )
|
||||
return;
|
||||
|
||||
FlatWndProc* fwp = hwndMap[hwnd];
|
||||
hwndMap.erase( hwnd );
|
||||
FlatWndProc* fwp = (FlatWndProc*) hwndMap->get( hwnd );
|
||||
if( fwp == NULL )
|
||||
return;
|
||||
|
||||
hwndMap->remove( hwnd );
|
||||
|
||||
// restore original window procedure
|
||||
::SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG_PTR) fwp->defaultWndProc );
|
||||
@@ -132,7 +141,7 @@ void FlatWndProc::updateFrame() {
|
||||
}
|
||||
|
||||
LRESULT CALLBACK FlatWndProc::StaticWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {
|
||||
FlatWndProc* fwp = hwndMap[hwnd];
|
||||
FlatWndProc* fwp = (FlatWndProc*) hwndMap->get( hwnd );
|
||||
return fwp->WindowProc( hwnd, uMsg, wParam, lParam );
|
||||
}
|
||||
|
||||
@@ -175,7 +184,7 @@ LRESULT FlatWndProc::WmDestroy( HWND hwnd, int uMsg, WPARAM wParam, LPARAM lPara
|
||||
|
||||
// cleanup
|
||||
getEnv()->DeleteGlobalRef( obj );
|
||||
hwndMap.erase( hwnd );
|
||||
hwndMap->remove( hwnd );
|
||||
delete this;
|
||||
|
||||
// call original AWT window procedure because it may fire window closed event in AwtWindow::WmDestroy()
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include "HWNDMap.h"
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
@@ -31,7 +32,7 @@ private:
|
||||
static jmethodID isFullscreenMID;
|
||||
static jmethodID fireStateChangedLaterOnceMID;
|
||||
|
||||
static std::map<HWND, FlatWndProc*> hwndMap;
|
||||
static HWNDMap* hwndMap;
|
||||
|
||||
JavaVM* jvm;
|
||||
JNIEnv* env; // attached to AWT-Windows/Win32 thread
|
||||
|
||||
153
flatlaf-natives/flatlaf-natives-windows/src/main/cpp/HWNDMap.cpp
Normal file
153
flatlaf-natives/flatlaf-natives-windows/src/main/cpp/HWNDMap.cpp
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright 2021 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// avoid inlining of printf()
|
||||
#define _NO_CRT_STDIO_INLINE
|
||||
|
||||
#include <stdio.h>
|
||||
#include "HWNDMap.h"
|
||||
|
||||
#define DEFAULT_CAPACITY 20
|
||||
#define INCREASE_CAPACITY 10
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
|
||||
class LOCK {
|
||||
LPCRITICAL_SECTION lpCriticalSection;
|
||||
|
||||
public:
|
||||
LOCK( LPCRITICAL_SECTION lpCriticalSection ) {
|
||||
this->lpCriticalSection = lpCriticalSection;
|
||||
::EnterCriticalSection( lpCriticalSection );
|
||||
}
|
||||
~LOCK() {
|
||||
::LeaveCriticalSection( lpCriticalSection );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
HWNDMap::HWNDMap() {
|
||||
size = 0;
|
||||
capacity = DEFAULT_CAPACITY;
|
||||
table = new Entry[capacity];
|
||||
|
||||
::InitializeCriticalSection( &criticalSection );
|
||||
|
||||
// dump( "<init>" );
|
||||
}
|
||||
|
||||
LPVOID HWNDMap::get( HWND key ) {
|
||||
LOCK lock( &criticalSection );
|
||||
|
||||
int index = binarySearch( key );
|
||||
return (index >= 0) ? table[index].value : NULL;
|
||||
}
|
||||
|
||||
void HWNDMap::put( HWND key, LPVOID value ) {
|
||||
LOCK lock( &criticalSection );
|
||||
|
||||
int index = binarySearch( key );
|
||||
// printf( "put %p %p = %d --\n", key, value, index );
|
||||
if( index >= 0 ) {
|
||||
// key already in map --> replace
|
||||
table[index].value = value;
|
||||
} else {
|
||||
// insert new key
|
||||
ensureCapacity( size + 1 );
|
||||
|
||||
// make roor for new entry
|
||||
index = -(index + 1);
|
||||
for( int i = size - 1; i >= index; i-- )
|
||||
table[i + 1] = table[i];
|
||||
size++;
|
||||
|
||||
// insert entry
|
||||
table[index].key = key;
|
||||
table[index].value = value;
|
||||
}
|
||||
|
||||
// dump( "put" );
|
||||
}
|
||||
|
||||
void HWNDMap::remove( HWND key ) {
|
||||
LOCK lock( &criticalSection );
|
||||
|
||||
// search for key
|
||||
int index = binarySearch( key );
|
||||
// printf( "remove %p = %d --\n", key, index );
|
||||
if( index < 0 )
|
||||
return;
|
||||
|
||||
// remove entry
|
||||
for( int i = index + 1; i < size; i++ )
|
||||
table[i - 1] = table[i];
|
||||
size--;
|
||||
|
||||
// dump( "remove" );
|
||||
}
|
||||
|
||||
int HWNDMap::binarySearch( HWND key ) {
|
||||
int low = 0;
|
||||
int high = size - 1;
|
||||
|
||||
while( low <= high ) {
|
||||
int mid = (low + high) >> 1;
|
||||
|
||||
HWND midKey = table[mid].key;
|
||||
int cmp = midKey - key;
|
||||
if( cmp < 0 )
|
||||
low = mid + 1;
|
||||
else if( cmp > 0 )
|
||||
high = mid - 1;
|
||||
else
|
||||
return mid;
|
||||
}
|
||||
|
||||
return -(low + 1);
|
||||
}
|
||||
|
||||
void HWNDMap::ensureCapacity( int minCapacity ) {
|
||||
if( minCapacity <= capacity )
|
||||
return;
|
||||
|
||||
// allocate new table
|
||||
int newCapacity = minCapacity + INCREASE_CAPACITY;
|
||||
Entry* newTable = new Entry[newCapacity];
|
||||
|
||||
// copy old table to new table
|
||||
for( int i = 0; i < capacity; i++ )
|
||||
newTable[i] = table[i];
|
||||
|
||||
// delete old table
|
||||
delete table;
|
||||
|
||||
table = newTable;
|
||||
capacity = newCapacity;
|
||||
}
|
||||
|
||||
/*
|
||||
void HWNDMap::dump( char* msg ) {
|
||||
printf( "---- %s -----------------------\n", msg );
|
||||
printf( "size %d\n", size );
|
||||
printf( "capacity %d\n", capacity );
|
||||
printf( "table %p\n", table );
|
||||
|
||||
for( int i = 0; i < capacity; i++ )
|
||||
printf( " %d: %p - %p %s\n", i, table[i].key, table[i].value, i >= size ? "UNUSED" : "" );
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2021 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
/**
|
||||
* A simple map that uses a sorted array to store key/value pairs.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
|
||||
struct Entry
|
||||
{
|
||||
HWND key;
|
||||
LPVOID value;
|
||||
};
|
||||
|
||||
class HWNDMap
|
||||
{
|
||||
private:
|
||||
int size; // used entries in table
|
||||
int capacity; // total size of table
|
||||
Entry* table;
|
||||
|
||||
// used to synchronize to make it thread safe
|
||||
CRITICAL_SECTION criticalSection;
|
||||
|
||||
public:
|
||||
HWNDMap();
|
||||
|
||||
LPVOID get( HWND key );
|
||||
void put( HWND key, LPVOID value );
|
||||
void remove( HWND key );
|
||||
|
||||
private:
|
||||
int binarySearch( HWND key );
|
||||
void ensureCapacity( int newCapacity );
|
||||
|
||||
// void dump( char* msg );
|
||||
};
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2021 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// avoid inlining of printf()
|
||||
#define _NO_CRT_STDIO_INLINE
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/**
|
||||
* Methods that replace C-runtime methods and allow linking/running without C-runtime.
|
||||
*
|
||||
* WARNING: Constructors/destructors of static objects are not invoked!
|
||||
*
|
||||
* https://documentation.help/Far-Manager/msdnmag-issues-01-01-hood-default.aspx.html
|
||||
* www.catch22.net/tuts/win32/reducing-executable-size#the-c-runtime-and-default-libraries
|
||||
* https://www.mvps.org/user32/nocrt.html
|
||||
*
|
||||
* see also LIBCTINY on "Downloads" page here: http://www.wheaty.net/
|
||||
* or https://github.com/leepa/libctiny
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
|
||||
extern "C"
|
||||
BOOL WINAPI _DllMainCRTStartup( HINSTANCE instance, DWORD reason, LPVOID reserved ) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void* __cdecl operator new( size_t cb ) {
|
||||
return ::HeapAlloc( ::GetProcessHeap(), HEAP_ZERO_MEMORY, cb );
|
||||
}
|
||||
|
||||
void* __cdecl operator new[]( size_t cb ) {
|
||||
return ::HeapAlloc( ::GetProcessHeap(), HEAP_ZERO_MEMORY, cb );
|
||||
}
|
||||
|
||||
void __cdecl operator delete( void* pv, size_t cb ) {
|
||||
if( pv != NULL )
|
||||
::HeapFree( ::GetProcessHeap(), 0, pv );
|
||||
}
|
||||
|
||||
/*
|
||||
extern "C"
|
||||
int __cdecl printf( const char* format, ... ) {
|
||||
char szBuff[1024];
|
||||
int retValue;
|
||||
DWORD cbWritten;
|
||||
va_list argptr;
|
||||
|
||||
va_start( argptr, format );
|
||||
retValue = wvsprintfA( szBuff, format, argptr );
|
||||
va_end( argptr );
|
||||
|
||||
WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), szBuff, retValue, &cbWritten, NULL );
|
||||
|
||||
return retValue;
|
||||
}
|
||||
*/
|
||||
Reference in New Issue
Block a user