All Downloads are FREE. Search and download functionalities are using the official Maven repository.

VAqua.src.org.violetlib.aqua.AquaRootPaneUI Maven / Gradle / Ivy

The newest version!
/*
 * Changes Copyright (c) 2015-2023 Alan Snyder.
 * All rights reserved.
 *
 * You may not use, copy or modify this file, except in compliance with the license agreement. For details see
 * accompanying license terms.
 */

/*
 * Copyright (c) 2011, 2012, 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
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package org.violetlib.aqua;

import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.MenuBarUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicRootPaneUI;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import static org.violetlib.aqua.AquaVibrantSupport.NO_VIBRANT_STYLE;
import static org.violetlib.aqua.AquaVibrantSupport.WINDOW_BACKGROUND_STYLE;

public class AquaRootPaneUI extends BasicRootPaneUI implements AquaComponentUI,
        SystemPropertyChangeManager.SystemPropertyChangeListener {

    public final static String AQUA_WINDOW_STYLE_KEY = "Aqua.windowStyle";
    public final static String AQUA_WINDOW_TOP_MARGIN_KEY = "Aqua.windowTopMargin";
    public final static String AQUA_WINDOW_BOTTOM_MARGIN_KEY = "Aqua.windowBottomMargin";
    public final static String AQUA_WINDOW_REPRESENTED_FILENAME_KEY = "Aqua.windowRepresentedFilename";

    // Internally, an appearance is represented by an instance of AquaAppearance.
    // Externally, the colors are made available as a map from string to color.

    static final boolean sUseScreenMenuBar = AquaUtils.getScreenMenuBarProperty();

    public static ComponentUI createUI(JComponent c)
    {
        return new AquaRootPaneUI();
    }

    private static boolean forceActiveWindowDisplay;

    protected JRootPane rootPane;
    protected WindowHierarchyListener hierarchyListener;
    protected AncestorListener ancestorListener;
    protected PropertyChangeListener windowStylePropertyChangeListener;
    protected WindowListener windowListener;
    protected ContainerListener containerListener;
    protected boolean isInitialized;
    protected AquaCustomStyledWindow customStyledWindow;
    protected int vibrantStyle = NO_VIBRANT_STYLE;
    protected boolean vibrantStyleIsExplicitlySet;

    /**
     Set the debugging option to force all windows to display as active. Used to compare a Java window with a native
     active window.
     */
    public static void setForceActiveWindowDisplay(boolean b)
    {
        if (b != forceActiveWindowDisplay) {
            forceActiveWindowDisplay = b;
            Window[] windows = Window.getWindows();
            for (Window w : windows) {
                JRootPane rp = AquaUtils.getRootPane(w);
                if (rp != null) {
                    AquaRootPaneUI ui = AquaUtils.getUI(rp, AquaRootPaneUI.class);
                    if (ui != null) {
                        boolean shouldBeActive = b || w.isActive();
                        boolean isActiveStyle = Boolean.TRUE.equals(rp.getClientProperty(AquaFocusHandler.FRAME_ACTIVE_PROPERTY));
                        if (shouldBeActive != isActiveStyle) {
                            rp.repaint();
                            AquaFocusHandler.updateComponentTreeUIActivation(rp, shouldBeActive);
                        }
                    }
                }
            }
        }
    }

    public void installUI(JComponent c)
    {
        rootPane = (JRootPane) c;

        super.installUI(c);

        // for  OutOfMemoryError swapping menus.
        // Listen for layered pane/JMenuBar updates if the screen menu bar is active.
        if (sUseScreenMenuBar) {
            containerListener = new MyContainerListener();
            JRootPane root = (JRootPane) c;
            root.addContainerListener(containerListener);
        }

        configureWindowIfPossible();
        configureLayeredPane();
        configure();
    }

    public void uninstallUI(JComponent c)
    {
        c.removeAncestorListener(ancestorListener);
        disposeCustomWindowStyle();
        removeVisualEffectView();
        unconfigureLayeredPane();

        if (sUseScreenMenuBar) {
            JRootPane root = (JRootPane) c;
            root.removeContainerListener(containerListener);
            containerListener = null;
        }

        isInitialized = false;
        vibrantStyle = NO_VIBRANT_STYLE;
        vibrantStyleIsExplicitlySet = false;

        super.uninstallUI(c);
    }

    @Override
    protected void installListeners(JRootPane root)
    {
        super.installListeners(root);
        hierarchyListener = new WindowHierarchyListener();
        root.addHierarchyListener(hierarchyListener);
        AquaAppearances.register(root);
        ancestorListener = new MyAncestorListener();
        root.addAncestorListener(ancestorListener);
        windowListener = new MyWindowListener();
        AppearanceManager.installListeners(root);
    }

    @Override
    protected void uninstallListeners(JRootPane root)
    {
        AppearanceManager.uninstallListeners(root);
        AquaAppearances.unregister(root);
        root.removeHierarchyListener(hierarchyListener);
        hierarchyListener = null;
        root.removeAncestorListener(ancestorListener);
        ancestorListener = null;
        Window w = getWindow();
        if (w != null) {
            w.removeWindowListener(windowListener);
        }
        windowListener = null;
        super.uninstallListeners(root);
        if (windowStylePropertyChangeListener != null) {
            root.removePropertyChangeListener(windowStylePropertyChangeListener);
            windowStylePropertyChangeListener = null;
        }
    }

    @Override
    public void systemPropertyChanged(JComponent c, Object type) {
        if (type.equals(AquaAppearances.APPEARANCE_CHANGE_TYPE)) {
            updateAppearances(null, false);
        }
    }

    private class MyContainerListener
            implements ContainerListener
    {

        /**
         If the screen menu bar is active we need to listen to the layered pane of the root pane
         because it holds the JMenuBar.  So, if a new layered pane was added, listen to it.
         If a new JMenuBar was added, tell the menu bar UI, because it will need to update the menu bar.
         */
        public void componentAdded(ContainerEvent e)
        {
            if (e.getContainer() instanceof JRootPane) {
                JRootPane root = (JRootPane) e.getContainer();
                if (e.getChild() == root.getLayeredPane()) {
                    configureLayeredPane();
                }
            } else {
                if (e.getChild() instanceof JMenuBar) {
                    JMenuBar jmb = (JMenuBar) e.getChild();
                    MenuBarUI mbui = jmb.getUI();

                    if (mbui.getClass().getName().equals("com.apple.laf.AquaMenuBarUI")) {
                        Window owningWindow = SwingUtilities.getWindowAncestor(jmb);

                        // Could be a JDialog, and may have been added to a JRootPane not yet in a window.
                        if (owningWindow instanceof JFrame) {
                            JFrame fr = (JFrame) owningWindow;
                            AquaUtils.setScreenMenuBar(fr, mbui);
                        }
                    }
                }
            }
        }

        /**
         Likewise, when the layered pane is removed from the root pane, stop listening to it.
         If the JMenuBar is removed, tell the menu bar UI to clear the menu bar.
         */
        public void componentRemoved(ContainerEvent e)
        {
            if (e.getContainer() instanceof JRootPane) {
                JRootPane root = (JRootPane) e.getContainer();
                if (e.getChild() == root.getLayeredPane()) {
                    unconfigureLayeredPane();
                }
            } else {
                if (e.getChild() instanceof JMenuBar) {
                    JMenuBar jmb = (JMenuBar) e.getChild();
                    MenuBarUI mbui = jmb.getUI();

                    if (mbui.getClass().getName().equals("com.apple.laf.AquaMenuBarUI")) {
                        Window owningWindow = SwingUtilities.getWindowAncestor(jmb);

                        // Could be a JDialog, and may have been added to a JRootPane not yet in a window.
                        if (owningWindow instanceof JFrame) {
                            JFrame fr = (JFrame) owningWindow;
                            AquaUtils.clearScreenMenuBar(fr, mbui);
                        }
                    }
                }
            }
        }
    }

    /**
     Invoked when a property changes on the root pane.
     */
    public void propertyChange(PropertyChangeEvent e)
    {
        super.propertyChange(e);

        String prop = e.getPropertyName();
        if (AquaVibrantSupport.BACKGROUND_STYLE_KEY.equals(prop)) {
            Object o = e.getNewValue();
            updateVibrantStyleFromProperty(o);
        } else if (AQUA_WINDOW_STYLE_KEY.equals(prop) || AQUA_WINDOW_TOP_MARGIN_KEY.equals(prop) || AQUA_WINDOW_BOTTOM_MARGIN_KEY.equals(prop)) {
            reconfigureCustomWindowStyle();
        } else if (AQUA_WINDOW_REPRESENTED_FILENAME_KEY.equals(prop)) {
            configureRepresentedFilename();
        } else if ("ancestor".equals(prop)) {
            Component parent = rootPane.getParent();
            if (parent instanceof Window) {
                Window w = (Window) parent;
                KeyWindowPatch.applyPatchIfNeeded(w);
            }
        } else if (AppearanceManager.AQUA_APPEARANCE_NAME_KEY.equals(prop)) {
            configureSpecifiedWindowAppearance(true);
        }
    }

    protected class MyAncestorListener
            implements AncestorListener
    {
        /**
         This is sort of like viewDidMoveToWindow:.  When the root pane is put into a window
         this method gets called for the notification.
         We need to set up the listener relationship so we can pick up activation events.
         And, if a JMenuBar was added before the root pane was added to the window, we now need
         to notify the menu bar UI.
         */
        public void ancestorAdded(AncestorEvent event)
        {
            // this is so we can handle window activated and deactivated events so
            // our swing controls can color/enable/disable/focus draw correctly

            Window w = getWindow();
            if (w != null) {
                // We get this message even when a dialog is opened and the owning window is a window
                // that could already be listened to. We should only be a listener once.
                w.removeWindowListener(windowListener);
                w.addWindowListener(windowListener);
            }
        }

        /**
         If the JRootPane was removed from the window we should clear the screen menu bar.
         That's a non-trivial problem, because you need to know which window the JRootPane was in
         before it was removed.  By the time ancestorRemoved was called, the JRootPane has already been removed
         */

        public void ancestorRemoved(AncestorEvent event)
        {
        }

        public void ancestorMoved(AncestorEvent event)
        {
        }
    }

    private class MyWindowListener
            extends WindowAdapter
    {

        public void windowActivated(WindowEvent e)
        {
            updateWindowActivation(e, true);
        }

        public void windowDeactivated(WindowEvent e)
        {
            updateWindowActivation(e, false);
        }
    }

    private static void updateWindowActivation(WindowEvent e, boolean active)
    {
        if (forceActiveWindowDisplay) {
            active = true;
        }
        Component c = (Component) e.getSource();
        c.repaint(); // much faster to make one repaint call rather than repainting individual components
        AquaFocusHandler.updateComponentTreeUIActivation(c, active);
    }

    @Override
    public final void update(Graphics g, JComponent c)
    {

        if (!isInitialized) {
            configure();
        }

        AquaAppearance appearance = AppearanceManager.registerCurrentAppearance(c);
        if (c.isOpaque() || vibrantStyle >= 0) {
            // Need a special case here. A dark mode textured window has a vibrant background (needed for a unified
            // title/toolbar), but the content area is opaque.
            int eraserMode = AquaUtils.ERASE_IF_TEXTURED | AquaUtils.ERASE_IF_VIBRANT;
            if (appearance.isDark() && customStyledWindow != null && customStyledWindow.isTextured()) {
                eraserMode = 0;
            }
            AquaUtils.fillRect(g, c, eraserMode);
        }
        if (customStyledWindow != null) {
            customStyledWindow.paintMarginBackgrounds(g);
        }
        paint(g, c);
    }

    protected class WindowHierarchyListener
            implements HierarchyListener
    {
        @Override
        public void hierarchyChanged(HierarchyEvent e)
        {
            long flags = e.getChangeFlags();
            if ((flags & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0) {
                if (rootPane.getParent() != null && rootPane.getParent().isDisplayable()) {
                    configureWindowIfPossible();
                    configure();
                } else {
                    unconfigure();
                }
            }
        }
    }

    /**
     Configure or reconfigure the window based on root pane client properties and popup client properties, if
     appropriate. This method has no effect if the root pane parent is not displayable.
     */
    public void configure()
    {
        if (rootPane.getParent() != null && rootPane.getParent().isDisplayable()) {
            isInitialized = true;
            configureSpecifiedWindowAppearance(false);
            updateAppearances(null, false);
            updatePopupStyle(rootPane);
            reconfigureCustomWindowStyle();
            updateVisualEffectView();
            configureRepresentedFilename();
        } else {
            reconfigureCustomWindowStyle();
        }
    }

    private void configureSpecifiedWindowAppearance(boolean resetIfNull)
    {
        Window w = getWindow();
        if (w != null && w.isDisplayable()) {
            String appearanceName = getSpecifiedWindowAppearance();
            if (appearanceName != null || resetIfNull) {
                AquaUtils.setWindowAppearance(w, appearanceName);
            }
        }
    }

    private @Nullable String getSpecifiedWindowAppearance()
    {
        Object o = rootPane.getClientProperty(AppearanceManager.AQUA_APPEARANCE_NAME_KEY);
        if (o instanceof String) {
            return (String) o;
        }
        return null;
    }

    private void unconfigure()
    {
        removeVisualEffectView();
        Window w = getWindow();
        if (w != null) {
            configureEmbeddedDialogPatchIfNeeded(w);
        }
    }

    /**
     This method is called when the native window discovers that it has been assigned a different appearance,
     meaning an appearance with a different appearance name.

     @param appearanceName The new appearance name.
     */
    public void windowAppearanceChanged(@NotNull String appearanceName)
    {
        updateAppearances(appearanceName, false);
    }

    /**
     Update the appearances in the component tree based on the most current information.
     */

    protected void updateAppearances(@Nullable String appearanceName, boolean forceInitialization)
    {
        Window w = getWindow();
        if (w != null) {
            updateWindowAppearances(w, appearanceName, forceInitialization);
        }
    }

    protected void updateWindowAppearances(@NotNull Window w,
                                           @Nullable String appearanceName,
                                           boolean forceInitialization)
    {
        if (appearanceName == null) {
            appearanceName = AquaUtils.getWindowEffectiveAppearanceName(w);
        }
        if (appearanceName != null) {
            AquaAppearance appearance = AquaAppearances.get(appearanceName);
            AquaAppearance oldAppearance = (AquaAppearance) rootPane.getClientProperty(AppearanceManager.AQUA_APPEARANCE_KEY);
            if (appearance != oldAppearance) {
                if (false) {
                    // debug
                    String windowName = AquaUtils.getWindowNameForDebugging(w);
                    String message = "Updating appearances for window " + windowName + ": ";
                    if (oldAppearance == null) {
                        message += "initial appearance " + appearanceName;
                    } else {
                        String oldAppearanceName = oldAppearance.getName();
                        if (appearanceName.equals(oldAppearanceName)) {
                            message += "updated appearance " + appearanceName;
                        } else {
                            message += oldAppearanceName + " -> " + appearanceName;
                        }
                    }
                    Utils.logDebug(message);
                }
                rootPane.repaint();
                AppearanceManager.setRootPaneRegisteredAppearance(rootPane, appearance);  // a callback will be invoked
            } else if (forceInitialization) {
                configureWindow(w);
                appearanceHasChanged();
            }
        }
    }

    private void configureWindowIfPossible() {
        Component parent = rootPane.getParent();
        if (parent instanceof Window) {
            Window w = (Window) parent;
            configureWindow(w);
        }
    }

    protected void configureWindow(@NotNull Window w) {

        configureEmbeddedDialogPatchIfNeeded(w);

        if (w.isDisplayable()) {
            if (OSXSystemProperties.OSVersion >= 1014 && !vibrantStyleIsExplicitlySet) {
                int vibrantStyle = getDefaultWindowVibrantStyle();
                updateVibrantStyle(vibrantStyle, false);
            }

            if (!AquaColors.isPriority(rootPane.getBackground())) {
                rootPane.setBackground(null);
            }

            Color c = AquaUtils.getWindowBackground(rootPane);
            AquaUtils.setBackgroundCarefully(w, c);

            // Make sure that the default window foreground is not considered an application priority.
            Color fc = w.getForeground();
            if (!(fc instanceof UIResource)) {
                w.setForeground(new ColorUIResource(fc));
            }
        }
    }

    protected void configureEmbeddedDialogPatchIfNeeded(@NotNull Window w)
    {
        // Workaround for dialogs created by embedded components.
        // See related issue JDK-8320438.

        if (w instanceof Dialog) {
            Dialog d = (Dialog) w;
            if (AquaUtils.windowHasEmbeddedOwner(w)) {
                String s = d.isModal() ? " modal" : "";
                Utils.logDebug("Configuring" + s + " dialog with embedded owner");
                // Note: a dialog may be disposed and later reanimated, which requires updating the fix.
                if (d.isVisible() && d.isDisplayable()) {
                    AquaUtils.fixWindowWithEmbeddedOwner(w, AquaUtils.NSModalPanelWindowLevel);
                }
            }
        }
    }

    protected int getDefaultWindowVibrantStyle() {
        // Non-textured windows use a vibrant background in dark mode
        // Textured windows use a vibrant background in dark mode but reveal it only in the title/toolbar
        AquaAppearance appearance = AppearanceManager.getAppearance(rootPane);
        if (appearance.isDark()) {
            return WINDOW_BACKGROUND_STYLE;
        }
        return NO_VIBRANT_STYLE;
    }

    protected void appearanceHasChanged() {
        rootPane.repaint();
    }

    @Override
    public void appearanceChanged(@NotNull JComponent c, @NotNull AquaAppearance appearance) {
        // This method is called when the registered appearance of the root pane is changed.
        Component parent = rootPane.getParent();
        if (parent instanceof Window) {
            Window w = (Window) parent;
            configureWindow(w);
        }
        appearanceHasChanged();
    }

    @Override
    public void activeStateChanged(@NotNull JComponent c, boolean isActive) {
        // This method is called when the active frame client property changes.
        Component parent = rootPane.getParent();
        if (parent instanceof Window) {
            Window w = (Window) parent;
            configureWindow(w);
        }
    }

    protected void updatePopupStyle(JRootPane rp) {
        Window w = SwingUtilities.getWindowAncestor(rp);
        if (w != null && w.getType() == Window.Type.POPUP) {
            Container cp = rp.getContentPane();
            if (cp != null) {
                int count = cp.getComponentCount();
                if (count == 1) {
                    Component c = cp.getComponent(0);
                    if (c instanceof JComponent) {
                        JComponent jc = (JComponent) c;
                        Object o = jc.getClientProperty(AquaVibrantSupport.POPUP_BACKGROUND_STYLE_KEY);
                        updateVibrantStyleFromProperty(o);
                        o = jc.getClientProperty(AquaVibrantSupport.POPUP_CORNER_RADIUS_KEY);
                        configurePopup(o);
                    }
                }
            }
        }
    }

    protected void configureRepresentedFilename() {
        Window w = getWindow();
        if (w != null && w.isDisplayable()) {
            Object o = rootPane.getClientProperty(AQUA_WINDOW_REPRESENTED_FILENAME_KEY);
            String filename = "";
            if (o instanceof String) {
                filename = (String) o;
            }
            AquaUtils.setWindowRepresentedFilename(w, filename);
        }
    }

    protected void configureLayeredPane()
    {
        JLayeredPane layeredPane = rootPane.getLayeredPane();
        AppearanceManager.installListeners(layeredPane);
        if (sUseScreenMenuBar) {
            layeredPane.addContainerListener(containerListener);
        }
    }

    protected void unconfigureLayeredPane()
    {
        JLayeredPane layeredPane = rootPane.getLayeredPane();
        AppearanceManager.uninstallListeners(layeredPane);
        if (sUseScreenMenuBar) {
            layeredPane.removeContainerListener(containerListener);
        }
    }

    protected void updateVibrantStyleFromProperty(Object o) {
        int style = AquaVibrantSupport.parseVibrantStyle(o, false);
        updateVibrantStyle(style, style != NO_VIBRANT_STYLE);
    }

    protected void updateVibrantStyle(int style, boolean isSet)
    {
        int oldVibrantStyle = vibrantStyle;
        vibrantStyle = style;
        vibrantStyleIsExplicitlySet = isSet;
        if (vibrantStyle != oldVibrantStyle && isInitialized) {
            updateVisualEffectView();
        }
    }

    protected void configurePopup(Object o) {
        float radius = 0;
        if (o != null) {
            if (o instanceof String) {
                String s = (String) o;
                if (s.equals("default")) {
                    radius = 6;
                }
            } else if (o instanceof Number) {
                radius = ((Number) o).floatValue();
            }
            if (radius < 0) {
                radius = 0;
            }
        }
        Window w = SwingUtilities.getWindowAncestor(rootPane);
        AquaUtils.configurePopup(w, radius);
    }

    protected @Nullable Window getWindow() {
        return SwingUtilities.getWindowAncestor(rootPane);
    }

    protected void updateVisualEffectView() {
        Window w = getWindow();
        if (w != null && !isEmbeddedView(w)) {
            if (false) {
                Utils.logDebug("Updating visual effect view: " + vibrantStyle);
            }
            if (vibrantStyle >= 0) {
                try {
                    AquaVibrantSupport.addFullWindowVibrantView(w, vibrantStyle);
                } catch (IllegalArgumentException | UnsupportedOperationException ex) {
                    Utils.logError("Unable to install visual effect view", ex);
                }
            } else {
                AquaVibrantSupport.removeFullWindowVibrantView(w);
                // TBD: cannot really undo this
            }
        }
    }

    protected boolean isEmbeddedView(@NotNull Window w) {
        String name = w.getClass().getSimpleName();
        return name.contains("CViewEmbeddedFrame");
    }

    protected void removeVisualEffectView() {
        Window w = getWindow();
        if (w != null) {
            AquaVibrantSupport.removeFullWindowVibrantView(w);
        }
    }

    protected void reconfigureCustomWindowStyle() {
        Window w = getWindow();
        int style = getCustomWindowStyle();
        if (style < 0 || w == null) {
            disposeCustomWindowStyle();
            if (w != null) {
                configureWindow(w);
            }
        } else if (w.isDisplayable()) {
            int topMarginHeight = getTopMarginHeight();
            int bottomMarginHeight = getBottomMarginHeight();
            if (customStyledWindow != null && !customStyledWindow.isValid(style, topMarginHeight, bottomMarginHeight)) {
                customStyledWindow = customStyledWindow.reconfigure(style, topMarginHeight, bottomMarginHeight);
                configureWindow(w);
            } else if (customStyledWindow == null) {
                try {
                    customStyledWindow = new AquaCustomStyledWindow(w, style, topMarginHeight, bottomMarginHeight);
                    configureWindow(w);
                } catch (AquaCustomStyledWindow.RequiredToolBarNotFoundException ex) {
                    // This exception would be thrown if the window style is set before adding the tool bar to the
                    // content pane, which would not be an error.
                } catch (IllegalArgumentException ex) {
                    AquaUtils.syslog("Unable to install custom window style: " + ex.getMessage());
                }
            }
        } else {
            AquaCustomStyledWindow.preconfigureWindowStyle(w, style);
        }
    }

    private void disposeCustomWindowStyle() {
        if (customStyledWindow != null) {
            customStyledWindow.dispose();
            customStyledWindow = null;
        }
    }

    public AquaCustomStyledWindow getCustomStyledWindow() {
        return customStyledWindow;
    }

    public static @Nullable String getWindowStyleKey(@NotNull JRootPane rp) {
        Object o = rp.getClientProperty(AQUA_WINDOW_STYLE_KEY);
        return o instanceof String ? (String) o : null;
    }

    protected int getCustomWindowStyle() {
        String key = getWindowStyleKey(rootPane);
        if (key != null) {
            if ("unifiedToolBar".equals(key)) {
                return AquaCustomStyledWindow.STYLE_UNIFIED;
            }
            if ("texturedToolBar".equals(key)) {
                return AquaCustomStyledWindow.STYLE_TEXTURED_HIDDEN;
            }
            if ("combinedToolBar".equals(key)) {
                return AquaCustomStyledWindow.STYLE_COMBINED;
            }
            if ("overlayTitleBar".equals(key)) {
                return AquaCustomStyledWindow.STYLE_OVERLAY;
            }
            if ("transparentTitleBar".equals(key)) {
                return AquaCustomStyledWindow.STYLE_TRANSPARENT;
            }
            if ("noTitleBar".equals(key)) {
                return AquaCustomStyledWindow.STYLE_HIDDEN;
            }
            if ("undecorated".equals(key)) {
                return AquaCustomStyledWindow.STYLE_UNDECORATED;
            }
        }

        return -1;
    }

    protected int getTopMarginHeight() {
        Integer n = AquaUtils.getIntegerProperty(rootPane, AquaRootPaneUI.AQUA_WINDOW_TOP_MARGIN_KEY);
        return n != null ? n : -1;
    }

    protected int getBottomMarginHeight() {
        Integer n = AquaUtils.getIntegerProperty(rootPane, AquaRootPaneUI.AQUA_WINDOW_BOTTOM_MARGIN_KEY);
        return n != null ? n : -1;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy