diff --git a/.gitignore b/.gitignore index 547c1411..da83460c 100644 --- a/.gitignore +++ b/.gitignore @@ -49,6 +49,10 @@ bin/ # maven target/ +# gradle +/build +/.gradle + # Python venv/ diff --git a/build.gradle b/build.gradle new file mode 100644 index 00000000..7ca9e38f --- /dev/null +++ b/build.gradle @@ -0,0 +1,111 @@ +import org.gradle.internal.jvm.Jvm + +plugins { + id 'java' + id 'maven-publish' + id 'idea' + id 'cpp' +} + +repositories { + mavenLocal() + mavenCentral() + maven { + url = 'http://repo.maven.apache.org/maven2' + } +} + +dependencies { + compile 'darcula:darcula.laf:1.0.0' + compile 'com.metsci.ext.com.kitfox.svg:svg-salamander:[0.1.19,)' + compile 'org.jetbrains:annotations:16.0.1' + compile 'org.jetbrains.kotlin:kotlin-compiler:1.3.21' + compile 'org.swinglabs:swingx:1.6.1' + testCompileOnly 'org.swinglabs:swingx:1.6.1' + testCompile 'junit:junit:4.12' +} + +group = 'com.weis' +version = '1.0-SNAPSHOT' + +compileJava { + sourceCompatibility = 11 + targetCompatibility = 11 +} + +test { + dependsOn 'jniplatformSharedLibrary' + systemProperty "java.library.path", file("${buildDir}/libs/jniplatform/shared").absolutePath + '\\' +} + +println "Building on OS: " + System.properties['os.name'] +println "Using JDK: " + System.properties['java.home'] + +model { + platforms { + x86 { + architecture 'x86' + } + x64 { + architecture 'x86_64' + } + } +} + +model { + components { + jniplatform(NativeLibrarySpec) { +// targetPlatform "x86" + targetPlatform "x64" + binaries.all { + if (targetPlatform.operatingSystem.macOsX) { + cppCompiler.args '-I', "${Jvm.current().javaHome}/include" + cppCompiler.args '-I', "${Jvm.current().javaHome}/include/darwin" + cppCompiler.args '-mmacosx-version-min=10.4' + linker.args '-mmacosx-version-min=10.4' + } else if (targetPlatform.operatingSystem.linux) { + cppCompiler.args '-I', "${Jvm.current().javaHome}/include" + cppCompiler.args '-I', "${Jvm.current().javaHome}/include/linux" + cppCompiler.args '-D_FILE_OFFSET_BITS=64' + } else if (targetPlatform.operatingSystem.windows) { + cppCompiler.args "-I${Jvm.current().javaHome}/include" + cppCompiler.args "-I${Jvm.current().javaHome}/include/win32" + cppCompiler.args "-std=c++11" + linker.args "-ldwmapi" + linker.args "-lGdi32" + } else if (targetPlatform.operatingSystem.freeBSD) { + cppCompiler.args '-I', "${Jvm.current().javaHome}/include" + cppCompiler.args '-I', "${Jvm.current().javaHome}/include/freebsd" + } + } + } + } +} + +publishing { + publications { + maven(MavenPublication) { + from(components.java) + } + } +} + + +tasks.withType(JavaCompile) { + configure(options) { + options.encoding = 'UTF-8' + options.compilerArgs += [ + '-h', file("${projectDir}/src/jniplatform/cpp"), + ] + options.compilerArgs += [ + '--add-exports=java.desktop/sun.awt=ALL-UNNAMED', + '--add-exports=java.desktop/com.sun.java.swing=ALL-UNNAMED', + '--add-exports=java.desktop/sun.swing=ALL-UNNAMED' + ] + } +} + +tasks.withType(JavaExec) { + dependsOn 'jniplatformSharedLibrary' + systemProperty "java.library.path", file("${buildDir}/libs/jniplatform/shared").absolutePath + '\\' +} diff --git a/darklaf.iml b/darklaf.iml new file mode 100644 index 00000000..674dd783 --- /dev/null +++ b/darklaf.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..5c2d1cf0 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..e4fbbbcf --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue Oct 01 16:12:24 CEST 2019 +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew new file mode 100644 index 00000000..83f2acfd --- /dev/null +++ b/gradlew @@ -0,0 +1,188 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# 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. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 00000000..9618d8d9 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,100 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 00000000..65956fd8 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,5 @@ +/* + * This file was generated by the Gradle 'init' task. + */ + +rootProject.name = 'darklaf' diff --git a/src/jniplatform/cpp/JNIDecorations.cpp b/src/jniplatform/cpp/JNIDecorations.cpp new file mode 100644 index 00000000..13ae6eb3 --- /dev/null +++ b/src/jniplatform/cpp/JNIDecorations.cpp @@ -0,0 +1,184 @@ +#include "JNIDecorations.h"; +#include "com_weis_darklaf_platform_windows_JNIDecorations.h" +#include +#include +#include +#include + +#define GWL_WNDPROC -4 + +std::map wrapper_map = std::map(); + +LRESULT HitTestNCA(HWND hWnd, WPARAM wParam, LPARAM lParam, WindowWrapper *wrapper) +{ + // Get the point coordinates for the hit test. + POINT ptMouse = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; + + // Get the window rectangle. + RECT rcWindow; + GetWindowRect(hWnd, &rcWindow); + + // Determine if the hit test is for resizing. Default middle (1,1). + USHORT uRow = 1; + USHORT uCol = 1; + + // Determine if the point is at the top or bottom of the window. + if (ptMouse.y >= rcWindow.top && ptMouse.y < rcWindow.top + 5) + { + uRow = 0; + } + else if (ptMouse.y < rcWindow.bottom && ptMouse.y >= rcWindow.bottom - 5) + { + uRow = 2; + } + + // Determine if the point is at the left or right of the window. + if (ptMouse.x >= rcWindow.left && ptMouse.x < rcWindow.left + 5) + { + uCol = 0; // left side + } + else if (ptMouse.x < rcWindow.right && ptMouse.x >= rcWindow.right - 5) + { + uCol = 2; // right side + } + + // Hit test (HTTOPLEFT, ... HTBOTTOMRIGHT) + LRESULT hitTests[3][3] = + { + {HTTOPLEFT, HTTOP, HTTOPRIGHT}, + {HTLEFT, HTNOWHERE, HTRIGHT}, + {HTBOTTOMLEFT, HTBOTTOM, HTBOTTOMRIGHT}, + }; + LRESULT hit = hitTests[uRow][uCol]; + if (hit == HTNOWHERE || !wrapper->resizable) + { + //Handle window drag. + if (ptMouse.y < rcWindow.top + wrapper->height && ptMouse.x >= rcWindow.left + wrapper->left && ptMouse.x <= rcWindow.right - wrapper->right) + { + return HTCAPTION; + } + return HTCLIENT; + } + else + { + return hit; + } +} + +LRESULT CALLBACK WindowWrapper::WindowProc(_In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam) +{ + HWND handle = reinterpret_cast(hwnd); + auto wrapper = wrapper_map[handle]; + if (uMsg == WM_NCCALCSIZE) + { + if (wParam == TRUE) + { + SetWindowLong(hwnd, 0, 0); + return TRUE; + } + return FALSE; + } + else if (uMsg == WM_NCHITTEST) + { + return HitTestNCA(hwnd, wParam, lParam, wrapper); + } + else if (uMsg == WM_PAINT) + { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hwnd, &ps); + + RECT rc = ps.rcPaint; + FillRect(hdc, &rc, CreateSolidBrush(wrapper->background)); + EndPaint(hwnd, &ps); + } + return CallWindowProc(wrapper->prev_proc, hwnd, uMsg, wParam, lParam); +} + +JNIEXPORT void JNICALL +Java_com_weis_darklaf_platform_windows_JNIDecorations_setResizable(JNIEnv *env, jclass obj, jlong hwnd, jboolean res) +{ + HWND handle = reinterpret_cast(hwnd); + auto wrap = wrapper_map[handle]; + if (wrap) + { + wrap->resizable = res; + } +} + +JNIEXPORT void JNICALL +Java_com_weis_darklaf_platform_windows_JNIDecorations_updateValues(JNIEnv *env, jclass obj, jlong hwnd, + jint l, jint r, jint h) +{ + HWND handle = reinterpret_cast(hwnd); + auto wrap = wrapper_map[handle]; + if (wrap) + { + wrap->left = l; + wrap->right = r; + wrap->height = h; + } +} + +JNIEXPORT void JNICALL +Java_com_weis_darklaf_platform_windows_JNIDecorations_setBackground(JNIEnv *env, jclass obj, jlong hwnd, jint r, jint g, jint b) +{ + HWND handle = reinterpret_cast(hwnd); + auto wrap = wrapper_map[handle]; + if (wrap) + { + wrap->background = RGB(r, g, b); + } +} + +JNIEXPORT void JNICALL +Java_com_weis_darklaf_platform_windows_JNIDecorations_installDecorations(JNIEnv *env, jclass obj, jlong hwnd) +{ + HWND handle = reinterpret_cast(hwnd); + + MARGINS margins = {0, 0, 0, 1}; + DwmExtendFrameIntoClientArea(handle, &margins); + SetWindowPos(handle, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); + WNDPROC proc = reinterpret_cast(GetWindowLongPtr(handle, GWL_WNDPROC)); + + WindowWrapper *wrapper = new WindowWrapper(); + wrapper->prev_proc = proc; + wrapper_map[handle] = wrapper; + + SetWindowLongPtr((HWND)hwnd, GWL_WNDPROC, (LONG_PTR)WindowWrapper::WindowProc); +} + +JNIEXPORT void JNICALL +Java_com_weis_darklaf_platform_windows_JNIDecorations_uninstallDecorations(JNIEnv *env, jclass obj, jlong hwnd) +{ + HWND handle = reinterpret_cast(hwnd); + auto wrap = wrapper_map[handle]; + if (wrap) + { + SetWindowLongPtr((HWND)hwnd, GWL_WNDPROC, reinterpret_cast(wrap->prev_proc)); + wrapper_map.erase(handle); + delete (wrap); + } +} + +//Window functions. + +JNIEXPORT void JNICALL +Java_com_weis_darklaf_platform_windows_JNIDecorations_minimize(JNIEnv *env, jclass obj, jlong hwnd) +{ + HWND handle = reinterpret_cast(hwnd); + ShowWindow(handle, SW_MINIMIZE); +} + +JNIEXPORT void JNICALL +Java_com_weis_darklaf_platform_windows_JNIDecorations_maximize(JNIEnv *env, jclass obj, jlong hwnd) +{ + HWND handle = reinterpret_cast(hwnd); + ShowWindow(handle, SW_MAXIMIZE); +} + +JNIEXPORT void JNICALL +Java_com_weis_darklaf_platform_windows_JNIDecorations_restore(JNIEnv *env, jclass obj, jlong hwnd) +{ + HWND handle = reinterpret_cast(hwnd); + ShowWindow(handle, SW_RESTORE); +} diff --git a/src/jniplatform/cpp/JNIDecorations.h b/src/jniplatform/cpp/JNIDecorations.h new file mode 100644 index 00000000..aeaa3f9f --- /dev/null +++ b/src/jniplatform/cpp/JNIDecorations.h @@ -0,0 +1,17 @@ +#include +#include +#include + +class WindowWrapper +{ +public: + bool resizable = true; + WNDPROC prev_proc; + COLORREF background = RGB(255, 255, 255); + + int left = 0; + int right = 0; + int height = 0; + + static LRESULT CALLBACK WindowProc(_In_ HWND hwnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam); +}; \ No newline at end of file diff --git a/src/jniplatform/cpp/com_weis_darklaf_platform_windows_JNIDecorations.h b/src/jniplatform/cpp/com_weis_darklaf_platform_windows_JNIDecorations.h new file mode 100644 index 00000000..5ec6dc86 --- /dev/null +++ b/src/jniplatform/cpp/com_weis_darklaf_platform_windows_JNIDecorations.h @@ -0,0 +1,77 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_weis_darklaf_platform_windows_JNIDecorations */ + +#ifndef _Included_com_weis_darklaf_platform_windows_JNIDecorations +#define _Included_com_weis_darklaf_platform_windows_JNIDecorations +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: com_weis_darklaf_platform_windows_JNIDecorations + * Method: updateValues + * Signature: (JIII)V + */ +JNIEXPORT void JNICALL Java_com_weis_darklaf_platform_windows_JNIDecorations_updateValues + (JNIEnv *, jclass, jlong, jint, jint, jint); + +/* + * Class: com_weis_darklaf_platform_windows_JNIDecorations + * Method: setResizable + * Signature: (JZ)V + */ +JNIEXPORT void JNICALL Java_com_weis_darklaf_platform_windows_JNIDecorations_setResizable + (JNIEnv *, jclass, jlong, jboolean); + +/* + * Class: com_weis_darklaf_platform_windows_JNIDecorations + * Method: setBackground + * Signature: (JIII)V + */ +JNIEXPORT void JNICALL Java_com_weis_darklaf_platform_windows_JNIDecorations_setBackground + (JNIEnv *, jclass, jlong, jint, jint, jint); + +/* + * Class: com_weis_darklaf_platform_windows_JNIDecorations + * Method: minimize + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_com_weis_darklaf_platform_windows_JNIDecorations_minimize + (JNIEnv *, jclass, jlong); + +/* + * Class: com_weis_darklaf_platform_windows_JNIDecorations + * Method: maximize + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_com_weis_darklaf_platform_windows_JNIDecorations_maximize + (JNIEnv *, jclass, jlong); + +/* + * Class: com_weis_darklaf_platform_windows_JNIDecorations + * Method: restore + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_com_weis_darklaf_platform_windows_JNIDecorations_restore + (JNIEnv *, jclass, jlong); + +/* + * Class: com_weis_darklaf_platform_windows_JNIDecorations + * Method: installDecorations + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_com_weis_darklaf_platform_windows_JNIDecorations_installDecorations + (JNIEnv *, jclass, jlong); + +/* + * Class: com_weis_darklaf_platform_windows_JNIDecorations + * Method: uninstallDecorations + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_com_weis_darklaf_platform_windows_JNIDecorations_uninstallDecorations + (JNIEnv *, jclass, jlong); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/main/java/com/weis/darklaf/components/ColorPipetteBase.java b/src/main/java/com/weis/darklaf/components/ColorPipetteBase.java index 416866ac..aa923186 100644 --- a/src/main/java/com/weis/darklaf/components/ColorPipetteBase.java +++ b/src/main/java/com/weis/darklaf/components/ColorPipetteBase.java @@ -1,7 +1,6 @@ package com.weis.darklaf.components; import com.bulenkov.iconloader.util.SystemInfo; -import com.weis.darklaf.platform.windows.WindowsFrameUtil; import com.weis.darklaf.ui.colorchooser.ColorListener; import com.weis.darklaf.ui.colorchooser.ColorPipette; import com.weis.darklaf.util.DarkUIUtil; @@ -202,9 +201,6 @@ public abstract class ColorPipetteBase implements ColorPipette, AWTEventListener closeAction.run(); } Toolkit.getDefaultToolkit().removeAWTEventListener(this); - if (SystemInfo.isWindows) { - WindowsFrameUtil.User32dll.INSTANCE.ShowCursor(true); - } } @Override diff --git a/src/main/java/com/weis/darklaf/components/border/TextBubbleBorder.java b/src/main/java/com/weis/darklaf/components/border/TextBubbleBorder.java index 65a5217a..d35cb9a2 100644 --- a/src/main/java/com/weis/darklaf/components/border/TextBubbleBorder.java +++ b/src/main/java/com/weis/darklaf/components/border/TextBubbleBorder.java @@ -304,7 +304,7 @@ public class TextBubbleBorder extends AbstractBorder { } @Contract("_, _, _, _ -> new") - public RoundRectangle2D.@NotNull Double calculateBubbleRect(final int x, final int y, + public RoundRectangle2D.Double calculateBubbleRect(final int x, final int y, final int width, final int height) { return new RoundRectangle2D.Double(x + insets.left, y + insets.top, width - insets.left - insets.right, height - insets.top - insets.bottom, radius, radius); diff --git a/src/main/java/com/weis/darklaf/platform/windows/JNIDecorations.java b/src/main/java/com/weis/darklaf/platform/windows/JNIDecorations.java new file mode 100644 index 00000000..f5faa2c1 --- /dev/null +++ b/src/main/java/com/weis/darklaf/platform/windows/JNIDecorations.java @@ -0,0 +1,36 @@ +package com.weis.darklaf.platform.windows; + +import com.sun.jna.Native; +import com.sun.jna.Pointer; +import com.sun.jna.platform.win32.WinDef; + +import java.awt.*; + +public class JNIDecorations { + + public static native void updateValues(final long hwnd, final int left, final int right, final int height); + + public static native void setResizable(final long hwnd, final boolean resizable); + + public static native void setBackground(final long hwnd, final int r, final int g, final int b); + + public static native void minimize(final long hwnd); + + public static native void maximize(final long hwnd); + + public static native void restore(final long hwnd); + + public static native void installDecorations(final long hwnd); + + public static native void uninstallDecorations(final long hwnd); + + public static long getHWND(final Component component) { + var hwnd = new WinDef.HWND(); + hwnd.setPointer(Native.getComponentPointer(component)); + return Pointer.nativeValue(hwnd.getPointer()); + } + + static { + System.loadLibrary("jniplatform"); + } +} diff --git a/src/main/java/com/weis/darklaf/platform/windows/WindowsFrameUtil.java b/src/main/java/com/weis/darklaf/platform/windows/WindowsFrameUtil.java deleted file mode 100644 index ab4c5364..00000000 --- a/src/main/java/com/weis/darklaf/platform/windows/WindowsFrameUtil.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.weis.darklaf.platform.windows; - -import com.sun.jna.LastErrorException; -import com.sun.jna.Native; -import com.sun.jna.Pointer; -import com.sun.jna.platform.win32.User32; -import com.sun.jna.platform.win32.WinDef; -import com.sun.jna.platform.win32.WinDef.HWND; -import com.sun.jna.win32.StdCallLibrary; -import com.sun.jna.win32.W32APIOptions; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; - -import java.awt.*; - -public final class WindowsFrameUtil { - - public static void enableTitleBar(final Window window, final boolean enabled, final boolean resizable) { - if (window == null) return; - - final HWND hwnd = getHWND(window); - int style = User32.INSTANCE.GetWindowLong(hwnd, User32dll.GWL_STYLE); - if (enabled) { - style |= User32.WS_CAPTION; - } else { - style = User32.WS_THICKFRAME; - } - if (!resizable) { - style &= ~User32.WS_SIZEBOX; - } else { - style |= User32.WS_SIZEBOX; - } - //ResizeMode="CanResizeWithGrip" AllowsTransparency="True" - User32.INSTANCE.SetWindowLong(hwnd, User32dll.GWL_STYLE, style); - User32.INSTANCE.SetWindowPos(hwnd, new HWND(new Pointer(0L)), - 0, 0, 0, 0, 0x27); - } - - public static void setWindowCallback(final Window window, final WindowProc callback) { - if (window == null) return; - - final HWND hwnd = getHWND(window); - callback.parent = User32dll.INSTANCE.GetWindowLongPtr(hwnd, (long) User32dll.GWL_WNDPROC); - User32dll.INSTANCE.SetWindowLongPtr(hwnd, User32dll.GWL_WNDPROC, callback); - } - - @NotNull - @Contract("_ -> new") - public static HWND getHWND(final Component component) { - var hwnd = new HWND(); - hwnd.setPointer(Native.getComponentPointer(component)); - return hwnd; - } - - public interface User32dll extends User32 { - - User32dll INSTANCE = Native.loadLibrary("user32", User32dll.class, - W32APIOptions.UNICODE_OPTIONS); - - WNDPROC GetWindowLongPtr(HWND hWnd, long nIndex) throws LastErrorException; - - LONG_PTR SetWindowLongPtr(HWND hWnd, int nIndex, WNDPROC wndProc) throws LastErrorException; - - int ShowCursor(boolean bShow); - - void DisableProcessWindowsGhosting() throws LastErrorException; - - INT_PTR GetWindowDC(HWND hwnd); - - int ReleaseDC(HWND hwnd, INT_PTR hdc); - } - - public interface WNDPROC extends StdCallLibrary.StdCallCallback { - WinDef.LRESULT callback(HWND hWnd, int uMsg, WinDef.WPARAM uParam, WinDef.LPARAM lParam) throws LastErrorException; - } - - public abstract static class WindowProc implements WNDPROC { - - protected WNDPROC parent; - - } -} diff --git a/src/main/java/com/weis/darklaf/ui/colorchooser/DarkColorChooserUI.java b/src/main/java/com/weis/darklaf/ui/colorchooser/DarkColorChooserUI.java index afd24198..66121bed 100644 --- a/src/main/java/com/weis/darklaf/ui/colorchooser/DarkColorChooserUI.java +++ b/src/main/java/com/weis/darklaf/ui/colorchooser/DarkColorChooserUI.java @@ -8,9 +8,14 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.colorchooser.AbstractColorChooserPanel; +import javax.swing.event.AncestorEvent; +import javax.swing.event.AncestorListener; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicColorChooserUI; import java.awt.*; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; import java.beans.PropertyChangeListener; public class DarkColorChooserUI extends BasicColorChooserUI { @@ -33,6 +38,26 @@ public class DarkColorChooserUI extends BasicColorChooserUI { } } }; + private final AncestorListener ancestorListener = new AncestorListener() { + @Override + public void ancestorAdded(AncestorEvent event) { + var win = SwingUtilities.getWindowAncestor(chooser); + if (win instanceof Dialog) { + ((Dialog)win).setResizable(false); + chooser.removeAncestorListener(ancestorListener); + } + } + + @Override + public void ancestorRemoved(AncestorEvent event) { + + } + + @Override + public void ancestorMoved(AncestorEvent event) { + + } + }; @NotNull @Contract("_ -> new") @@ -54,12 +79,14 @@ public class DarkColorChooserUI extends BasicColorChooserUI { protected void installListeners() { super.installListeners(); chooser.addPropertyChangeListener(propertyChangeListener); + chooser.addAncestorListener(ancestorListener); } @Override protected void uninstallListeners() { super.uninstallListeners(); chooser.removePropertyChangeListener(propertyChangeListener); + chooser.removeAncestorListener(ancestorListener); } @Override diff --git a/src/main/java/com/weis/darklaf/ui/rootpane/DarkRootPaneUI.java b/src/main/java/com/weis/darklaf/ui/rootpane/DarkRootPaneUI.java index ec2eed40..ccd985eb 100644 --- a/src/main/java/com/weis/darklaf/ui/rootpane/DarkRootPaneUI.java +++ b/src/main/java/com/weis/darklaf/ui/rootpane/DarkRootPaneUI.java @@ -16,55 +16,31 @@ package com.weis.darklaf.ui.rootpane; * limitations under the License. */ -import com.sun.jna.platform.win32.WinDef; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import javax.swing.*; -import javax.swing.event.MouseInputAdapter; -import javax.swing.event.MouseInputListener; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicRootPaneUI; import java.awt.*; -import java.awt.event.ComponentAdapter; -import java.awt.event.ComponentEvent; -import java.awt.event.ComponentListener; +import java.awt.event.HierarchyEvent; import java.awt.event.HierarchyListener; -import java.awt.event.InputEvent; -import java.awt.event.MouseEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.awt.event.WindowListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; /** * @author Konstantin Bulenkov */ -public class DarkRootPaneUI extends BasicRootPaneUI { - private Cursor lastCursor; - - private enum CursorState {EXITED, ENTERED, NIL} - - private static final int CORNER_DRAG_WIDTH = 16; - private static final int BORDER_DRAG_THICKNESS = 5; +public class DarkRootPaneUI extends BasicRootPaneUI implements HierarchyListener { private Window window; private DarkTitlePane titlePane; - private MouseInputListener mouseInputListener; - private MouseInputListener titleMouseInputListener; private LayoutManager layoutManager; private LayoutManager oldLayout; - protected JRootPane rootPane; - protected WindowListener windowListener; - protected Window currentWindow; - protected HierarchyListener hierarchyListener; - protected ComponentListener windowComponentListener; - protected GraphicsConfiguration currentRootPaneGC; - protected PropertyChangeListener propertyChangeListener; + private JRootPane rootPane; + + private HierarchyListener hierarchyListener; + private PropertyChangeListener propertyChangeListener; @NotNull @@ -83,16 +59,12 @@ public class DarkRootPaneUI extends BasicRootPaneUI { public void uninstallUI(final JComponent c) { super.uninstallUI(c); uninstallClientDecorations(rootPane); - layoutManager = null; - mouseInputListener = null; - rootPane = null; } public void installBorder(@NotNull final JRootPane root) { int style = root.getWindowDecorationStyle(); - if (style == JRootPane.NONE) { LookAndFeel.uninstallBorder(root); } else { @@ -105,40 +77,12 @@ public class DarkRootPaneUI extends BasicRootPaneUI { } - private void installWindowListeners(final JRootPane root, final Component parent) { + private void updateWindow(final Component parent) { if (parent instanceof Window) { window = (Window) parent; } else { window = SwingUtilities.getWindowAncestor(parent); } - - if (window != null) { - if (mouseInputListener == null) { - mouseInputListener = createWindowMouseInputListener(root); - } - window.addMouseListener(mouseInputListener); - window.addMouseMotionListener(mouseInputListener); - - if (titlePane != null) { - if (titleMouseInputListener == null) { - titleMouseInputListener = new TitleMouseInputHandler(); - } - titlePane.addMouseMotionListener(titleMouseInputListener); - titlePane.addMouseListener(titleMouseInputListener); - } - setMaximized(); - } - } - - private void uninstallWindowListeners(final JRootPane root) { - if (window != null) { - window.removeMouseListener(mouseInputListener); - window.removeMouseMotionListener(mouseInputListener); - } - if (titlePane != null) { - titlePane.removeMouseListener(titleMouseInputListener); - titlePane.removeMouseMotionListener(titleMouseInputListener); - } } private void installLayout(final JRootPane root) { @@ -152,130 +96,12 @@ public class DarkRootPaneUI extends BasicRootPaneUI { @Override protected void installListeners(final JRootPane root) { super.installListeners(root); - hierarchyListener = e -> { - Component parent = root.getParent(); - if (parent == null) { - return; - } - if (parent.getClass().getName().startsWith("org.jdesktop.jdic.tray") - || (parent.getClass().getName().compareTo("javax.swing.Popup$HeavyWeightWindow") == 0)) { - - //noinspection SSBasedInspection - SwingUtilities.invokeLater(() -> { - root.removeHierarchyListener(hierarchyListener); - hierarchyListener = null; - }); - } - - Window currWindow; - if (parent instanceof Window) { - currWindow = (Window) parent; - } else { - currWindow = SwingUtilities.getWindowAncestor(parent); - } - if (windowListener != null) { - currentWindow.removeWindowListener(windowListener); - windowListener = null; - } - if (windowComponentListener != null) { - currentWindow.removeComponentListener(windowComponentListener); - windowComponentListener = null; - } - if (currWindow != null) { - windowListener = new WindowAdapter() { - @Override - public void windowClosed(final WindowEvent e) { - //noinspection SSBasedInspection - SwingUtilities.invokeLater(() -> { - Frame[] frames = Frame.getFrames(); - for (Frame frame : frames) { - if (frame.isDisplayable()) { - return; - } - } - }); - } - }; - - if (!(parent instanceof JInternalFrame)) { - currWindow.addWindowListener(windowListener); - } - - windowComponentListener = new ComponentAdapter() { - @Override - public void componentMoved(final ComponentEvent e) { - processNewPosition(); - } - - @Override - public void componentResized(final ComponentEvent e) { - processNewPosition(); - } - - private void processNewPosition() { - //noinspection SSBasedInspection - SwingUtilities.invokeLater(() -> { - if (window == null) { - return; - } - - if (!window.isShowing() - || !window.isDisplayable()) { - currentRootPaneGC = null; - return; - } - - GraphicsEnvironment ge = GraphicsEnvironment - .getLocalGraphicsEnvironment(); - GraphicsDevice[] gds = ge - .getScreenDevices(); - if (gds.length == 1) { - return; - } - Point midLoc = new Point(window.getLocationOnScreen().x + window.getWidth() / 2, - window.getLocationOnScreen().y - + window.getHeight() / 2); - - for (GraphicsDevice gd : gds) { - GraphicsConfiguration gc = gd.getDefaultConfiguration(); - Rectangle bounds = gc.getBounds(); - if (bounds.contains(midLoc)) { - if (gc != currentRootPaneGC) { - currentRootPaneGC = gc; - setMaximized(); - } - break; - } - } - }); - } - }; - - if (parent instanceof JFrame) { - currWindow.addComponentListener(windowComponentListener); - } - - if (currWindow != window) { - installClientDecorations(rootPane); - } - - window = currWindow; - } - currentWindow = currWindow; - }; - root.addHierarchyListener(hierarchyListener); + root.addHierarchyListener(this); root.addPropertyChangeListener(propertyChangeListener); } @Override protected void uninstallListeners(final JRootPane root) { - if (window != null) { - window.removeWindowListener(windowListener); - windowListener = null; - window - .removeComponentListener(windowComponentListener); - windowComponentListener = null; - } root.removeHierarchyListener(hierarchyListener); hierarchyListener = null; @@ -285,11 +111,6 @@ public class DarkRootPaneUI extends BasicRootPaneUI { super.uninstallListeners(root); } - /** - * Uninstalls the previously installed LayoutManager. - * - * @param root Root pane. - */ private void uninstallLayout(final JRootPane root) { if (oldLayout != null) { root.setLayout(oldLayout); @@ -297,18 +118,11 @@ public class DarkRootPaneUI extends BasicRootPaneUI { } } - /** - * Installs the necessary state onto the JRootPane to render client - * decorations. This is ONLY invoked if the JRootPane has a - * decoration style other than JRootPane.NONE. - * - * @param root Root pane. - */ private void installClientDecorations(final JRootPane root) { installBorder(root); DarkTitlePane titlePane = createTitlePane(root); setTitlePane(root, titlePane); - installWindowListeners(root, root.getParent()); + updateWindow(root.getParent()); installLayout(root); if (window != null) { if (window instanceof Frame) { @@ -323,7 +137,6 @@ public class DarkRootPaneUI extends BasicRootPaneUI { private void uninstallClientDecorations(final JRootPane root) { uninstallBorder(root); - uninstallWindowListeners(root); setTitlePane(root, null); uninstallLayout(root); int style = root.getWindowDecorationStyle(); @@ -335,7 +148,6 @@ public class DarkRootPaneUI extends BasicRootPaneUI { titlePane.uninstall(); titlePane = null; } - if (window != null) { window.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } @@ -343,13 +155,7 @@ public class DarkRootPaneUI extends BasicRootPaneUI { } protected DarkTitlePane createTitlePane(final JRootPane root) { - return new DarkTitlePane(root, this); - } - - @NotNull - @Contract(value = "_ -> new", pure = true) - private MouseInputListener createWindowMouseInputListener(final JRootPane root) { - return new DarkRootPaneUI.MouseInputHandler(); + return new DarkTitlePane(root); } protected LayoutManager createLayoutManager() { @@ -370,38 +176,16 @@ public class DarkRootPaneUI extends BasicRootPaneUI { this.titlePane = titlePane; } - public void setMaximized() { - Component tla = rootPane.getTopLevelAncestor(); - GraphicsConfiguration gc = (currentRootPaneGC != null) ? currentRootPaneGC - : tla.getGraphicsConfiguration(); - var mode = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDisplayMode(); - Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(gc); - Rectangle maxBounds = new Rectangle(screenInsets.left, screenInsets.top, - mode.getWidth() - ((screenInsets.left + screenInsets.right)), - mode.getHeight() - ((screenInsets.top + screenInsets.bottom))); - if (tla instanceof JFrame) { - ((JFrame) tla).setMaximizedBounds(maxBounds); - } - } - - public JComponent getTitlePane() { + @Contract(pure = true) + protected JComponent getTitlePane() { return titlePane; } - protected JRootPane getRootPane() { - return rootPane; - } - @Override public void propertyChange(final PropertyChangeEvent e) { super.propertyChange(e); - String propertyName = e.getPropertyName(); - if (propertyName == null) { - return; - } - - if (propertyName.equals("windowDecorationStyle")) { + if ("windowDecorationStyle".equals(propertyName)) { JRootPane root = (JRootPane) e.getSource(); int style = root.getWindowDecorationStyle(); @@ -409,594 +193,40 @@ public class DarkRootPaneUI extends BasicRootPaneUI { if (style != JRootPane.NONE) { installClientDecorations(root); } - } - if (propertyName.equals("ancestor")) { - uninstallWindowListeners(rootPane); + } else if ("ancestor".equals(propertyName)) { if (((JRootPane) e.getSource()).getWindowDecorationStyle() != JRootPane.NONE) { - installWindowListeners(rootPane, rootPane.getParent()); + updateWindow(rootPane.getParent()); } } } - protected static class SubstanceRootLayout implements LayoutManager2 { - public Dimension preferredLayoutSize(@NotNull final Container parent) { - Dimension cpd, mbd, tpd; - int cpWidth = 0; - int cpHeight = 0; - int mbWidth = 0; - int mbHeight = 0; - int tpWidth = 0; - int tpHeight = 0; - Insets i = parent.getInsets(); - JRootPane root = (JRootPane) parent; - - if (root.getContentPane() != null) { - cpd = root.getContentPane().getPreferredSize(); - } else { - cpd = root.getSize(); - } - if (cpd != null) { - cpWidth = cpd.width; - cpHeight = cpd.height; - } - - if (root.getJMenuBar() != null) { - mbd = root.getJMenuBar().getPreferredSize(); - if (mbd != null) { - mbWidth = mbd.width; - mbHeight = mbd.height; - } - } - - if ((root.getWindowDecorationStyle() != JRootPane.NONE) - && (root.getUI() instanceof DarkRootPaneUI)) { - JComponent titlePane = ((DarkRootPaneUI) root.getUI()).getTitlePane(); - if (titlePane != null) { - tpd = titlePane.getPreferredSize(); - if (tpd != null) { - tpWidth = tpd.width; - tpHeight = tpd.height; - } - } - } - - return new Dimension(Math.max(Math.max(cpWidth, mbWidth), tpWidth) - + i.left + i.right, cpHeight + mbHeight + tpHeight + i.top + i.bottom); - } - - public Dimension minimumLayoutSize(@NotNull final Container parent) { - Dimension cpd, mbd, tpd; - int cpWidth = 0; - int cpHeight = 0; - int mbWidth = 0; - int mbHeight = 0; - int tpWidth = 0; - int tpHeight = 0; - Insets i = parent.getInsets(); - JRootPane root = (JRootPane) parent; - - if (root.getContentPane() != null) { - cpd = root.getContentPane().getMinimumSize(); - } else { - cpd = root.getSize(); - } - if (cpd != null) { - cpWidth = cpd.width; - cpHeight = cpd.height; - } - - if (root.getJMenuBar() != null) { - mbd = root.getJMenuBar().getMinimumSize(); - if (mbd != null) { - mbWidth = mbd.width; - mbHeight = mbd.height; - } - } - if ((root.getWindowDecorationStyle() != JRootPane.NONE) - && (root.getUI() instanceof DarkRootPaneUI)) { - JComponent titlePane = ((DarkRootPaneUI) root.getUI()) - .getTitlePane(); - if (titlePane != null) { - tpd = titlePane.getMinimumSize(); - if (tpd != null) { - tpWidth = tpd.width; - tpHeight = tpd.height; - } - } - } - - return new Dimension(Math.max(Math.max(cpWidth, mbWidth), tpWidth) - + i.left + i.right, cpHeight + mbHeight + tpHeight + i.top - + i.bottom); - } - - public Dimension maximumLayoutSize(@NotNull final Container target) { - Dimension cpd, mbd, tpd; - int cpWidth = Integer.MAX_VALUE; - int cpHeight = Integer.MAX_VALUE; - int mbWidth = Integer.MAX_VALUE; - int mbHeight = Integer.MAX_VALUE; - int tpWidth = Integer.MAX_VALUE; - int tpHeight = Integer.MAX_VALUE; - Insets i = target.getInsets(); - JRootPane root = (JRootPane) target; - - if (root.getContentPane() != null) { - cpd = root.getContentPane().getMaximumSize(); - if (cpd != null) { - cpWidth = cpd.width; - cpHeight = cpd.height; - } - } - - if (root.getJMenuBar() != null) { - mbd = root.getJMenuBar().getMaximumSize(); - if (mbd != null) { - mbWidth = mbd.width; - mbHeight = mbd.height; - } - } - - if ((root.getWindowDecorationStyle() != JRootPane.NONE) - && (root.getUI() instanceof DarkRootPaneUI)) { - JComponent titlePane = ((DarkRootPaneUI) root.getUI()) - .getTitlePane(); - if (titlePane != null) { - tpd = titlePane.getMaximumSize(); - if (tpd != null) { - tpWidth = tpd.width; - tpHeight = tpd.height; - } - } - } - - int maxHeight = Math.max(Math.max(cpHeight, mbHeight), tpHeight); - if (maxHeight != Integer.MAX_VALUE) { - maxHeight = cpHeight + mbHeight + tpHeight + i.top + i.bottom; - } - - int maxWidth = Math.max(Math.max(cpWidth, mbWidth), tpWidth); - - if (maxWidth != Integer.MAX_VALUE) { - maxWidth += i.left + i.right; - } - - return new Dimension(maxWidth, maxHeight); - } - - public void layoutContainer(final Container parent) { - JRootPane root = (JRootPane) parent; - Rectangle b = root.getBounds(); - Insets i = root.getInsets(); - int nextY = 0; - int w = b.width - i.right - i.left; - int h = b.height - i.top - i.bottom; - - if (root.getLayeredPane() != null) { - root.getLayeredPane().setBounds(i.left, i.top, w, h); - } - if (root.getGlassPane() != null) { - root.getGlassPane().setBounds(i.left, i.top, w, h); - } - - if ((root.getWindowDecorationStyle() != JRootPane.NONE) - && (root.getUI() instanceof DarkRootPaneUI)) { - JComponent titlePane = ((DarkRootPaneUI) root.getUI()) - .getTitlePane(); - if (titlePane != null) { - Dimension tpd = titlePane.getPreferredSize(); - if (tpd != null) { - int tpHeight = tpd.height; - titlePane.setBounds(0, 0, w, tpHeight); - nextY += tpHeight; - } - } - } - if (root.getJMenuBar() != null) { - Dimension mbd = root.getJMenuBar().getPreferredSize(); - root.getJMenuBar().setBounds(0, nextY, w, mbd.height); - nextY += mbd.height; - } - if (root.getContentPane() != null) { - - root.getContentPane().setBounds(0, nextY, w, h < nextY ? 0 : h - nextY); - } - } - - public void addLayoutComponent(final String name, final Component comp) { - } - - public void removeLayoutComponent(final Component comp) { - } - - public void addLayoutComponent(final Component comp, final Object constraints) { - } - - public float getLayoutAlignmentX(final Container target) { - return 0.0f; - } - - public float getLayoutAlignmentY(final Container target) { - return 0.0f; - } - - public void invalidateLayout(final Container target) { - } - } - - private static final int[] cursorMapping = new int[]{ - Cursor.NW_RESIZE_CURSOR, Cursor.NW_RESIZE_CURSOR, - Cursor.N_RESIZE_CURSOR, Cursor.NE_RESIZE_CURSOR, - Cursor.NE_RESIZE_CURSOR, Cursor.NW_RESIZE_CURSOR, 0, 0, 0, - Cursor.NE_RESIZE_CURSOR, Cursor.W_RESIZE_CURSOR, 0, 0, 0, - Cursor.E_RESIZE_CURSOR, Cursor.SW_RESIZE_CURSOR, 0, 0, 0, - Cursor.SE_RESIZE_CURSOR, Cursor.SW_RESIZE_CURSOR, - Cursor.SW_RESIZE_CURSOR, Cursor.S_RESIZE_CURSOR, - Cursor.SE_RESIZE_CURSOR, Cursor.SE_RESIZE_CURSOR}; - - private class MouseInputHandler implements MouseInputListener { - private boolean isMovingWindow; - private int dragCursor; - private int dragOffsetX; - private int dragOffsetY; - private int dragWidth; - private int dragHeight; - - private final PrivilegedExceptionAction getLocationAction = () -> MouseInfo.getPointerInfo().getLocation(); - - public void mousePressed(final MouseEvent ev) { - JRootPane rootPane = getRootPane(); - - if (rootPane.getWindowDecorationStyle() == JRootPane.NONE) { - return; - } - Point dragWindowOffset = ev.getPoint(); - Window w = (Window) ev.getSource(); - if (w != null) { - w.toFront(); - } - Point convertedDragWindowOffset = SwingUtilities.convertPoint(w, dragWindowOffset, getTitlePane()); - - Frame f = null; - Dialog d = null; - - if (w instanceof Frame) { - f = (Frame) w; - } else if (w instanceof Dialog) { - d = (Dialog) w; - } - - int frameState = (f != null) ? f.getExtendedState() : 0; - - if ((getTitlePane() != null) - && getTitlePane().contains( - convertedDragWindowOffset)) { - if ((((f != null) && ((frameState & Frame.MAXIMIZED_BOTH) == 0)) || (d != null)) - && (dragWindowOffset.y >= BORDER_DRAG_THICKNESS) - && (dragWindowOffset.x >= BORDER_DRAG_THICKNESS) - && (dragWindowOffset.x < w.getWidth() - BORDER_DRAG_THICKNESS)) { - isMovingWindow = true; - dragOffsetX = dragWindowOffset.x; - dragOffsetY = dragWindowOffset.y; - } - } else if (((f != null) && f.isResizable() && ((frameState & Frame.MAXIMIZED_BOTH) == 0)) - || ((d != null) && d.isResizable())) { - dragOffsetX = dragWindowOffset.x; - dragOffsetY = dragWindowOffset.y; - dragWidth = w.getWidth(); - dragHeight = w.getHeight(); - dragCursor = getCursor(calculateCorner(w, dragWindowOffset.x, dragWindowOffset.y)); - } - } - - public void mouseReleased(final MouseEvent ev) { - if ((dragCursor != 0) - && (window != null) - && !window.isValid()) { - window.validate(); - getRootPane().repaint(); - } - isMovingWindow = false; - dragCursor = 0; - } - - public void mouseMoved(final MouseEvent ev) { - JRootPane root = getRootPane(); - - if (root.getWindowDecorationStyle() == JRootPane.NONE) { - return; - } - - Window w = (Window) ev.getSource(); - - Frame f = null; - Dialog d = null; - - if (w instanceof Frame) { - f = (Frame) w; - } else if (w instanceof Dialog) { - d = (Dialog) w; - } - - int cursor = getCursor(calculateCorner(w, ev.getX(), ev.getY())); - - if ((cursor != 0) - && (((f != null) && (f.isResizable() && ((f.getExtendedState() & Frame.MAXIMIZED_BOTH) == 0))) - || ((d != null) && d.isResizable()))) { - w.setCursor(Cursor.getPredefinedCursor(cursor)); - } else { - w.setCursor(lastCursor); - } - } - - private void adjust(@NotNull final Rectangle bounds, final Dimension min, final int deltaX, - final int deltaY, final int deltaWidth, final int deltaHeight) { - bounds.x += deltaX; - bounds.y += deltaY; - bounds.width += deltaWidth; - bounds.height += deltaHeight; - if (min != null) { - if (bounds.width < min.width) { - int correction = min.width - bounds.width; - if (deltaX != 0) { - bounds.x -= correction; - } - bounds.width = min.width; - } - if (bounds.height < min.height) { - int correction = min.height - bounds.height; - if (deltaY != 0) { - bounds.y -= correction; - } - bounds.height = min.height; - } - } - } - - public void mouseDragged(@NotNull final MouseEvent ev) { - Window w = (Window) ev.getSource(); - Point pt = ev.getPoint(); - - if (isMovingWindow) { - Point windowPt; - try { - windowPt = (Point) AccessController.doPrivileged(getLocationAction); - windowPt.x = windowPt.x - dragOffsetX; - windowPt.y = windowPt.y - dragOffsetY; - setLocation(window, windowPt.x, windowPt.y); - } catch (PrivilegedActionException ignored) { - } - } else if (dragCursor != 0) { - Rectangle r = w.getBounds(); - Rectangle startBounds = new Rectangle(r); - Dimension min = w.getMinimumSize(); - - switch (dragCursor) { - case Cursor.E_RESIZE_CURSOR: - adjust(r, min, 0, 0, pt.x - + (dragWidth - dragOffsetX) - r.width, 0); - break; - case Cursor.S_RESIZE_CURSOR: - adjust(r, min, 0, 0, 0, pt.y - + (dragHeight - dragOffsetY) - r.height); - break; - case Cursor.N_RESIZE_CURSOR: - adjust(r, min, 0, pt.y - dragOffsetY, 0, - -(pt.y - dragOffsetY)); - break; - case Cursor.W_RESIZE_CURSOR: - adjust(r, min, pt.x - dragOffsetX, 0, - -(pt.x - dragOffsetX), 0); - break; - case Cursor.NE_RESIZE_CURSOR: - adjust(r, min, 0, pt.y - dragOffsetY, pt.x - + (dragWidth - dragOffsetX) - r.width, - -(pt.y - dragOffsetY)); - break; - case Cursor.SE_RESIZE_CURSOR: - adjust(r, min, 0, 0, pt.x - + (dragWidth - dragOffsetX) - r.width, - pt.y + (dragHeight - dragOffsetY) - - r.height); - break; - case Cursor.NW_RESIZE_CURSOR: - adjust(r, min, pt.x - dragOffsetX, pt.y - - dragOffsetY, -(pt.x - dragOffsetX), - -(pt.y - dragOffsetY)); - break; - case Cursor.SW_RESIZE_CURSOR: - adjust(r, min, pt.x - dragOffsetX, 0, - -(pt.x - dragOffsetX), pt.y - + (dragHeight - dragOffsetY) - - r.height); - break; - default: - break; - } - if (!r.equals(startBounds)) { - w.setBounds(r); - if (Toolkit.getDefaultToolkit().isDynamicLayoutActive()) { - w.validate(); - getRootPane().repaint(); - } - } - } - } - - private DarkRootPaneUI.CursorState cursorState = - DarkRootPaneUI.CursorState.NIL; - - public void mouseEntered(@NotNull final MouseEvent ev) { - Window w = (Window) ev.getSource(); - if (cursorState == DarkRootPaneUI.CursorState.EXITED - || cursorState == DarkRootPaneUI.CursorState.NIL) { - lastCursor = w.getCursor(); - } - cursorState = DarkRootPaneUI.CursorState.ENTERED; - mouseMoved(ev); - } - - public void mouseExited(@NotNull final MouseEvent ev) { - Window w = (Window) ev.getSource(); - w.setCursor(lastCursor); - cursorState = DarkRootPaneUI.CursorState.EXITED; - } - - public void mouseClicked(@NotNull final MouseEvent ev) { - Window w = (Window) ev.getSource(); - Frame f; - - if (w instanceof Frame) { - f = (Frame) w; - } else { - return; - } - - JComponent windowTitlePane = getTitlePane(); - if (windowTitlePane == null) { - return; - } - - Point convertedPoint = SwingUtilities.convertPoint(w, ev.getPoint(), windowTitlePane); - - int state = f.getExtendedState(); - if (windowTitlePane.contains(convertedPoint)) { - if (((ev.getClickCount() % 2) == 0) - && ((ev.getModifiers() & InputEvent.BUTTON1_MASK) != 0)) { - if (f.isResizable()) { - if ((state & Frame.MAXIMIZED_BOTH) != 0) { - setMaximized(); - f.setExtendedState(state & ~Frame.MAXIMIZED_BOTH); - } else { - setMaximized(); - f.setExtendedState(state | Frame.MAXIMIZED_BOTH); - } - } - } - } - } - - private int calculateCorner(@NotNull final Window w, final int x, final int y) { - Insets insets = w.getInsets(); - int xPosition = calculatePosition(x - insets.left, w.getWidth() - insets.left - insets.right); - int yPosition = calculatePosition(y - insets.top, w.getHeight() - insets.top - insets.bottom); - - if ((xPosition == -1) || (yPosition == -1)) { - return -1; - } - return yPosition * 5 + xPosition; - } - - @Contract(pure = true) - private int getCursor(final int corner) { - if (corner == -1) { - return 0; - } - return cursorMapping[corner]; - } - - @Contract(pure = true) - private int calculatePosition(final int spot, final int width) { - if (spot < BORDER_DRAG_THICKNESS) { - return 0; - } - if (spot < CORNER_DRAG_WIDTH) { - return 1; - } - if (spot >= (width - BORDER_DRAG_THICKNESS)) { - return 4; - } - if (spot >= (width - CORNER_DRAG_WIDTH)) { - return 3; - } - return 2; + @Override + public void hierarchyChanged(HierarchyEvent e) { + Component parent = rootPane.getParent(); + if (parent == null) { + return; } - } - - private void setLocation(@NotNull final Window w, final int x, final int y) { - WinDef.LPARAM lParam = new WinDef.LPARAM(); - lParam.setValue((y << 16) | x); - w.setLocation(x, y); -// WindowsFrameUtil.User32dll.INSTANCE.SendMessage(WindowsFrameUtil.getHWND(w), 3, -// new WinDef.WPARAM(0), lParam); - - } - - private class TitleMouseInputHandler extends MouseInputAdapter { - private Point dragOffset = new Point(0, 0); - - @Override - public void mousePressed(final MouseEvent ev) { - JRootPane rootPane = getRootPane(); - - if (rootPane.getWindowDecorationStyle() == JRootPane.NONE) { - return; - } - - Point dragWindowOffset = ev.getPoint(); - Component source = (Component) ev.getSource(); - - Point convertedDragWindowOffset = SwingUtilities.convertPoint( - source, dragWindowOffset, getTitlePane()); - - dragWindowOffset = SwingUtilities.convertPoint(source, dragWindowOffset, window); - - if (getTitlePane() != null && getTitlePane().contains(convertedDragWindowOffset)) { - if (window != null) { - window.toFront(); - dragOffset = dragWindowOffset; - } - } + if (parent.getClass().getName().startsWith("org.jdesktop.jdic.tray") + || (parent.getClass().getName().compareTo("javax.swing.Popup$HeavyWeightWindow") == 0)) { + SwingUtilities.invokeLater(() -> { + rootPane.removeHierarchyListener(hierarchyListener); + hierarchyListener = null; + }); } - @Override - public void mouseDragged(@NotNull final MouseEvent ev) { - Component source = (Component) ev.getSource(); - - Point eventLocationOnScreen = ev.getLocationOnScreen(); - if (eventLocationOnScreen == null) { - eventLocationOnScreen = new Point( - ev.getX() + source.getLocationOnScreen().x, ev.getY() + source.getLocationOnScreen().y); - } - if (window instanceof Frame) { - Frame f = (Frame) window; - int frameState = f.getExtendedState(); - - if (((frameState & Frame.MAXIMIZED_BOTH) == 0)) { - - setLocation(window, eventLocationOnScreen.x - dragOffset.x, eventLocationOnScreen.y - dragOffset.y); - } - } else { - setLocation(window, eventLocationOnScreen.x - dragOffset.x, eventLocationOnScreen.y - dragOffset.y); - } + Window currWindow; + if (parent instanceof Window) { + currWindow = (Window) parent; + } else { + currWindow = SwingUtilities.getWindowAncestor(parent); } - @Override - public void mouseClicked(final MouseEvent e) { - Frame f; - - if (window instanceof Frame) { - f = (Frame) window; - } else { - return; - } - - Point convertedPoint = SwingUtilities.convertPoint(window, e.getPoint(), getTitlePane()); - - int state = f.getExtendedState(); - if ((getTitlePane() != null) && getTitlePane().contains(convertedPoint)) { - if (((e.getClickCount() % 2) == 0) && ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0)) { - if (f.isResizable()) { - if ((state & Frame.MAXIMIZED_BOTH) != 0) { - setMaximized(); - f.setExtendedState(state & ~Frame.MAXIMIZED_BOTH); - } else { - setMaximized(); - f.setExtendedState(state | Frame.MAXIMIZED_BOTH); - } - } - } + if (currWindow != null) { + if (currWindow != window) { + uninstallClientDecorations(rootPane); + installClientDecorations(rootPane); } + window = currWindow; } } } \ No newline at end of file diff --git a/src/main/java/com/weis/darklaf/ui/rootpane/DarkTitlePane.java b/src/main/java/com/weis/darklaf/ui/rootpane/DarkTitlePane.java index aac18b56..eaa7c136 100644 --- a/src/main/java/com/weis/darklaf/ui/rootpane/DarkTitlePane.java +++ b/src/main/java/com/weis/darklaf/ui/rootpane/DarkTitlePane.java @@ -16,8 +16,7 @@ package com.weis.darklaf.ui.rootpane; * limitations under the License. */ -import com.sun.jna.Structure; -import com.weis.darklaf.platform.windows.WindowsFrameUtil; +import com.weis.darklaf.platform.windows.JNIDecorations; import com.weis.darklaf.ui.button.DarkButtonUI; import com.weis.darklaf.util.GraphicsUtil; import org.jetbrains.annotations.Contract; @@ -107,6 +106,7 @@ public class DarkTitlePane extends JComponent { private JLabel titleLabel; private Window window; + private long windowHandle; private final JRootPane rootPane; private JMenuBar menuBar; private int state; @@ -117,7 +117,7 @@ public class DarkTitlePane extends JComponent { private Color activeForeground; private Color border; - public DarkTitlePane(final JRootPane root, final DarkRootPaneUI ui) { + public DarkTitlePane(final JRootPane root) { this.rootPane = root; rootPane.addContainerListener(rootPaneContainerListener); rootPane.getLayeredPane().addContainerListener(layeredPaneContainerListener); @@ -131,6 +131,8 @@ public class DarkTitlePane extends JComponent { public void uninstall() { uninstallListeners(); window = null; + JNIDecorations.uninstallDecorations(windowHandle); + windowHandle = 0; rootPane.removeContainerListener(rootPaneContainerListener); removeAll(); } @@ -178,34 +180,15 @@ public class DarkTitlePane extends JComponent { window = SwingUtilities.getWindowAncestor(this); if (window != null) { if (window instanceof Dialog || window instanceof Frame) { - //rootPane.getWindowDecorationStyle() == JRootPane.FRAME - WindowsFrameUtil.enableTitleBar(window, false, true); + windowHandle = JNIDecorations.getHWND(window); + JNIDecorations.installDecorations(windowHandle); + JNIDecorations.setResizable(windowHandle, isResizable(rootPane)); + var color = UIManager.getColor("RootPane.background"); + JNIDecorations.setBackground(windowHandle, color.getRed(), color.getGreen(), color.getBlue()); } -// var hwnd = WindowsFrameUtil.getHWND(window); -// NativeLibrary dwm = NativeLibrary.getInstance("dwmapi"); -// dwm.getFunction("DwmExtendFrameIntoClientArea").invoke(WinNT.HRESULT.class, -// new Object[]{hwnd, new MARGINS(0, 0, 0, 0)}); -// WindowsFrameUtil.User32dll.INSTANCE.SetWindowPos(hwnd, new WinDef.HWND(new Pointer(0)), 0, 0, 0, 0, -// WinUser.SWP_NOZORDER | -// WinUser.SWP_NOOWNERZORDER | -// WinUser.SWP_NOMOVE | -// WinUser.SWP_NOSIZE | -// WinUser.SWP_FRAMECHANGED); -// WindowsFrameUtil.setWindowCallback(window, new WindowsFrameUtil.WindowProc() { -// @Override -// public WinDef.LRESULT callback(final WinDef.HWND hWnd, final int uMsg, final WinDef.WPARAM uParam, -// final WinDef.LPARAM lParam) throws LastErrorException { -// if (uMsg == 0x0083 && uParam.intValue() != 0) { -// return new WinDef.LRESULT(0); -// } -// return parent.callback(hWnd, uMsg, uParam, lParam); -// } -// }); - if (window instanceof Frame) { titleLabel.setText(((Frame) window).getTitle()); - ((Frame) window).setMaximizedBounds(getMaximizedBounds()); setState(((Frame) window).getExtendedState()); } else { setState(0); @@ -219,41 +202,13 @@ public class DarkTitlePane extends JComponent { } } - public class MARGINS extends Structure implements Structure.ByReference { - public int cxLeftWidth; - public int cxRightWidth; - public int cyTopHeight; - public int cyBottomHeight; - - public MARGINS(final int a, final int b, final int c, final int d) { - cxLeftWidth = a; - cxRightWidth = b; - cyTopHeight = c; - cyBottomHeight = d; - } - - @Override - protected List getFieldOrder() { - return List.of("cxLeftWidth", "cxRightWidth", "cyTopHeight", "cyBottomHeight"); - } - } - - - @NotNull - private Rectangle getMaximizedBounds() { - Insets screenInsets = getToolkit().getScreenInsets(getGraphicsConfiguration()); - Rectangle screenSize = getGraphicsConfiguration().getBounds(); - return new Rectangle(screenInsets.left + screenSize.x, - screenInsets.top + screenSize.y, - screenSize.x + screenSize.width - screenInsets.right - screenInsets.left, - screenSize.y + screenSize.height - screenInsets.bottom - screenInsets.top); + protected boolean isResizable(@NotNull final JRootPane rootPane) { + return JRootPane.NONE != rootPane.getWindowDecorationStyle(); } public void removeNotify() { super.removeNotify(); - uninstallListeners(); - window = null; } private void installSubcomponents() { @@ -271,12 +226,12 @@ public class DarkTitlePane extends JComponent { add(maximizeToggleButton); add(closeButton); } else if (decorationStyle == JRootPane.PLAIN_DIALOG || - decorationStyle == JRootPane.INFORMATION_DIALOG || - decorationStyle == JRootPane.ERROR_DIALOG || - decorationStyle == JRootPane.COLOR_CHOOSER_DIALOG || - decorationStyle == JRootPane.FILE_CHOOSER_DIALOG || - decorationStyle == JRootPane.QUESTION_DIALOG || - decorationStyle == JRootPane.WARNING_DIALOG) { + decorationStyle == JRootPane.INFORMATION_DIALOG || + decorationStyle == JRootPane.ERROR_DIALOG || + decorationStyle == JRootPane.COLOR_CHOOSER_DIALOG || + decorationStyle == JRootPane.FILE_CHOOSER_DIALOG || + decorationStyle == JRootPane.QUESTION_DIALOG || + decorationStyle == JRootPane.WARNING_DIALOG) { add(closeButton); } } @@ -316,10 +271,11 @@ public class DarkTitlePane extends JComponent { windowIconButton = new JButton(); windowIconButton.setComponentPopupMenu(createMenu()); windowIconButton.putClientProperty("JButton.variant", "onlyLabel"); - windowIconButton.addActionListener( - e -> windowIconButton.getComponentPopupMenu().show(windowIconButton, - windowIconButton.getWidth() / 2, - windowIconButton.getHeight() / 2)); + windowIconButton.addActionListener(e -> windowIconButton + .getComponentPopupMenu() + .show(windowIconButton, + windowIconButton.getWidth() / 2, + windowIconButton.getHeight() / 2)); windowIconButton.setFocusable(false); windowIconButton.setBorderPainted(false); return windowIconButton; @@ -355,38 +311,21 @@ public class DarkTitlePane extends JComponent { private void close() { Window window = getWindow(); - if (window != null) { window.dispatchEvent(new WindowEvent(window, WindowEvent.WINDOW_CLOSING)); } } private void minimize() { - Frame frame = getFrame(); - if (frame != null) { - frame.setExtendedState(state | Frame.ICONIFIED); - } + JNIDecorations.minimize(windowHandle); } private void maximize() { - Frame frame = getFrame(); - if (frame != null) { - frame.setExtendedState(state | Frame.MAXIMIZED_BOTH); - } + JNIDecorations.maximize(windowHandle); } private void restore() { - Frame frame = getFrame(); - - if (frame == null) { - return; - } - - if ((state & Frame.ICONIFIED) != 0) { - frame.setExtendedState(state & ~Frame.ICONIFIED); - } else { - frame.setExtendedState(state & ~Frame.MAXIMIZED_BOTH); - } + JNIDecorations.restore(windowHandle); } private void createActions() { @@ -470,17 +409,13 @@ public class DarkTitlePane extends JComponent { if (frame != null) { JRootPane rootPane = getRootPane(); - if (((state & Frame.MAXIMIZED_BOTH) != 0) && - (rootPane.getBorder() == null || - (rootPane.getBorder() instanceof UIResource)) && - frame.isShowing()) { + if (((state & Frame.MAXIMIZED_BOTH) != 0) + && (rootPane.getBorder() == null + || (rootPane.getBorder() instanceof UIResource)) + && frame.isShowing()) { rootPane.setBorder(null); - } else if ((state & Frame.MAXIMIZED_BOTH) == 0) { - // This is a croak, if state becomes bound, this can - // be nuked. - //Todo -// rootPaneUI.installBorder(rootPane); } + if (frame.isResizable()) { if ((state & Frame.MAXIMIZED_BOTH) != 0) { updateToggleButton(restoreAction, restoreIcon); @@ -491,8 +426,7 @@ public class DarkTitlePane extends JComponent { maximizeAction.setEnabled(true); restoreAction.setEnabled(false); } - if (maximizeToggleButton.getParent() == null || - minimizeButton.getParent() == null) { + if (maximizeToggleButton.getParent() == null || minimizeButton.getParent() == null) { add(maximizeToggleButton); add(minimizeButton); revalidate(); @@ -653,36 +587,46 @@ public class DarkTitlePane extends JComponent { int start = 0; int y = 0; int height = computeHeight(); + int left = 0; + int right = 0; if (leftToRight) { if (windowIconButton != null) { windowIconButton.setBounds(start + PAD, y, ICON_WIDTH, height); start += ICON_WIDTH + PAD; + left = start; } if (menuBar != null) { int menuWidth = getPreferredMenuSize().width; Insets menuInsets = menuBar.getInsets(); menuBar.setBounds(start + PAD, y, menuWidth, height + menuInsets.bottom); start += menuWidth + PAD; + left += menuWidth; } x = w; if (closeButton != null) { x -= BUTTON_WIDTH; + right += BUTTON_WIDTH; closeButton.setBounds(x, y, BUTTON_WIDTH, height); } if (getWindowDecorationStyle() == JRootPane.FRAME) { if (Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.MAXIMIZED_BOTH)) { if (minimizeButton != null && maximizeToggleButton.getParent() != null) { x -= BUTTON_WIDTH; + right += BUTTON_WIDTH; maximizeToggleButton.setBounds(x, y, BUTTON_WIDTH, height); } if (minimizeButton != null && minimizeButton.getParent() != null) { x -= BUTTON_WIDTH; + right += BUTTON_WIDTH; minimizeButton.setBounds(x, y, BUTTON_WIDTH, height); } } } titleLabel.setBounds(start + TITLE_PAD, 0, x - start - 2 * TITLE_PAD, height); + JNIDecorations.updateValues(windowHandle, (int) (left * GraphicsUtil.SCALE_X), + (int) (right * GraphicsUtil.SCALE_X), + (int) (height * GraphicsUtil.SCALE_Y)); } else { //Todo. } @@ -698,6 +642,7 @@ public class DarkTitlePane extends JComponent { setState(frame.getExtendedState(), true); } if ("resizable".equals(name)) { + JNIDecorations.setResizable(windowHandle, Boolean.TRUE.equals(pce.getNewValue())); getRootPane().repaint(); } } else if ("title".equals(name)) { diff --git a/src/main/java/com/weis/darklaf/ui/rootpane/SubstanceRootLayout.java b/src/main/java/com/weis/darklaf/ui/rootpane/SubstanceRootLayout.java new file mode 100644 index 00000000..2e61c4be --- /dev/null +++ b/src/main/java/com/weis/darklaf/ui/rootpane/SubstanceRootLayout.java @@ -0,0 +1,213 @@ +package com.weis.darklaf.ui.rootpane; + +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; + +class SubstanceRootLayout implements LayoutManager2 { + public Dimension preferredLayoutSize(@NotNull final Container parent) { + Dimension cpd, mbd, tpd; + int cpWidth = 0; + int cpHeight = 0; + int mbWidth = 0; + int mbHeight = 0; + int tpWidth = 0; + int tpHeight = 0; + Insets i = parent.getInsets(); + JRootPane root = (JRootPane) parent; + + if (root.getContentPane() != null) { + cpd = root.getContentPane().getPreferredSize(); + } else { + cpd = root.getSize(); + } + if (cpd != null) { + cpWidth = cpd.width; + cpHeight = cpd.height; + } + + if (root.getJMenuBar() != null) { + mbd = root.getJMenuBar().getPreferredSize(); + if (mbd != null) { + mbWidth = mbd.width; + mbHeight = mbd.height; + } + } + + if ((root.getWindowDecorationStyle() != JRootPane.NONE) + && (root.getUI() instanceof DarkRootPaneUI)) { + JComponent titlePane = ((DarkRootPaneUI) root.getUI()).getTitlePane(); + if (titlePane != null) { + tpd = titlePane.getPreferredSize(); + if (tpd != null) { + tpWidth = tpd.width; + tpHeight = tpd.height; + } + } + } + + return new Dimension(Math.max(Math.max(cpWidth, mbWidth), tpWidth) + + i.left + i.right, + cpHeight + mbHeight + tpHeight + i.top + i.bottom); + } + + public Dimension minimumLayoutSize(@NotNull final Container parent) { + Dimension cpd, mbd, tpd; + int cpWidth = 0; + int cpHeight = 0; + int mbWidth = 0; + int mbHeight = 0; + int tpWidth = 0; + int tpHeight = 0; + Insets i = parent.getInsets(); + JRootPane root = (JRootPane) parent; + + if (root.getContentPane() != null) { + cpd = root.getContentPane().getMinimumSize(); + } else { + cpd = root.getSize(); + } + if (cpd != null) { + cpWidth = cpd.width; + cpHeight = cpd.height; + } + + if (root.getJMenuBar() != null) { + mbd = root.getJMenuBar().getMinimumSize(); + if (mbd != null) { + mbWidth = mbd.width; + mbHeight = mbd.height; + } + } + if ((root.getWindowDecorationStyle() != JRootPane.NONE) + && (root.getUI() instanceof DarkRootPaneUI)) { + JComponent titlePane = ((DarkRootPaneUI) root.getUI()) + .getTitlePane(); + if (titlePane != null) { + tpd = titlePane.getMinimumSize(); + if (tpd != null) { + tpWidth = tpd.width; + tpHeight = tpd.height; + } + } + } + + return new Dimension(Math.max(Math.max(cpWidth, mbWidth), tpWidth) + + i.left + i.right, cpHeight + mbHeight + tpHeight + i.top + + i.bottom); + } + + public Dimension maximumLayoutSize(@NotNull final Container target) { + Dimension cpd, mbd, tpd; + int cpWidth = Integer.MAX_VALUE; + int cpHeight = Integer.MAX_VALUE; + int mbWidth = Integer.MAX_VALUE; + int mbHeight = Integer.MAX_VALUE; + int tpWidth = Integer.MAX_VALUE; + int tpHeight = Integer.MAX_VALUE; + Insets i = target.getInsets(); + JRootPane root = (JRootPane) target; + + if (root.getContentPane() != null) { + cpd = root.getContentPane().getMaximumSize(); + if (cpd != null) { + cpWidth = cpd.width; + cpHeight = cpd.height; + } + } + + if (root.getJMenuBar() != null) { + mbd = root.getJMenuBar().getMaximumSize(); + if (mbd != null) { + mbWidth = mbd.width; + mbHeight = mbd.height; + } + } + + if ((root.getWindowDecorationStyle() != JRootPane.NONE) + && (root.getUI() instanceof DarkRootPaneUI)) { + JComponent titlePane = ((DarkRootPaneUI) root.getUI()) + .getTitlePane(); + if (titlePane != null) { + tpd = titlePane.getMaximumSize(); + if (tpd != null) { + tpWidth = tpd.width; + tpHeight = tpd.height; + } + } + } + + int maxHeight = Math.max(Math.max(cpHeight, mbHeight), tpHeight); + if (maxHeight != Integer.MAX_VALUE) { + maxHeight = cpHeight + mbHeight + tpHeight + i.top + i.bottom; + } + + int maxWidth = Math.max(Math.max(cpWidth, mbWidth), tpWidth); + + if (maxWidth != Integer.MAX_VALUE) { + maxWidth += i.left + i.right; + } + + return new Dimension(maxWidth, maxHeight); + } + + public void layoutContainer(final Container parent) { + JRootPane root = (JRootPane) parent; + Rectangle b = root.getBounds(); + Insets i = root.getInsets(); + int nextY = 0; + int w = b.width - i.right - i.left; + int h = b.height - i.top - i.bottom; + + if (root.getLayeredPane() != null) { + root.getLayeredPane().setBounds(i.left, i.top, w, h); + } + if (root.getGlassPane() != null) { + root.getGlassPane().setBounds(i.left, i.top, w, h); + } + + if ((root.getWindowDecorationStyle() != JRootPane.NONE) + && (root.getUI() instanceof DarkRootPaneUI)) { + JComponent titlePane = ((DarkRootPaneUI) root.getUI()) + .getTitlePane(); + if (titlePane != null) { + Dimension tpd = titlePane.getPreferredSize(); + if (tpd != null) { + int tpHeight = tpd.height; + titlePane.setBounds(0, 0, w, tpHeight); + nextY += tpHeight; + } + } + } + if (root.getJMenuBar() != null) { + Dimension mbd = root.getJMenuBar().getPreferredSize(); + root.getJMenuBar().setBounds(0, nextY, w, mbd.height); + nextY += mbd.height; + } + if (root.getContentPane() != null) { + + root.getContentPane().setBounds(0, nextY, w, h < nextY ? 0 : h - nextY); + } + } + + public void addLayoutComponent(final String name, final Component comp) { + } + + public void removeLayoutComponent(final Component comp) { + } + + public void addLayoutComponent(final Component comp, final Object constraints) { + } + + public float getLayoutAlignmentX(final Container target) { + return 0.0f; + } + + public float getLayoutAlignmentY(final Container target) { + return 0.0f; + } + + public void invalidateLayout(final Container target) { + } +} diff --git a/src/main/java/com/weis/darklaf/util/DarkUIUtil.java b/src/main/java/com/weis/darklaf/util/DarkUIUtil.java index d51f41d7..467ebc65 100644 --- a/src/main/java/com/weis/darklaf/util/DarkUIUtil.java +++ b/src/main/java/com/weis/darklaf/util/DarkUIUtil.java @@ -160,6 +160,7 @@ public final class DarkUIUtil { return SwingUtilities.getWindowAncestor(owner) == w; } + @SuppressWarnings("unchecked") @Nullable public static T getParentOfType(final Class cls, final Component c) { for (Component eachParent = c; eachParent != null; eachParent = eachParent.getParent()) { diff --git a/src/main/resources/com/weis/darklaf/darcula.properties b/src/main/resources/com/weis/darklaf/darcula.properties index 1f4af6cb..0b9eca65 100644 --- a/src/main/resources/com/weis/darklaf/darcula.properties +++ b/src/main/resources/com/weis/darklaf/darcula.properties @@ -133,7 +133,7 @@ Panel.background = 3c3f41 #RootPane RootPaneUI = com.weis.darklaf.ui.rootpane.DarkRootPaneUI - +RootPane.background = 3c3f41 #OptionPane OptionPane.messageForeground = bbbbbb diff --git a/src/test/java/ColorChooserDemo.java b/src/test/java/ColorChooserDemo.java index 64255bd3..96dbbb0e 100644 --- a/src/test/java/ColorChooserDemo.java +++ b/src/test/java/ColorChooserDemo.java @@ -10,6 +10,7 @@ public final class ColorChooserDemo { LafManager.loadLaf(LafManager.Theme.Dark); JColorChooser.showDialog(null, "Color Chooser without transparency", Color.RED, true); +// JOptionPane.showMessageDialog(null, "This is a test!","THis is a test!", JOptionPane.ERROR_MESSAGE); }); } }