Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -60,6 +60,9 @@ public final class MouseEventFirer {
public MouseEventFirer(EventTarget target) {
this.target = target;

// Use the alternative creation path for MouseEvent by default, see JDK-8253769
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the alternative path is made the default then this class needs some cleanup. That can be done as part of JDK-8253769. Request you to add a comment in JBS on JDK-8253769 to clean up the unused portion of MouseEventFirer.java

this.alternative = true;

// Force the target node onto a stage so that it is accessible
if (target instanceof Node) {
Node n = (Node)target;
Expand Down
22 changes: 18 additions & 4 deletions modules/javafx.graphics/src/main/java/javafx/scene/Scene.java
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,18 @@ private Scene(Parent root, double width, double height, Paint fill,
setRoot(root);
init(width, height);
setFill(fill);

// Any mouse or touch press on the scene will clear the focusVisible flag of
// the current focus owner, if there is one.
EventHandler<InputEvent> pressedHandler = event -> {
Node focusOwner = getFocusOwner();
if (focusOwner != null) {
getKeyHandler().setFocusVisible(focusOwner, false);
}
};

addEventFilter(MouseEvent.MOUSE_PRESSED, pressedHandler);
addEventFilter(TouchEvent.TOUCH_PRESSED, pressedHandler);
}

static {
Expand Down Expand Up @@ -4036,7 +4048,9 @@ private PickResult pickNode(PickRay pickRay) {
class KeyHandler {
boolean focusVisible;

private void setFocusOwner(final Node value) {
private void setFocusOwner(Node value, boolean focusVisible) {
this.focusVisible = focusVisible;

// Cancel IM composition if there is one in progress.
// This needs to be done before the focus owner is switched as it
// generates event that needs to be delivered to the old focus owner.
Expand All @@ -4053,6 +4067,7 @@ private void setFocusOwner(final Node value) {
}

private void setFocusVisible(Node node, boolean focusVisible) {
this.focusVisible = focusVisible;
node.focusVisible.set(focusVisible);
node.focusVisible.notifyListeners();
}
Expand Down Expand Up @@ -4100,11 +4115,10 @@ private void process(KeyEvent e) {

private void requestFocus(Node node, boolean focusVisible) {
if (node == null) {
setFocusOwner(null);
setFocusOwner(null, false);
} else if (node.isCanReceiveFocus()) {
if (node != getFocusOwner()) {
this.focusVisible = focusVisible;
setFocusOwner(node);
setFocusOwner(node, focusVisible);
} else {
setFocusVisible(node, focusVisible);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

import com.sun.javafx.scene.SceneHelper;
import javafx.event.Event;
import javafx.event.EventTarget;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import test.com.sun.javafx.pgstub.StubScene;
Expand All @@ -41,6 +42,7 @@
import static org.junit.Assert.fail;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javafx.scene.Group;
Expand All @@ -49,6 +51,11 @@
import javafx.scene.Scene;
import javafx.scene.SceneShim;

import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.PickResult;
import javafx.scene.input.TouchEvent;
import javafx.scene.input.TouchPoint;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

Expand Down Expand Up @@ -775,6 +782,25 @@ private void fireTabKeyEvent(Node node) {
Event.fireEvent(node, new KeyEvent(KeyEvent.KEY_RELEASED, null, null, KeyCode.TAB, false, false, false, false));
}

private void fireMousePressedEvent(EventTarget target) {
double x = 10, y = 10;
PickResult pickResult = new PickResult(target, x, y);
Event.fireEvent(target, new MouseEvent(
MouseEvent.MOUSE_PRESSED, x, y, x, y, MouseButton.PRIMARY, 1,
false, false, false, false,
true, false, false,
false, false, false, pickResult));
}

private void fireTouchPressedEvent(EventTarget target) {
double x = 10, y = 10;
PickResult pickResult = new PickResult(scene, x, y);
Event.fireEvent(target, new TouchEvent(
TouchEvent.TOUCH_PRESSED,
new TouchPoint(0, TouchPoint.State.PRESSED, x, y, x, y, target, pickResult),
Collections.emptyList(), 0, false, false, false, false));
}

/**
* If a node acquires focus by calling {@link Node#requestFocus()}, it does not acquire visible focus.
*/
Expand Down Expand Up @@ -848,6 +874,44 @@ private void fireTabKeyEvent(Node node) {
assertNotFocusVisible(node2);
}

/**
* When any region of the window is clicked, the focus owner loses visible focus
* even when the focus owner doesn't change.
*/
@Test public void testMousePressedClearsFocusVisible() {
Node node1 = n(), node2 = n();
Group g = new Group(node1, node2);
scene.setRoot(g);
fireTabKeyEvent(g);

assertIsFocused(scene, node1);
assertIsFocusVisible(node1);

fireMousePressedEvent(scene);

assertIsFocused(scene, node1);
assertNotFocusVisible(node1);
}

/**
* When any region of the window is touched, the focus owner loses visible focus
* even when the focus owner doesn't change.
*/
@Test public void testTouchPressedClearsFocusVisible() {
Node node1 = n(), node2 = n();
Group g = new Group(node1, node2);
scene.setRoot(g);
fireTabKeyEvent(g);

assertIsFocused(scene, node1);
assertIsFocusVisible(node1);

fireTouchPressedEvent(scene);

assertIsFocused(scene, node1);
assertNotFocusVisible(node1);
}

/**
* When a node acquires focus, the focusWithin property is set on the node
* and all of its parents.
Expand Down