IDEABKL-6104 Full screen/Compact mode

This commit is contained in:
Vassiliy Kudryashov
2013-01-11 18:14:53 +04:00
parent 8d724fd927
commit 8ffb6f6bd3
21 changed files with 185 additions and 38 deletions
@@ -43,6 +43,7 @@ import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.ListCellRendererWrapper;
import com.intellij.ui.ScreenUtil;
import com.intellij.ui.SideBorder;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.usages.UsageView;
@@ -445,6 +446,8 @@ public class ImplementationViewComponent extends JPanel {
@Override
public void removeNotify() {
super.removeNotify();
if (!ScreenUtil.isStandardAddRemoveNotify(this))
return;
EditorFactory.getInstance().releaseEditor(myEditor);
disposeNonTextEditor();
}
@@ -30,6 +30,7 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.openapi.wm.IdeFrame;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.ui.ScreenUtil;
import com.intellij.ui.UIBundle;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.awt.RelativeRectangle;
@@ -1260,6 +1261,8 @@ public class RunnerContentUi implements ContentUI, Disposable, CellTransform.Fac
public void removeNotify() {
super.removeNotify();
if (!ScreenUtil.isStandardAddRemoveNotify(this))
return;
if (Disposer.isDisposed(RunnerContentUi.this)) return;
@@ -45,6 +45,7 @@ import com.intellij.pom.Navigatable;
import com.intellij.psi.*;
import com.intellij.psi.search.scope.packageSet.NamedScope;
import com.intellij.psi.search.scope.packageSet.NamedScopesHolder;
import com.intellij.ui.ScreenUtil;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.treeStructure.Tree;
import com.intellij.util.Alarm;
@@ -229,7 +230,8 @@ public abstract class HierarchyBrowserBaseEx extends HierarchyBrowserBase implem
@Override
public void removeNotify() {
super.removeNotify();
myRefreshAction.unregisterCustomShortcutSet(this);
if (ScreenUtil.isStandardAddRemoveNotify(this))
myRefreshAction.unregisterCustomShortcutSet(this);
}
@Override
@@ -290,7 +292,8 @@ public abstract class HierarchyBrowserBaseEx extends HierarchyBrowserBase implem
@Override
public void removeNotify() {
super.removeNotify();
myRefreshAction.unregisterCustomShortcutSet(this);
if (ScreenUtil.isStandardAddRemoveNotify(this))
myRefreshAction.unregisterCustomShortcutSet(this);
}
@Override
@@ -739,7 +739,8 @@ public class NavBarPanel extends JPanel implements DataProvider, PopupOwner, Dis
@Override
public void removeNotify() {
super.removeNotify();
Disposer.dispose(this);
if (ScreenUtil.isStandardAddRemoveNotify(this))
Disposer.dispose(this);
}
public void updateState(final boolean show) {
@@ -31,6 +31,7 @@ import com.intellij.openapi.util.UserDataHolder;
import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.ScreenUtil;
import com.intellij.ui.SideBorder;
import com.intellij.ui.components.JBScrollPane;
import org.jetbrains.annotations.NotNull;
@@ -110,7 +111,8 @@ public class DetailViewImpl extends JPanel implements DetailView, UserDataHolder
@Override
public void removeNotify() {
super.removeNotify();
clearEditor();
if (ScreenUtil.isStandardAddRemoveNotify(this))
clearEditor();
}
@Override
@@ -20,6 +20,7 @@ import com.intellij.openapi.util.SystemInfo;
import com.intellij.util.containers.WeakHashMap;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.Map;
@@ -28,6 +29,7 @@ import java.util.Map;
* @author Konstantin Bulenkov
*/
public class ScreenUtil {
public static final String DISPOSE_TEMPORARY = "dispose.temporary";
@Nullable private static final Map<GraphicsConfiguration, Pair<Insets, Long>> ourInsetsCache;
static {
final boolean useCache = SystemInfo.isXWindow && !GraphicsEnvironment.isHeadless();
@@ -80,6 +82,46 @@ public class ScreenUtil {
return answer;
}
public static GraphicsDevice getScreenDevice(Rectangle bounds) {
GraphicsDevice candidate = null;
int maxIntersection = 0;
for (GraphicsDevice device : GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()) {
GraphicsConfiguration config = device.getDefaultConfiguration();
final Rectangle rect = config.getBounds();
Rectangle intersection = rect.intersection(bounds);
if (intersection.isEmpty()) {
continue;
}
if (intersection.width * intersection.height > maxIntersection) {
maxIntersection = intersection.width * intersection.height;
candidate = device;
}
}
return candidate;
}
/**
* Method removeNotify (and then addNotify) will be invoked for all components when main frame switches between states "Normal" <-> "FullScreen".
* In this case we shouldn't call Disposer in removeNotify and/or release some resources that we won't initialize again in addNotify (e.g. listeners).
*/
public static boolean isStandardAddRemoveNotify(Component component) {
JRootPane rootPane = findMainRootPane(component);
return rootPane == null || rootPane.getClientProperty(DISPOSE_TEMPORARY) == null;
}
private static JRootPane findMainRootPane(Component component) {
while(component != null) {
Container parent = component.getParent();
if (parent == null)
return component instanceof RootPaneContainer ? ((RootPaneContainer) component).getRootPane() : null;
component = parent;
}
return null;
}
private static Rectangle applyInsets(Rectangle rect, Insets i) {
if (i == null) {
return rect;
@@ -19,10 +19,7 @@ import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.ComponentWithExpandableItems;
import com.intellij.ui.ExpandableItemsHandler;
import com.intellij.ui.ExpandableItemsHandlerFactory;
import com.intellij.ui.ExpandedItemListCellRendererWrapper;
import com.intellij.ui.*;
import com.intellij.util.ArrayUtil;
import com.intellij.util.NotNullFunction;
import com.intellij.util.ui.AsyncProcessIcon;
@@ -79,6 +76,9 @@ public class JBList extends JList implements ComponentWithEmptyText, ComponentWi
public void removeNotify() {
super.removeNotify();
if (!ScreenUtil.isStandardAddRemoveNotify(this))
return;
if (myBusyIcon != null) {
remove(myBusyIcon);
Disposer.dispose(myBusyIcon);
@@ -68,6 +68,8 @@ public class JBOptionButton extends JButton implements MouseMotionListener {
@Override
public void addNotify() {
super.addNotify();
if (!ScreenUtil.isStandardAddRemoveNotify(this))
return;
myGlassPane = IdeGlassPaneUtil.find(this);
if (myGlassPane != null) {
myGlassPane.addMouseMotionPreprocessor(this, myDisposable);
@@ -77,6 +79,8 @@ public class JBOptionButton extends JButton implements MouseMotionListener {
@Override
public void removeNotify() {
super.removeNotify();
if (!ScreenUtil.isStandardAddRemoveNotify(this))
return;
Disposer.dispose(myDisposable);
}
@@ -1,6 +1,7 @@
package com.intellij.ui.components;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.ui.ScreenUtil;
import com.intellij.util.ui.UIUtil;
import org.intellij.lang.annotations.JdkConstants;
import org.jetbrains.annotations.NonNls;
@@ -100,6 +101,8 @@ public class JBTabbedPane extends JTabbedPane implements HierarchyListener {
@Override
public void removeNotify() {
super.removeNotify();
if (!ScreenUtil.isStandardAddRemoveNotify(this))
return;
for (int i=0; i<getTabCount(); i++) {
getComponentAt(i).removeHierarchyListener(this);
}
@@ -20,6 +20,7 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.wm.StatusBar;
import com.intellij.ui.ScreenUtil;
import com.intellij.ui.UI;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.Nullable;
@@ -185,7 +186,8 @@ public class LinkLabel extends JLabel {
public void removeNotify() {
super.removeNotify();
disableUnderline();
if (ScreenUtil.isStandardAddRemoveNotify(this))
disableUnderline();
}
private void setActive(boolean isActive) {
@@ -315,16 +315,21 @@ public class JBTable extends JTable implements ComponentWithEmptyText, Component
}
public void removeNotify() {
final KeyboardFocusManager keyboardFocusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
//noinspection HardCodedStringLiteral
keyboardFocusManager.removePropertyChangeListener("permanentFocusOwner", myEditorRemover);
//noinspection HardCodedStringLiteral
keyboardFocusManager.removePropertyChangeListener("focusOwner", myEditorRemover);
super.removeNotify();
if (myBusyIcon != null) {
remove(myBusyIcon);
Disposer.dispose(myBusyIcon);
myBusyIcon = null;
if (ScreenUtil.isStandardAddRemoveNotify(this)) {
final KeyboardFocusManager keyboardFocusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
//noinspection HardCodedStringLiteral
keyboardFocusManager.removePropertyChangeListener("permanentFocusOwner", myEditorRemover);
//noinspection HardCodedStringLiteral
keyboardFocusManager.removePropertyChangeListener("focusOwner", myEditorRemover);
super.removeNotify();
if (myBusyIcon != null) {
remove(myBusyIcon);
Disposer.dispose(myBusyIcon);
myBusyIcon = null;
}
}
else {
super.removeNotify();
}
}
@@ -25,10 +25,7 @@ import com.intellij.openapi.ui.ShadowAction;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.wm.*;
import com.intellij.ui.CaptionPanel;
import com.intellij.ui.ColorUtil;
import com.intellij.ui.Gray;
import com.intellij.ui.JBColor;
import com.intellij.ui.*;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.awt.RelativeRectangle;
import com.intellij.ui.switcher.QuickActionProvider;
@@ -412,7 +409,7 @@ public class JBTabsImpl extends JComponent
removeTimerUpdate();
if (myGlassPane != null) {
if (ScreenUtil.isStandardAddRemoveNotify(this) && myGlassPane != null) {
myGlassPane.removeMouseMotionPreprocessor(myTabActionsAutoHideListener);
myGlassPane = null;
}
@@ -24,6 +24,7 @@ import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.openapi.wm.ex.WindowManagerEx;
import com.intellij.openapi.wm.impl.IdeFrameImpl;
import com.intellij.openapi.wm.impl.WindowManagerImpl;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
@@ -41,7 +42,7 @@ public class ToggleMacFullScreenAction extends AnAction implements DumbAware {
public void actionPerformed(final AnActionEvent e) {
final Frame frame = getFrame();
if (frame instanceof IdeFrameImpl) {
((IdeFrameImpl)frame).getFrameDecorator().toggleFullScreen();
WindowManagerImpl.toggleFullScreen((IdeFrameImpl)frame);
}
}
@@ -49,7 +50,7 @@ public class ToggleMacFullScreenAction extends AnAction implements DumbAware {
public void update(final AnActionEvent e) {
final Presentation p = e.getPresentation();
final boolean isApplicable = SystemInfo.isMac && SystemInfo.isMacOSLion;
final boolean isApplicable = (SystemInfo.isMac && SystemInfo.isMacOSLion) || SystemInfo.isWindows;
p.setVisible(isApplicable);
p.setEnabled(isApplicable);
@@ -43,6 +43,7 @@ import com.intellij.openapi.wm.ex.WindowManagerEx;
import com.intellij.ui.ColorUtil;
import com.intellij.ui.Gray;
import com.intellij.ui.JBColor;
import com.intellij.ui.ScreenUtil;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.awt.RelativeRectangle;
import com.intellij.ui.switcher.SwitchTarget;
@@ -212,7 +213,8 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar {
ourToolbars.remove(this);
myActionManager.removeTimerListener(myWeakTimerListener);
myActionManager.removeTransparentTimerListener(myWeakTimerListener);
myKeymapManager.removeWeakListener(myKeymapManagerListener);
if (ScreenUtil.isStandardAddRemoveNotify(this))
myKeymapManager.removeWeakListener(myKeymapManagerListener);
}
@Override
@@ -24,6 +24,7 @@ import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.wm.ex.WindowManagerEx;
import com.intellij.ui.Gray;
import com.intellij.ui.JBColor;
import com.intellij.ui.ScreenUtil;
import com.intellij.util.Alarm;
import com.intellij.util.ui.UIUtil;
@@ -128,7 +129,18 @@ public final class FloatingDecorator extends JDialog{
}
public final void dispose(){
Disposer.dispose(myDelayAlarm);
if (ScreenUtil.isStandardAddRemoveNotify(getParent()))
Disposer.dispose(myDelayAlarm);
else {
if (isShowing()) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
show();
}
});
}
}
super.dispose();
}
@@ -46,15 +46,13 @@ import com.intellij.openapi.wm.IdeRootPaneNorthExtension;
import com.intellij.openapi.wm.StatusBar;
import com.intellij.openapi.wm.ex.LayoutFocusTraversalPolicyExt;
import com.intellij.openapi.wm.ex.StatusBarEx;
import com.intellij.openapi.wm.ex.WindowManagerEx;
import com.intellij.openapi.wm.impl.status.EncodingPanel;
import com.intellij.openapi.wm.impl.status.InsertOverwritePanel;
import com.intellij.openapi.wm.impl.status.PositionPanel;
import com.intellij.openapi.wm.impl.status.ToggleReadOnlyAttributePanel;
import com.intellij.openapi.wm.impl.welcomeScreen.WelcomeFrame;
import com.intellij.ui.AppUIUtil;
import com.intellij.ui.BalloonLayout;
import com.intellij.ui.BalloonLayoutImpl;
import com.intellij.ui.FocusTrackback;
import com.intellij.ui.*;
import com.intellij.ui.mac.MacMainFrameDecorator;
import com.intellij.util.PlatformUtils;
import com.intellij.util.ui.UIUtil;
@@ -172,6 +170,8 @@ public class IdeFrameImpl extends JFrame implements IdeFrame, DataProvider {
addWindowListener(
new WindowAdapter() {
public void windowClosing(final WindowEvent e) {
if (isTemporaryDisposed())
return;
final Application app = ApplicationManager.getApplication();
app.invokeLater(new DumbAwareRunnable() {
public void run() {
@@ -385,6 +385,10 @@ public class IdeFrameImpl extends JFrame implements IdeFrame, DataProvider {
}
public void dispose() {
if (isTemporaryDisposed()) {
super.dispose();
return;
}
MouseGestureManager.getInstance().remove(this);
WelcomeFrame.notifyFrameClosed(this);
@@ -402,6 +406,10 @@ public class IdeFrameImpl extends JFrame implements IdeFrame, DataProvider {
super.dispose();
}
private boolean isTemporaryDisposed() {
return myRootPane != null && myRootPane.getClientProperty(ScreenUtil.DISPOSE_TEMPORARY) != null;
}
public MacMainFrameDecorator getFrameDecorator() {
return myFrameDecorator;
}
@@ -29,6 +29,7 @@ import com.intellij.openapi.actionSystem.impl.WeakTimerListener;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.util.Disposer;
import com.intellij.ui.ScreenUtil;
import com.intellij.util.ui.UIUtil;
import javax.swing.*;
@@ -67,6 +68,8 @@ public class IdeMenuBar extends JMenuBar {
public void addNotify() {
super.addNotify();
updateMenuActions();
if (!ScreenUtil.isStandardAddRemoveNotify(this))
return;
// Add updater for menus
myActionManager.addTimerListener(1000, new WeakTimerListener(myActionManager, myTimerListener));
UISettingsListener UISettingsListener = new UISettingsListener() {
@@ -84,7 +87,9 @@ public class IdeMenuBar extends JMenuBar {
*/
@Override
public void removeNotify() {
Disposer.dispose(myDisposable);
if (ScreenUtil.isStandardAddRemoveNotify(this)) {
Disposer.dispose(myDisposable);
}
super.removeNotify();
}
@@ -26,6 +26,7 @@ import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.wm.ToolWindowAnchor;
import com.intellij.ui.ColorUtil;
import com.intellij.ui.Gray;
import com.intellij.ui.ScreenUtil;
import com.intellij.util.ui.UIUtil;
import javax.swing.*;
@@ -154,7 +155,9 @@ final class Stripe extends JPanel{
updateText();
updateState();
KeymapManagerEx.getInstanceEx().addWeakListener(myWeakKeymapManagerListener);
UISettings.getInstance().addUISettingsListener(myUISettingsListener,myDisposable);
if (ScreenUtil.isStandardAddRemoveNotify(this)) {
UISettings.getInstance().addUISettingsListener(myUISettingsListener,myDisposable);
}
}
/**
@@ -163,7 +166,9 @@ final class Stripe extends JPanel{
@Override
public void removeNotify(){
KeymapManagerEx.getInstanceEx().removeWeakListener(myWeakKeymapManagerListener);
Disposer.dispose(myDisposable);
if (ScreenUtil.isStandardAddRemoveNotify(this)) {
Disposer.dispose(myDisposable);
}
super.removeNotify();
}
@@ -30,6 +30,7 @@ import com.intellij.openapi.wm.ToolWindowType;
import com.intellij.openapi.wm.ex.ToolWindowEx;
import com.intellij.openapi.wm.impl.commands.FinalizableCommand;
import com.intellij.reference.SoftReference;
import com.intellij.ui.ScreenUtil;
import com.intellij.util.containers.HashMap;
import com.intellij.util.ui.UIUtil;
@@ -173,14 +174,18 @@ final class ToolWindowsPane extends JLayeredPane implements Disposable {
*/
public final void addNotify(){
super.addNotify();
UISettings.getInstance().addUISettingsListener(myUISettingsListener,myDisposable);
if (ScreenUtil.isStandardAddRemoveNotify(this)) {
UISettings.getInstance().addUISettingsListener(myUISettingsListener,myDisposable);
}
}
/**
* Invoked when enclosed frame is being disposed.
*/
public final void removeNotify(){
Disposer.dispose(myDisposable);
if (ScreenUtil.isStandardAddRemoveNotify(this)) {
Disposer.dispose(myDisposable);
}
super.removeNotify();
}
@@ -250,7 +250,14 @@ public final class WindowManagerImpl extends WindowManagerEx implements Applicat
@Override
public boolean isFullScreen(@NotNull Frame frame) {
return frame instanceof IdeFrameImpl && ((IdeFrameImpl)frame).isInFullScreen();
if (SystemInfo.isMac && SystemInfo.isMacOSLion) {
return frame instanceof IdeFrameImpl && ((IdeFrameImpl)frame).isInFullScreen();
}
if (SystemInfo.isWindows) {
GraphicsDevice device = ScreenUtil.getScreenDevice(frame.getBounds());
return (device != null && device.getDefaultConfiguration().getBounds().equals(frame.getBounds()) && frame.isUndecorated());
}
return false;
}
@Override
@@ -821,4 +828,38 @@ public final class WindowManagerImpl extends WindowManagerEx implements Applicat
public WindowWatcher getWindowWatcher() {
return myWindowWatcher;
}
public static void toggleFullScreen(IdeFrameImpl frame) {
if (SystemInfo.isMac && SystemInfo.isMacOSLion) {
frame.getFrameDecorator().toggleFullScreen();
return;
}
if (SystemInfo.isWindows) {
GraphicsDevice device = ScreenUtil.getScreenDevice(frame.getBounds());
if (device != null) {
boolean isFullScreenNow = device.getDefaultConfiguration().getBounds().equals(frame.getBounds()) && frame.isUndecorated();
Object o = frame.getRootPane().getClientProperty("oldBounds");
Rectangle oldBounds = (o instanceof Rectangle) ? (Rectangle)o : null;
try {
frame.getRootPane().putClientProperty(ScreenUtil.DISPOSE_TEMPORARY, Boolean.TRUE);
if (!isFullScreenNow)
frame.getRootPane().putClientProperty("oldBounds", frame.getBounds());
frame.dispose();
frame.setUndecorated(!isFullScreenNow);
} finally {
if (isFullScreenNow) {
if (oldBounds != null)
frame.setBounds(oldBounds);
}
else {
frame.setBounds(device.getDefaultConfiguration().getBounds());
}
frame.setVisible(true);
frame.getRootPane().putClientProperty(ScreenUtil.DISPOSE_TEMPORARY, null);
}
}
return;
}
}
}
@@ -1330,6 +1330,9 @@ public class BalloonImpl implements Balloon, IdeTooltip.Ui, SwingConstants {
public void removeNotify() {
super.removeNotify();
if (!ScreenUtil.isStandardAddRemoveNotify(this))
return;
final CloseButton closeButton = myCloseRec;
SwingUtilities.invokeLater(new Runnable() {
@Override