Skip to content
Open
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
Expand Up @@ -296,6 +296,8 @@ public interface FlatClientProperties
* and should therefore return quickly.
* <li>This function is invoked on 'AWT-Windows' thread (not 'AWT-EventQueue' thread)
* while processing Windows messages.
* On macOS in fullWindowContent mode (since 3.7.2), it is invoked on the AppKit
* main thread before the mouse event is dispatched to AWT.
* It <b>must not</b> change any component property or layout because this could cause a dead lock.
* </ul>
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
*/
public class FlatNativeMacLibrary
{
private static int API_VERSION_MACOS = 2004;
private static int API_VERSION_MACOS = 2005;

/**
* Checks whether native library is loaded/available.
Expand All @@ -71,6 +71,41 @@ public static boolean isLoaded() {
/** @since 3.4 */ public native static boolean isWindowFullScreen( Window window );
/** @since 3.4 */ public native static boolean toggleWindowFullScreen( Window window );

/**
* Registers a hit-test callback used to decide whether a left mouse down event
* in a fullWindowContent macOS window's title bar area should start a native
* window drag instead of being delivered to AWT.
* <p>
* The window must already use {@code apple.awt.fullWindowContent=true}.
* Passing the same window twice replaces the previously registered callback.
*
* @since 3.7.2
*/
public native static boolean setupFullWindowContentTitleBarCaption( Window window, FullWindowContentTitleBarCaptionCallback callback );

/**
* Removes the callback previously installed with
* {@link #setupFullWindowContentTitleBarCaption(Window, FullWindowContentTitleBarCaptionCallback)}.
*
* @since 3.7.2
*/
public native static boolean removeFullWindowContentTitleBarCaption( Window window );

/** @since 3.7.2 */
public interface FullWindowContentTitleBarCaptionCallback {
/**
* Invoked on the AppKit main thread (not the AWT event dispatching thread)
* before the mouse event is dispatched to AWT.
* It <b>must not</b> change any component property or layout because this could cause a dead lock.
*
* @param x x coordinate in AWT window coordinates (origin top-left)
* @param y y coordinate in AWT window coordinates (origin top-left)
* @return {@code true} if the location should behave as title bar caption
* (i.e. start a native window drag instead of being delivered to AWT)
*/
boolean isTitleBarCaptionAt( int x, int y );
}


/** @since 3.7 */
public static final int
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,11 @@ protected void uninstallDefaults( JRootPane c ) {
protected void installListeners( JRootPane root ) {
super.installListeners( root );

if( SystemInfo.isMacFullWindowContentSupported )
if( SystemInfo.isMacFullWindowContentSupported ) {
macFullWindowContentListener = FullWindowContentSupport.macInstallListeners( root );
if( FlatClientProperties.clientPropertyBoolean( root, "apple.awt.fullWindowContent", false ) )
FullWindowContentSupport.macInstallTitleBarCaption( root );
}
macInstallWindowBackgroundListener( root );
}

Expand All @@ -210,6 +213,7 @@ protected void uninstallListeners( JRootPane root ) {

if( SystemInfo.isMacFullWindowContentSupported ) {
FullWindowContentSupport.macUninstallListeners( root, macFullWindowContentListener );
FullWindowContentSupport.macUninstallTitleBarCaption( root );
macFullWindowContentListener = null;
}
macUninstallWindowBackgroundListener( root );
Expand Down Expand Up @@ -536,17 +540,27 @@ public void propertyChange( PropertyChangeEvent e ) {
// "apple.awt.fullWindowContent" or FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING
// is usually done before the native window is created
// --> try again when native window is created
if( e.getNewValue() instanceof Window )
if( e.getNewValue() instanceof Window ) {
macInstallFullWindowContentSupport();
// title bar caption support also requires a native window
if( SystemInfo.isMacFullWindowContentSupported &&
FlatClientProperties.clientPropertyBoolean( rootPane, "apple.awt.fullWindowContent", false ) )
FullWindowContentSupport.macInstallTitleBarCaption( rootPane );
}
break;

case FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING:
macInstallFullWindowContentSupport();
break;

case "apple.awt.fullWindowContent":
if( SystemInfo.isMacFullWindowContentSupported )
if( SystemInfo.isMacFullWindowContentSupported ) {
FullWindowContentSupport.macUpdateFullWindowContentButtonsBoundsProperty( rootPane );
if( FlatClientProperties.clientPropertyBoolean( rootPane, "apple.awt.fullWindowContent", false ) )
FullWindowContentSupport.macInstallTitleBarCaption( rootPane );
else
FullWindowContentSupport.macUninstallTitleBarCaption( rootPane );
}
break;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
import java.beans.PropertyChangeListener;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import javax.accessibility.AccessibleContext;
import javax.swing.BorderFactory;
import javax.swing.Box;
Expand All @@ -65,7 +64,6 @@
import javax.swing.UIManager;
import javax.swing.border.AbstractBorder;
import javax.swing.border.Border;
import javax.swing.plaf.ComponentUI;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatSystemProperties;
import com.formdev.flatlaf.ui.FlatNativeWindowBorder.WindowTopBorder;
Expand Down Expand Up @@ -1145,77 +1143,7 @@ private boolean captionHitTest( Point pt ) {
}

private boolean isTitleBarCaptionAt( Component c, int x, int y ) {
if( !c.isDisplayable() || !c.isVisible() || !contains( c, x, y ) || c == mouseLayer )
return true; // continue checking with next component

// check enabled component that has mouse listeners
if( c.isEnabled() &&
(c.getMouseListeners().length > 0 ||
c.getMouseMotionListeners().length > 0) )
{
if( !(c instanceof JComponent) )
return false; // assume that this is not a caption because the component has mouse listeners

// check client property boolean value
Object caption = ((JComponent)c).getClientProperty( COMPONENT_TITLE_BAR_CAPTION );
if( caption instanceof Boolean )
return (boolean) caption;

// if component is not fully layouted, do not invoke function
// because it is too dangerous that the function tries to layout the component,
// which could cause a dead lock
if( !c.isValid() ) {
// revalidate if necessary so that it is valid when invoked again later
EventQueue.invokeLater( () -> {
Window w = SwingUtilities.windowForComponent( c );
if( w != null )
w.revalidate();
else
c.revalidate();
} );

return false; // assume that this is not a caption because the component has mouse listeners
}

if( caption instanceof Function ) {
// check client property function value
@SuppressWarnings( "unchecked" )
Function<Point, Boolean> hitTest = (Function<Point, Boolean>) caption;
Boolean result = hitTest.apply( new Point( x, y ) );
if( result != null )
return result;
} else {
// check component UI
ComponentUI ui = JavaCompatibility2.getUI( (JComponent) c );
if( !(ui instanceof TitleBarCaptionHitTest) )
return false; // assume that this is not a caption because the component has mouse listeners

Boolean result = ((TitleBarCaptionHitTest)ui).isTitleBarCaptionAt( x, y );
if( result != null )
return result;
}

// else continue checking children
}

// check children
if( c instanceof Container ) {
for( Component child : ((Container)c).getComponents() ) {
if( !isTitleBarCaptionAt( child, x - child.getX(), y - child.getY() ) )
return false;
}
}
return true;
}

/**
* Same as {@link Component#contains(int, int)}, but not using that method
* because it may be overridden by custom components and invoke code that
* tries to request AWT tree lock on 'AWT-Windows' thread.
* This could freeze the application if AWT tree is already locked on 'AWT-EventQueue' thread.
*/
private boolean contains( Component c, int x, int y ) {
return x >= 0 && y >= 0 && x < c.getWidth() && y < c.getHeight();
return FullWindowContentSupport.isTitleBarCaptionAt( c, x, y, mouseLayer );
}

private int lastCaptionHitTestX;
Expand Down
Loading