[mac] fullscreen bottom empty space fixed + restore frame state on start

This commit is contained in:
Alexey Pegov
2011-07-24 17:03:20 +04:00
parent 9903363f55
commit 9867e200c8
3 changed files with 158 additions and 10 deletions
@@ -19,6 +19,7 @@ import com.intellij.ide.AppLifecycleListener;
import com.intellij.ide.DataManager;
import com.intellij.ide.impl.ProjectUtil;
import com.intellij.ide.ui.UISettings;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.notification.impl.IdeNotificationArea;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.MnemonicHelper;
@@ -69,6 +70,7 @@ import java.io.File;
// Made non-final for Fabrique
public class IdeFrameImpl extends JFrame implements IdeFrame, DataProvider {
private static final String FULL_SCREEN = "FullScreen";
private String myTitle;
private String myFileTitle;
@@ -81,6 +83,8 @@ public class IdeFrameImpl extends JFrame implements IdeFrame, DataProvider {
private final BalloonLayout myBalloonLayout;
private static boolean myUpdatingTitle;
private MacMainFrameDecorator myFrameDecorator;
private boolean myRestoreFullscreen;
public IdeFrameImpl(ApplicationInfoEx applicationInfoEx, ActionManagerEx actionManager, UISettings uiSettings, DataManager dataManager,
final Application application, final String[] commandLineArgs) {
@@ -275,6 +279,14 @@ public class IdeFrameImpl extends JFrame implements IdeFrame, DataProvider {
}
public void setProject(final Project project) {
if (SystemInfo.isMacOSLion && myProject != project && project != null) {
myRestoreFullscreen = myProject == null && shouldRestoreFullScreen(project);
if (myProject != null) {
storeFullScreenStateIfNeeded(false); // disable for old project
}
}
myProject = project;
if (project != null) {
if (myRootPane != null) {
@@ -293,6 +305,28 @@ public class IdeFrameImpl extends JFrame implements IdeFrame, DataProvider {
if (project == null) {
FocusTrackback.release(this);
}
if (isVisible() && myRestoreFullscreen) {
MacMainFrameDecorator.toggleFullScreen(this);
myRestoreFullscreen = false;
storeFullScreenStateIfNeeded(false); // reset
}
}
@Override
public void setVisible(boolean b) {
super.setVisible(b);
if (b && myRestoreFullscreen) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
MacMainFrameDecorator.toggleFullScreen(IdeFrameImpl.this);
myRestoreFullscreen = false;
storeFullScreenStateIfNeeded(false); // reset
}
});
}
}
private void installDefaultProjectStatusBarWidgets(@NotNull final Project project) {
@@ -352,6 +386,30 @@ public class IdeFrameImpl extends JFrame implements IdeFrame, DataProvider {
super.dispose();
}
public void storeFullScreenStateIfNeeded() {
storeFullScreenStateIfNeeded(MacMainFrameDecorator.isFullScreenMode(this));
}
public void storeFullScreenStateIfNeeded(boolean state) {
if (!SystemInfo.isMacOSLion) return;
if (myProject != null) {
PropertiesComponent.getInstance(myProject).setValue(FULL_SCREEN, Boolean.valueOf(state).toString());
} else {
//PropertiesComponent.getInstance().setValue(FULL_SCREEN, Boolean.valueOf(state).toString());
}
}
public static boolean shouldRestoreFullScreen(Project project) {
if (!SystemInfo.isMacOSLion) return false;
if (project != null) {
return PropertiesComponent.getInstance(project).getBoolean(FULL_SCREEN, false);
} else {
return false; // PropertiesComponent.getInstance().getBoolean(FULL_SCREEN, false);
}
}
@Override
public void paint(Graphics g) {
UIUtil.applyRenderingHints(g);
@@ -16,6 +16,7 @@
package com.intellij.openapi.wm.impl;
import com.intellij.Patches;
import com.intellij.ide.AppLifecycleListener;
import com.intellij.ide.DataManager;
import com.intellij.ide.IdeEventQueue;
import com.intellij.ide.impl.DataManagerImpl;
@@ -43,6 +44,7 @@ import com.intellij.ui.mac.MacMainFrameDecorator;
import com.intellij.util.Alarm;
import com.intellij.util.ArrayUtil;
import com.intellij.util.EventDispatcher;
import com.intellij.util.messages.MessageBus;
import com.intellij.util.ui.UIUtil;
import com.sun.jna.platform.WindowUtils;
import org.jdom.Element;
@@ -134,7 +136,8 @@ public final class WindowManagerImpl extends WindowManagerEx implements Applicat
public WindowManagerImpl(DataManager dataManager,
ApplicationInfoEx applicationInfoEx,
ActionManagerEx actionManager,
UISettings uiSettings) {
UISettings uiSettings,
MessageBus bus) {
myApplicationInfoEx = applicationInfoEx;
myDataManager = dataManager;
myActionManager = actionManager;
@@ -185,6 +188,26 @@ public final class WindowManagerImpl extends WindowManagerEx implements Applicat
}
}
};
bus.connect().subscribe(AppLifecycleListener.TOPIC, new AppLifecycleListener.Adapter() {
@Override
public void appClosing() {
// save fullscreen window states
if (SystemInfo.isMacOSLion) {
Project[] openProjects = ProjectManager.getInstance().getOpenProjects();
if (openProjects.length > 0) {
WindowManagerEx wm = WindowManagerEx.getInstanceEx();
for (Project project : openProjects) {
IdeFrameImpl frame = wm.getFrame(project);
if (frame != null) {
frame.storeFullScreenStateIfNeeded();
}
}
}
}
}
});
}
public void showFrame(final String[] args) {
@@ -672,7 +695,8 @@ public final class WindowManagerImpl extends WindowManagerEx implements Applicat
final IdeFrameImpl frame = getFrame(project);
if (frame != null) {
final Rectangle rectangle = frame.getBounds();
boolean usePreviousBounds = SystemInfo.isMacOSLion && WindowManagerEx.getInstanceEx().isFullScreen(frame);
final Rectangle rectangle = usePreviousBounds ? myFrameBounds : frame.getBounds();
frameElement.setAttribute(X_ATTR, Integer.toString(rectangle.x));
frameElement.setAttribute(Y_ATTR, Integer.toString(rectangle.y));
frameElement.setAttribute(WIDTH_ATTR, Integer.toString(rectangle.width));
@@ -20,7 +20,7 @@ import com.intellij.ide.ui.UISettingsListener;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.openapi.wm.impl.IdeFrameImpl;
import com.intellij.ui.mac.foundation.Foundation;
import com.intellij.ui.mac.foundation.ID;
import com.intellij.util.Function;
@@ -90,7 +90,9 @@ public class MacMainFrameDecorator implements UISettingsListener, Disposable {
private static Runnable CURRENT_SETTER = null;
private static Function<Object, Boolean> CURRENT_GETTER = null;
private String myClassName;
private Callback myDidExit;
private Callback myDidEnter;
public MacMainFrameDecorator(@NotNull final Frame frame, final boolean navBar) {
final ID window = findWindowForTitle(frame.getTitle());
@@ -106,20 +108,75 @@ public class MacMainFrameDecorator implements UISettingsListener, Disposable {
final ID pool = invoke("NSAutoreleasePool", "new");
int v = UNIQUE_COUNTER.incrementAndGet();
try {
if (SystemInfo.isMacOSLion) {
// fullscreen
// fullscreen support
final ID delegateClass = Foundation.registerObjcClass(Foundation.getClass("NSObject"), "IdeaNSWindowDelegate" + v);
Foundation.registerObjcClassPair(delegateClass);
myDidExit = new Callback() {
public void callback(ID caller, ID notification) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (frame instanceof IdeFrameImpl) {
((IdeFrameImpl)frame).storeFullScreenStateIfNeeded(false);
}
}
});
}
};
Foundation.addMethod(delegateClass, Foundation.createSelector("windowDidExitFullScreen:"), myDidExit, "v*");
myDidEnter = new Callback() {
public void callback(ID caller, ID notification) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (frame instanceof IdeFrameImpl) {
//((IdeFrameImpl)frame).storeFullScreenStateIfNeeded(true);
// fix problem with bottom empty bar
// it seems like the title is still visible in fullscreen but the window itself shifted up for titlebar height
// and the size of the frame is still calculated to be the height of the screen which is wrong
// so just add these titlebar height to the frame height once again
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
frame.setSize(frame.getWidth(), frame.getHeight() + frame.getInsets().top);
}
});
}
}
});
}
};
Foundation.addMethod(delegateClass, Foundation.createSelector("windowDidEnterFullScreen:"), myDidEnter, "v*");
// enable fullscreen titlebar button
invoke(window, "setCollectionBehavior:", 1 << 7); // NSCollectionBehaviorFullScreenPrimary = 1 << 7, NSCollectionBehaviorFullScreenAuxiliary = 1 << 8
ID notificationCenter = invoke("NSNotificationCenter", "defaultCenter");
ID delegate = invoke(invoke("IdeaNSWindowDelegate" + v, "alloc"), "init");
invoke(notificationCenter, "addObserver:selector:name:object:", delegate,
Foundation.createSelector("windowDidEnterFullScreen:"),
Foundation.cfString("NSWindowDidEnterFullScreenNotification"), window);
//invoke(notificationCenter, "addObserver:selector:name:object:", delegate,
// Foundation.createSelector("windowDidExitFullScreen:"),
// Foundation.cfString("NSWindowDidExitFullScreenNotification"), window);
} else {
// toggle toolbar
myClassName = "IdeaToolbar" + UNIQUE_COUNTER.incrementAndGet();
final ID ownToolbar = Foundation.registerObjcClass(Foundation.getClass("NSToolbar"), myClassName);
String className = "IdeaToolbar" + v;
final ID ownToolbar = Foundation.registerObjcClass(Foundation.getClass("NSToolbar"), className);
Foundation.registerObjcClassPair(ownToolbar);
ID toolbar = invoke(invoke(myClassName, "alloc"), "initWithIdentifier:", Foundation.cfString(myClassName));
ID toolbar = invoke(invoke(className, "alloc"), "initWithIdentifier:", Foundation.cfString(className));
Foundation.cfRetain(toolbar);
invoke(toolbar, "setVisible:", 0); // hide native toolbar by default
@@ -152,6 +209,15 @@ public class MacMainFrameDecorator implements UISettingsListener, Disposable {
public void dispose() {
}
public static void toggleFullScreen(Frame frame) {
if (!SystemInfo.isMacOSLion) return;
final ID window = findWindowForTitle(frame.getTitle());
if (window == null) return;
invoke(window, "toggleFullScreen:", window);
}
public static boolean isFullScreenMode(@NotNull Frame frame) {
if (!SystemInfo.isMacOSLion) return false;