mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-13 15:27:16 -06:00
Linux: use X11 window manager events to move window and to show window menu (right-click on window title bar), if custom window decorations are enabled (issue #482)
This commit is contained in:
@@ -56,6 +56,10 @@ class FlatNativeLibrary
|
||||
|
||||
// load jawt native library
|
||||
loadJAWT();
|
||||
} else if( SystemInfo.isLinux && SystemInfo.isX86_64 ) {
|
||||
// Linux: requires x86_64
|
||||
|
||||
libraryName = "flatlaf-linux-x86_64";
|
||||
} else
|
||||
return; // no native library available for current OS or CPU architecture
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2022 FormDev Software GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JFrame;
|
||||
|
||||
/**
|
||||
* Native methods for Linux.
|
||||
* <p>
|
||||
* <b>Note</b>: This is private API. Do not use!
|
||||
*
|
||||
* @author Karl Tauber
|
||||
* @since 2.5
|
||||
*/
|
||||
class FlatNativeLinuxLibrary
|
||||
{
|
||||
static boolean isLoaded() {
|
||||
return FlatNativeLibrary.isLoaded();
|
||||
}
|
||||
|
||||
// direction for _NET_WM_MOVERESIZE message
|
||||
// see https://specifications.freedesktop.org/wm-spec/wm-spec-latest.html
|
||||
static final int MOVE = 8;
|
||||
|
||||
private static Boolean isXWindowSystem;
|
||||
|
||||
private static boolean isXWindowSystem() {
|
||||
if( isXWindowSystem == null )
|
||||
isXWindowSystem = Toolkit.getDefaultToolkit().getClass().getName().endsWith( ".XToolkit" );
|
||||
return isXWindowSystem;
|
||||
}
|
||||
|
||||
static boolean isWMUtilsSupported( Window window ) {
|
||||
return hasCustomDecoration( window ) && isXWindowSystem() && isLoaded();
|
||||
}
|
||||
|
||||
static boolean moveOrResizeWindow( Window window, MouseEvent e, int direction ) {
|
||||
Point pt = scale( window, e.getLocationOnScreen() );
|
||||
return xMoveOrResizeWindow( window, pt.x, pt.y, direction );
|
||||
|
||||
/*
|
||||
try {
|
||||
Class<?> cls = Class.forName( "com.formdev.flatlaf.natives.jna.linux.X11WmUtils" );
|
||||
java.lang.reflect.Method m = cls.getMethod( "xMoveOrResizeWindow", Window.class, int.class, int.class, int.class );
|
||||
return (Boolean) m.invoke( null, window, pt.x, pt.y, direction );
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
static boolean showWindowMenu( Window window, MouseEvent e ) {
|
||||
Point pt = scale( window, e.getLocationOnScreen() );
|
||||
return xShowWindowMenu( window, pt.x, pt.y );
|
||||
|
||||
/*
|
||||
try {
|
||||
Class<?> cls = Class.forName( "com.formdev.flatlaf.natives.jna.linux.X11WmUtils" );
|
||||
java.lang.reflect.Method m = cls.getMethod( "xShowWindowMenu", Window.class, int.class, int.class );
|
||||
return (Boolean) m.invoke( null, window, pt.x, pt.y );
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
private static Point scale( Window window, Point pt ) {
|
||||
AffineTransform transform = window.getGraphicsConfiguration().getDefaultTransform();
|
||||
int x = (int) Math.round( pt.x * transform.getScaleX() );
|
||||
int y = (int) Math.round( pt.y * transform.getScaleY() );
|
||||
return new Point( x, y );
|
||||
}
|
||||
|
||||
// X Window System
|
||||
private static native boolean xMoveOrResizeWindow( Window window, int x, int y, int direction );
|
||||
private static native boolean xShowWindowMenu( Window window, int x, int y );
|
||||
|
||||
private static boolean hasCustomDecoration( Window window ) {
|
||||
return (window instanceof JFrame && JFrame.isDefaultLookAndFeelDecorated() && ((JFrame)window).isUndecorated()) ||
|
||||
(window instanceof JDialog && JDialog.isDefaultLookAndFeelDecorated() && ((JDialog)window).isUndecorated());
|
||||
}
|
||||
}
|
||||
@@ -357,6 +357,7 @@ public class FlatTitlePane
|
||||
restoreButton.setVisible( resizable && maximized );
|
||||
|
||||
if( maximized &&
|
||||
!(SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window )) &&
|
||||
rootPane.getClientProperty( "_flatlaf.maximizedBoundsUpToDate" ) == null )
|
||||
{
|
||||
rootPane.putClientProperty( "_flatlaf.maximizedBoundsUpToDate", null );
|
||||
@@ -737,6 +738,17 @@ debug*/
|
||||
}
|
||||
}
|
||||
|
||||
private void maximizeOrRestore() {
|
||||
if( !(window instanceof Frame) || !((Frame)window).isResizable() )
|
||||
return;
|
||||
|
||||
Frame frame = (Frame) window;
|
||||
if( (frame.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0 )
|
||||
restore();
|
||||
else
|
||||
maximize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the window.
|
||||
*/
|
||||
@@ -1154,23 +1166,23 @@ debug*/
|
||||
//---- interface MouseListener ----
|
||||
|
||||
private Point dragOffset;
|
||||
private boolean nativeMove;
|
||||
|
||||
@Override
|
||||
public void mouseClicked( MouseEvent e ) {
|
||||
// on Linux, when using native library, the mouse clicked event
|
||||
// is usually not sent and maximize/restore is done in mouse pressed event
|
||||
// this check is here for the case that a mouse clicked event comes thru for some reason
|
||||
if( SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window ) )
|
||||
return;
|
||||
|
||||
if( e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton( e ) ) {
|
||||
if( e.getSource() == iconLabel ) {
|
||||
// double-click on icon closes window
|
||||
close();
|
||||
} else if( !hasNativeCustomDecoration() &&
|
||||
window instanceof Frame &&
|
||||
((Frame)window).isResizable() )
|
||||
{
|
||||
} else if( !hasNativeCustomDecoration() ) {
|
||||
// maximize/restore on double-click
|
||||
Frame frame = (Frame) window;
|
||||
if( (frame.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0 )
|
||||
restore();
|
||||
else
|
||||
maximize();
|
||||
maximizeOrRestore();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1180,10 +1192,37 @@ debug*/
|
||||
if( window == null )
|
||||
return; // should newer occur
|
||||
|
||||
// on Linux, show window menu
|
||||
if( SwingUtilities.isRightMouseButton( e ) &&
|
||||
SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window ) )
|
||||
{
|
||||
e.consume();
|
||||
FlatNativeLinuxLibrary.showWindowMenu( window, e );
|
||||
return;
|
||||
}
|
||||
|
||||
if( !SwingUtilities.isLeftMouseButton( e ) )
|
||||
return;
|
||||
|
||||
dragOffset = SwingUtilities.convertPoint( FlatTitlePane.this, e.getPoint(), window );
|
||||
nativeMove = false;
|
||||
|
||||
// on Linux, move or maximize/restore window
|
||||
if( SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window ) ) {
|
||||
switch( e.getClickCount() ) {
|
||||
case 1:
|
||||
// move window via _NET_WM_MOVERESIZE event
|
||||
e.consume();
|
||||
nativeMove = FlatNativeLinuxLibrary.moveOrResizeWindow( window, e, FlatNativeLinuxLibrary.MOVE );
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// maximize/restore on double-click
|
||||
// also done here because no mouse clicked event is sent when using _NET_WM_MOVERESIZE event
|
||||
maximizeOrRestore();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void mouseReleased( MouseEvent e ) {}
|
||||
@@ -1194,9 +1233,12 @@ debug*/
|
||||
|
||||
@Override
|
||||
public void mouseDragged( MouseEvent e ) {
|
||||
if( window == null )
|
||||
if( window == null || dragOffset == null )
|
||||
return; // should newer occur
|
||||
|
||||
if( nativeMove )
|
||||
return;
|
||||
|
||||
if( !SwingUtilities.isLeftMouseButton( e ) )
|
||||
return;
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ public class NativeLibrary
|
||||
System.load( libraryFile.getAbsolutePath() );
|
||||
return true;
|
||||
} catch( Throwable ex ) {
|
||||
log( null, ex );
|
||||
log( ex.getMessage(), ex );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user