mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
synchronous toolwindows initializing to prevent re-layout during startup
This commit is contained in:
@@ -15,13 +15,9 @@
|
||||
*/
|
||||
package com.intellij.openapi.wm.impl;
|
||||
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Conditions;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.wm.impl.commands.FinalizableCommand;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -44,7 +40,7 @@ public final class CommandProcessor implements Runnable {
|
||||
|
||||
/**
|
||||
* Executes passed batch of commands. Note, that the processor surround the
|
||||
* commands with BlockFocusEventsCmd - UnbockFocusEventsCmd. It's required to
|
||||
* commands with BlockFocusEventsCmd - UnblockFocusEventsCmd. It's required to
|
||||
* prevent focus handling of events which is caused by the commands to be executed.
|
||||
*/
|
||||
public final void execute(@NotNull List<FinalizableCommand> commandList, @NotNull Condition expired) {
|
||||
@@ -63,32 +59,27 @@ public final class CommandProcessor implements Runnable {
|
||||
|
||||
public final void run() {
|
||||
synchronized (myLock) {
|
||||
final CommandGroup commandGroup = getNextCommandGroup();
|
||||
if (commandGroup == null || commandGroup.isEmpty()) return;
|
||||
|
||||
final Condition conditionForGroup = commandGroup.getExpireCondition();
|
||||
|
||||
final FinalizableCommand command = commandGroup.takeNextCommand();
|
||||
myCommandCount--;
|
||||
|
||||
final Condition expire = command.getExpireCondition() != null ? command.getExpireCondition() : conditionForGroup;
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("CommandProcessor.run " + command);
|
||||
//noinspection StatementWithEmptyBody
|
||||
while (runNext()) {
|
||||
}
|
||||
// max. I'm not actually quite sure this should have NON_MODAL modality but it should
|
||||
// definitely have some since runnables in command list may (and do) request some PSI activity
|
||||
final boolean queueNext = myCommandCount > 0;
|
||||
Application application = ApplicationManager.getApplication();
|
||||
ModalityState modalityState = Registry.is("ide.perProjectModality") ? ModalityState.current() : ModalityState.NON_MODAL;
|
||||
application.getInvokator().invokeLater(command, modalityState, expire == null ? application.getDisposed() : expire).doWhenDone(() -> {
|
||||
if (queueNext) {
|
||||
this.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private boolean runNext() {
|
||||
final CommandGroup commandGroup = getNextCommandGroup();
|
||||
if (commandGroup == null || commandGroup.isEmpty()) return false;
|
||||
|
||||
final FinalizableCommand command = commandGroup.takeNextCommand();
|
||||
myCommandCount--;
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("CommandProcessor.run " + command);
|
||||
}
|
||||
|
||||
command.run();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private CommandGroup getNextCommandGroup() {
|
||||
while (!myCommandGroupList.isEmpty()) {
|
||||
|
||||
+64
-55
@@ -37,14 +37,11 @@ import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
|
||||
import com.intellij.openapi.fileEditor.impl.EditorsSplitters;
|
||||
import com.intellij.openapi.keymap.Keymap;
|
||||
import com.intellij.openapi.keymap.KeymapManager;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.util.ProgressIndicatorUtils;
|
||||
import com.intellij.openapi.progress.util.ReadTask;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.DumbAwareRunnable;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.startup.StartupManager;
|
||||
import com.intellij.openapi.startup.StartupActivity;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.ui.MessageType;
|
||||
import com.intellij.openapi.ui.Splitter;
|
||||
@@ -62,7 +59,9 @@ import com.intellij.ui.awt.RelativePoint;
|
||||
import com.intellij.ui.switcher.QuickAccessSettings;
|
||||
import com.intellij.ui.switcher.SwitchManager;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import com.intellij.util.ui.EdtInvocationManager;
|
||||
import com.intellij.util.ui.PositionTracker;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.util.ui.update.UiNotifyConnector;
|
||||
@@ -100,6 +99,7 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements
|
||||
private final Map<String, WindowedDecorator> myId2WindowedDecorator = new HashMap<>();
|
||||
private final Map<String, StripeButton> myId2StripeButton = new HashMap<>();
|
||||
private final Map<String, FocusWatcher> myId2FocusWatcher = new HashMap<>();
|
||||
private final Set<String> myDumbAwareIds = Collections.synchronizedSet(ContainerUtil.<String>newTroveSet());
|
||||
|
||||
private final EditorComponentFocusWatcher myEditorComponentFocusWatcher = new EditorComponentFocusWatcher();
|
||||
private final MyToolWindowPropertyChangeListener myToolWindowPropertyChangeListener = new MyToolWindowPropertyChangeListener();
|
||||
@@ -380,20 +380,22 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements
|
||||
myToolWindowsPane = new ToolWindowsPane(myFrame, this);
|
||||
Disposer.register(myProject, myToolWindowsPane);
|
||||
((IdeRootPane)myFrame.getRootPane()).setToolWindowsPane(myToolWindowsPane);
|
||||
List<FinalizableCommand> commandsList = new ArrayList<>();
|
||||
appendUpdateToolWindowsPaneCmd(commandsList);
|
||||
|
||||
myFrame.setTitle(FrameTitleBuilder.getInstance().getProjectTitle(myProject));
|
||||
JComponent editorComponent = createEditorComponent(myProject);
|
||||
myEditorComponentFocusWatcher.install(editorComponent);
|
||||
|
||||
appendSetEditorComponentCmd(editorComponent, commandsList);
|
||||
if (myEditorWasActive && editorComponent instanceof EditorsSplitters) {
|
||||
activateEditorComponentImpl(commandsList, true);
|
||||
}
|
||||
execute(commandsList);
|
||||
final DumbService.DumbModeListener dumbModeListener = new DumbService.DumbModeListener() {
|
||||
@Override
|
||||
public void enteredDumbMode() {
|
||||
disableStripeButtons();
|
||||
}
|
||||
|
||||
StartupManager.getInstance(myProject).registerPostStartupActivity((DumbAwareRunnable)() -> registerToolWindowsFromBeans());
|
||||
@Override
|
||||
public void exitDumbMode() {
|
||||
for (final String id : getToolWindowIds()) {
|
||||
getStripeButton(id).setEnabled(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
myProject.getMessageBus().connect().subscribe(DumbService.DUMB_MODE, dumbModeListener);
|
||||
|
||||
IdeEventQueue.getInstance().addDispatcher(e -> {
|
||||
if (e instanceof KeyEvent) {
|
||||
@@ -406,51 +408,46 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements
|
||||
}, myProject);
|
||||
}
|
||||
|
||||
private void initAll() {
|
||||
List<FinalizableCommand> commandsList = new ArrayList<>();
|
||||
appendUpdateToolWindowsPaneCmd(commandsList);
|
||||
|
||||
JComponent editorComponent = createEditorComponent(myProject);
|
||||
myEditorComponentFocusWatcher.install(editorComponent);
|
||||
|
||||
appendSetEditorComponentCmd(editorComponent, commandsList);
|
||||
if (myEditorWasActive && editorComponent instanceof EditorsSplitters) {
|
||||
activateEditorComponentImpl(commandsList, true);
|
||||
}
|
||||
execute(commandsList);
|
||||
}
|
||||
|
||||
private void disableStripeButtons() {
|
||||
for (final String id : getToolWindowIds()) {
|
||||
if (!myDumbAwareIds.contains(id)) {
|
||||
if (isToolWindowVisible(id)) {
|
||||
hideToolWindow(id, true);
|
||||
}
|
||||
StripeButton button = getStripeButton(id);
|
||||
if (button != null) {
|
||||
button.setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static JComponent createEditorComponent(@NotNull Project project) {
|
||||
return FrameEditorComponentProvider.EP.getExtensions()[0].createEditorComponent(project);
|
||||
}
|
||||
|
||||
private void registerToolWindowsFromBeans() {
|
||||
List<ToolWindowEP> beans = new ArrayList<>(Arrays.asList(Extensions.getExtensions(ToolWindowEP.EP_NAME)));
|
||||
Collections.reverse(beans);
|
||||
|
||||
checkConditionsInReadAction(beans, new ArrayList<>());
|
||||
}
|
||||
|
||||
private void checkConditionsInReadAction(@NotNull List<ToolWindowEP> beans, @NotNull List<ToolWindowEP> checkedSuccessfully) {
|
||||
ProgressIndicatorUtils.scheduleWithWriteActionPriority(new ReadTask() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Continuation performInReadAction(@NotNull ProgressIndicator indicator) throws ProcessCanceledException {
|
||||
for (int i = beans.size() - 1; i >= 0; i--) {
|
||||
indicator.checkCanceled();
|
||||
ToolWindowEP bean = beans.remove(i);
|
||||
Condition<Project> condition = ObjectUtils.notNull(bean.getCondition(), Conditions.<Project>alwaysTrue());
|
||||
if (!myProject.isDisposed() && condition.value(myProject)) {
|
||||
checkedSuccessfully.add(bean);
|
||||
}
|
||||
}
|
||||
return new Continuation(() -> {
|
||||
if (!myProject.isDisposed()) {
|
||||
for (ToolWindowEP bean : checkedSuccessfully) {
|
||||
if (getToolWindow(bean.id) == null) {
|
||||
try {
|
||||
initToolWindow(bean);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
LOG.error(String.format("Tool window %s initialization failed", bean.id), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, ModalityState.any());
|
||||
List<ToolWindowEP> beans = Arrays.asList(Extensions.getExtensions(ToolWindowEP.EP_NAME));
|
||||
for (ToolWindowEP bean : beans) {
|
||||
Condition<Project> condition = bean.getCondition();
|
||||
if (condition == null || condition.value(myProject)) {
|
||||
EdtInvocationManager.getInstance().invokeLater(() -> initToolWindow(bean));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCanceled(@NotNull ProgressIndicator indicator) {
|
||||
checkConditionsInReadAction(beans, checkedSuccessfully);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2454,4 +2451,16 @@ public final class ToolWindowManagerImpl extends ToolWindowManagerEx implements
|
||||
WindowInfoImpl info = getInfo(id);
|
||||
return info == null || info.isShowStripeButton();
|
||||
}
|
||||
|
||||
public static class InitToolWindowsActivity implements StartupActivity, DumbAware {
|
||||
@Override
|
||||
public void runActivity(@NotNull Project project) {
|
||||
ToolWindowManagerEx ex = ToolWindowManagerEx.getInstanceEx(project);
|
||||
if (ex instanceof ToolWindowManagerImpl) {
|
||||
ToolWindowManagerImpl myManager = (ToolWindowManagerImpl)ex;
|
||||
myManager.registerToolWindowsFromBeans();
|
||||
EdtInvocationManager.getInstance().invokeLater(() -> myManager.initAll());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,6 +375,7 @@
|
||||
|
||||
<postStartupActivity implementation="com.intellij.ide.TipOfTheDayManager"/>
|
||||
<postStartupActivity implementation="com.intellij.ide.actions.PowerSaveModeNotifier"/>
|
||||
<postStartupActivity implementation="com.intellij.openapi.wm.impl.ToolWindowManagerImpl$InitToolWindowsActivity" order="after OpenFilesActivity"/>
|
||||
<postStartupActivity id="OpenFilesActivity" implementation="com.intellij.openapi.fileEditor.impl.OpenFilesActivity"/>
|
||||
<postStartupActivity implementation="com.intellij.xml.breadcrumbs.BreadcrumbsInitializingActivity"/>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user