├── .gitignore
├── LICENSE
├── README.md
├── native
└── Win10
│ ├── Win10
│ └── blur_main.cpp
│ └── x64
│ └── Release
│ └── javafxblur.dll
├── pom.xml
├── res
├── example.gif
└── example2.gif
└── src
├── main
├── header
│ └── com_kieferlam_javafxblur_NativeBlur.h
└── java
│ └── com
│ └── kieferlam
│ └── javafxblur
│ ├── Blur.java
│ └── NativeBlur.java
└── test
└── java
└── PrimaryStageBlurTest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 | .idea
3 | *.iml
4 | target
5 | *.suo
6 | *.db
7 | *.sln
8 | *.vcxproj*
9 | *.tlog
10 | *.log
11 | *.obj
12 | *.exp
13 | *.lib
14 | *.iobj
15 | *.ipdb
16 | *.ipch
17 | out
18 | release
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Kiefer Lam
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JavaFX Blur
2 | This library provides methods to apply a blur effect to a JavaFX stage using JNI to call the native window manager functions.
3 |
4 |
5 |
6 |
7 | ## Install
8 | To install, simply add the jar file as a dependency on your favourite IDE (add jar to classpath) and add the library files (.dll) to the library path.
9 |
10 | ## Usage
11 | The module load method should be called at the start of your program to ensure the native functions have been loaded before the external function calls.
12 |
13 | ```java
14 | public static void main(String[] args){
15 | Blur.loadBlurLibrary();
16 | // Launch JavaFX application
17 | }
18 | ```
19 |
20 | Once your JavaFX stage is shown, you can call the blur method to apply the blur effect. The stage must be initialised as transparent (`StageStyle.TRANSPARENT`) or JavaFX will have an opaque window decoration background so the blur effect will not be visible.
21 |
22 | You might also need to set the backgrounds of the panes and scenes as transparent/none.
23 | ```java
24 | public void start(Stage primaryStage) {
25 | AnchorPane root = new AnchorPane();
26 | root.setBackground(Background.EMPTY);
27 |
28 | Scene scene = new Scene(root, 640.0, 480.0);
29 | scene.setFill(Color.TRANSPARENT);
30 |
31 | primaryStage.initStyle(StageStyle.TRANSPARENT);
32 |
33 | primaryStage.setScene(scene);
34 | primaryStage.show();
35 |
36 | // Blur effect must be called after the stage is visible
37 | Blur.applyBlur(primaryStage, Blur.ACRYLIC);
38 | }
39 | ```
40 |
41 | The second argument of `applyBlur(stage, blurType)` decides which method of blur should be used. The following blur types are available:
42 |
43 | - TRANSPARENT
44 | - No blur, the window background is just transparent.
45 | - BLUR_BEHIND
46 | - Slight blur behind window (see example image)
47 | - ACRYLIC
48 | - Windows acrylic blur. Stronger blur than `BLUR_BEHIND`.
49 |
50 | ## Compatibility
51 | So far, only the native functions for Windows 10 have been provided.
--------------------------------------------------------------------------------
/native/Win10/Win10/blur_main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "com_kieferlam_javafxblur_NativeBlur.h"
5 |
6 | std::string target = "";
7 | int targetAccentState = 0;
8 |
9 | void SetWindowBlur(HWND hWnd, int accentState)
10 | {
11 | const HINSTANCE hModule = LoadLibrary(TEXT("user32.dll"));
12 | if (hModule)
13 | {
14 | struct ACCENTPOLICY
15 | {
16 | int nAccentState;
17 | int nFlags;
18 | int nColor;
19 | int nAnimationId;
20 | };
21 | struct WINCOMPATTRDATA
22 | {
23 | int nAttribute;
24 | PVOID pData;
25 | ULONG ulDataSize;
26 | };
27 | typedef BOOL(WINAPI*pSetWindowCompositionAttribute)(HWND, WINCOMPATTRDATA*);
28 | const pSetWindowCompositionAttribute SetWindowCompositionAttribute = (pSetWindowCompositionAttribute)GetProcAddress(hModule, "SetWindowCompositionAttribute");
29 | if (SetWindowCompositionAttribute)
30 | {
31 | ACCENTPOLICY policy = { accentState, 0, 0x00FFFFFF, 0 }; // ACCENT_ENABLE_BLURBEHIND=3 / Colour in ARGB
32 | WINCOMPATTRDATA data = { 19, &policy, sizeof(ACCENTPOLICY) }; // WCA_ACCENT_POLICY=19
33 | SetWindowCompositionAttribute(hWnd, &data);
34 |
35 |
36 | }
37 | FreeLibrary(hModule);
38 | }
39 | }
40 | void enableBlur(HWND hWnd) {
41 | SetWindowBlur(hWnd, targetAccentState);
42 | }
43 |
44 | BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam)
45 | {
46 | char String[255];
47 |
48 | if (!hWnd)
49 | return TRUE; // Not a window
50 | if (!IsWindowVisible(hWnd))
51 | return TRUE; // Not visible
52 | if (!SendMessage(hWnd, WM_GETTEXT, sizeof(String), (LPARAM)String))
53 | return TRUE; // No window title
54 |
55 | char pszClassName[64];
56 | GetClassName(hWnd, pszClassName, 64);
57 | if (_stricmp(pszClassName, "shell_traywnd") && _stricmp(pszClassName, "progman")) {
58 | char windowTitle[64];
59 | GetWindowText(hWnd, windowTitle, 64);
60 | if (!target.compare(windowTitle)) {
61 | enableBlur(hWnd);
62 | }
63 | }
64 |
65 | return 1;
66 | }
67 |
68 |
69 | JNIEXPORT void JNICALL Java_com_kieferlam_javafxblur_NativeBlur__1extApplyBlur
70 | (JNIEnv *env, jobject, jstring title, jint accentState) {
71 |
72 | const jchar *nativeString = env->GetStringChars(title, 0);
73 | targetAccentState = (int)accentState;
74 |
75 | char chars[256];
76 |
77 | for (int i = 0; i < 256; ++i) {
78 | const jchar c = nativeString[i];
79 | if (c == 0) break;
80 | chars[i] = c;
81 | }
82 |
83 | std::string string(chars);
84 |
85 | target = string;
86 |
87 | EnumWindows(EnumWindowsProc, 0);
88 | }
--------------------------------------------------------------------------------
/native/Win10/x64/Release/javafxblur.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kieferlam/JavaFX-Blur/1cbc4e89dd8c203735e75a3851c7fe1284da2bfc/native/Win10/x64/Release/javafxblur.dll
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.kieferlam
8 | javafxblur
9 | 1.0-SNAPSHOT
10 |
11 |
12 | 1.8
13 | 1.8
14 | 11
15 | 13
16 |
17 |
18 |
19 |
20 | org.openjfx
21 | javafx-controls
22 | ${javafx.version}
23 |
24 |
25 |
26 |
27 |
28 | org.apache.maven.plugins
29 | maven-compiler-plugin
30 | 3.8.1
31 |
32 | ${maven.compiler.release}
33 |
34 |
35 |
36 | org.openjfx
37 | javafx-maven-plugin
38 | 0.0.3
39 |
40 | org.openjfx.App
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/res/example.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kieferlam/JavaFX-Blur/1cbc4e89dd8c203735e75a3851c7fe1284da2bfc/res/example.gif
--------------------------------------------------------------------------------
/res/example2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kieferlam/JavaFX-Blur/1cbc4e89dd8c203735e75a3851c7fe1284da2bfc/res/example2.gif
--------------------------------------------------------------------------------
/src/main/header/com_kieferlam_javafxblur_NativeBlur.h:
--------------------------------------------------------------------------------
1 | /* DO NOT EDIT THIS FILE - it is machine generated */
2 | #include
3 | /* Header for class com_kieferlam_javafxblur_NativeBlur */
4 |
5 | #ifndef _Included_com_kieferlam_javafxblur_NativeBlur
6 | #define _Included_com_kieferlam_javafxblur_NativeBlur
7 | #ifdef __cplusplus
8 | extern "C" {
9 | #endif
10 | /*
11 | * Class: com_kieferlam_javafxblur_NativeBlur
12 | * Method: _extApplyBlur
13 | * Signature: (Ljava/lang/String;I)V
14 | */
15 | JNIEXPORT void JNICALL Java_com_kieferlam_javafxblur_NativeBlur__1extApplyBlur
16 | (JNIEnv *, jobject, jstring, jint);
17 |
18 | #ifdef __cplusplus
19 | }
20 | #endif
21 | #endif
22 |
--------------------------------------------------------------------------------
/src/main/java/com/kieferlam/javafxblur/Blur.java:
--------------------------------------------------------------------------------
1 | package com.kieferlam.javafxblur;
2 |
3 | import javafx.stage.Stage;
4 |
5 | /**
6 | * Singleton handler enum class Blur.
7 | * This class provides global methods to load and apply blur effects to a JavaFX stage.
8 | */
9 | public enum Blur {
10 | NONE(0), BLUR_BEHIND(3), ACRYLIC(4);
11 | private final int accentState;
12 |
13 | Blur(int accentState) {
14 | this.accentState = accentState;
15 | }
16 |
17 | private static final String BLUR_TARGET_PREFIX = "_JFX";
18 | private static final NativeBlur _extBlur = new NativeBlur();
19 |
20 | /**
21 | * Loads the required blur library.
22 | * This should be called at the very start of your main function.
23 | * The "javafxblur" library file should be added to your library path.
24 | */
25 | public static void loadBlurLibrary(){
26 | System.loadLibrary("javafxblur");
27 | }
28 |
29 | private static void _extApplyBlur(String target, int accentState){
30 | _extBlur._extApplyBlur(target, accentState);
31 | }
32 |
33 | /**
34 | * Calls the external (native) function to apply the blur effect to a JavaFX stage.
35 | * The JavaFX stage must be visible before this function is called.
36 | * If the stage is ever hidden (destroyed, not minimised), this function must be called again once visible.
37 | * @param stage
38 | */
39 | public static void applyBlur(Stage stage, Blur blur){
40 | if (!stage.isShowing()) System.err.println("Warning: blur effect was called on a hidden stage!");
41 | String stageTitle = stage.getTitle();
42 | String targetTitle = BLUR_TARGET_PREFIX + (System.currentTimeMillis() % 1000);
43 | stage.setTitle(targetTitle);
44 | _extApplyBlur(targetTitle, blur.accentState);
45 | stage.setTitle(stageTitle);
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/com/kieferlam/javafxblur/NativeBlur.java:
--------------------------------------------------------------------------------
1 | package com.kieferlam.javafxblur;
2 |
3 | public class NativeBlur {
4 |
5 | protected NativeBlur(){}
6 |
7 | protected native void _extApplyBlur(String target, int accentState);
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/src/test/java/PrimaryStageBlurTest.java:
--------------------------------------------------------------------------------
1 | import com.kieferlam.javafxblur.Blur;
2 | import javafx.application.Application;
3 | import javafx.beans.property.SimpleStringProperty;
4 | import javafx.beans.property.StringProperty;
5 | import javafx.geometry.Insets;
6 | import javafx.geometry.Point2D;
7 | import javafx.scene.Scene;
8 | import javafx.scene.control.Button;
9 | import javafx.scene.input.MouseEvent;
10 | import javafx.scene.layout.*;
11 | import javafx.scene.paint.Color;
12 | import javafx.scene.text.Font;
13 | import javafx.scene.text.Text;
14 | import javafx.stage.Stage;
15 | import javafx.stage.StageStyle;
16 |
17 | import java.util.concurrent.atomic.AtomicReference;
18 |
19 | public class PrimaryStageBlurTest extends Application {
20 |
21 | public static final Color titleBarColour = new Color(Color.SLATEGREY.getRed(), Color.SLATEGREY.getGreen(), Color.SLATEGREY.getBlue(), 0.5);
22 | public static final Background titleBarBackground = new Background(new BackgroundFill(titleBarColour, CornerRadii.EMPTY, Insets.EMPTY));
23 | public static final Color highlightColour = new Color(Color.SLATEGREY.getRed(), Color.SLATEGREY.getGreen(), Color.SLATEGREY.getBlue(), 0.9);
24 | public static final Background highlightBackground = new Background(new BackgroundFill(highlightColour, CornerRadii.EMPTY, Insets.EMPTY));
25 | public static final Color textColor = Color.GHOSTWHITE;
26 |
27 | public static void main(String[] args) {
28 | Blur.loadBlurLibrary();
29 | launch(args);
30 | }
31 |
32 | public static Pane createTitleBar(Stage primaryStage, StringProperty titleProperty) {
33 | AnchorPane titlebar = new AnchorPane();
34 |
35 | titlebar.setBackground(titleBarBackground);
36 |
37 | Text titleText = new Text(0, 0, titleProperty.getValue());
38 | titleText.textProperty().bind(titleProperty);
39 | titleText.setFill(textColor);
40 | titleText.setFont(new Font(14.0));
41 | HBox titleTextContainer = new HBox();
42 | titleTextContainer.getChildren().add(titleText);
43 |
44 | HBox titlebarControls = new HBox();
45 | Button minBtn = new Button("Min");
46 | minBtn.setBackground(titleBarBackground);
47 | Button maxBtn = new Button("Max");
48 | maxBtn.setBackground(titleBarBackground);
49 | Button closeBtn = new Button("Close");
50 | closeBtn.setBackground(titleBarBackground);
51 |
52 | closeBtn.setOnAction(event -> primaryStage.close());
53 |
54 | titlebarControls.getChildren().addAll(minBtn, maxBtn, closeBtn);
55 | titlebarControls.getChildren().forEach(node -> {
56 | ((Button)node).setTextFill(textColor);
57 | node.addEventHandler(MouseEvent.MOUSE_ENTERED, mouseEvent -> ((Button) node).setBackground(highlightBackground));
58 | node.addEventHandler(MouseEvent.MOUSE_EXITED, mouseEvent -> ((Button) node).setBackground(titleBarBackground));
59 | });
60 |
61 | titlebar.getChildren().add(titleTextContainer);
62 | titlebar.getChildren().add(titlebarControls);
63 |
64 | AtomicReference stageDragOffset = new AtomicReference<>(new Point2D(0.0, 0.0));
65 | titlebar.addEventHandler(MouseEvent.MOUSE_PRESSED, mouseEvent -> stageDragOffset.set(new Point2D(mouseEvent.getSceneX(), mouseEvent.getSceneY())));
66 | titlebar.addEventHandler(MouseEvent.MOUSE_DRAGGED, mouseEvent ->{
67 | primaryStage.setX(mouseEvent.getScreenX() - stageDragOffset.get().getX());
68 | primaryStage.setY(mouseEvent.getScreenY() - stageDragOffset.get().getY());
69 | });
70 |
71 | AnchorPane.setLeftAnchor(titleTextContainer, 5.0);
72 | AnchorPane.setRightAnchor(titlebarControls, 0.0);
73 |
74 | return titlebar;
75 | }
76 |
77 | public static Pane createContentPane(Stage primaryStage){
78 | BorderPane pane = new BorderPane();
79 |
80 | pane.setBackground(new Background(new BackgroundFill(Color.gray(0.2, 0.5), CornerRadii.EMPTY, Insets.EMPTY)));
81 |
82 | Text content = new Text("Content");
83 | content.setFont(new Font(72.0));
84 | content.setFill(textColor);
85 |
86 | pane.setCenter(content);
87 |
88 | pane.prefWidthProperty().bind(primaryStage.widthProperty());
89 | pane.prefHeightProperty().bind(primaryStage.heightProperty());
90 |
91 | return pane;
92 | }
93 |
94 | public void start(Stage primaryStage) {
95 | Pane titlebar = createTitleBar(primaryStage, new SimpleStringProperty("JavaFX Blur Test"));
96 |
97 | Pane contentPane = createContentPane(primaryStage);
98 |
99 | AnchorPane root = new AnchorPane();
100 | root.getChildren().addAll(titlebar, contentPane);
101 | AnchorPane.setTopAnchor(titlebar, 0.0);
102 | AnchorPane.setTopAnchor(contentPane, 24.0);
103 |
104 | root.setBackground(Background.EMPTY);
105 | Scene scene = new Scene(root, 640.0, 480.0);
106 | scene.setFill(Color.TRANSPARENT);
107 |
108 | titlebar.prefWidthProperty().bind(scene.widthProperty());
109 | titlebar.prefHeight(24.0);
110 |
111 | primaryStage.initStyle(StageStyle.TRANSPARENT);
112 | primaryStage.setTitle("JavaFX");
113 |
114 | primaryStage.setScene(scene);
115 | primaryStage.show();
116 |
117 | Blur.applyBlur(primaryStage, Blur.ACRYLIC);
118 | }
119 | }
120 |
--------------------------------------------------------------------------------