mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-163208: divide TouchBarManager into separate classes
This commit is contained in:
@@ -22,7 +22,7 @@ import com.intellij.openapi.wm.IdeFocusManager;
|
||||
import com.intellij.platform.PlatformProjectOpenProcessor;
|
||||
import com.intellij.ui.mac.foundation.Foundation;
|
||||
import com.intellij.ui.mac.foundation.ID;
|
||||
import com.intellij.ui.mac.touchbar.TouchBarManager;
|
||||
import com.intellij.ui.mac.touchbar.TouchBarsManager;
|
||||
import com.sun.jna.Callback;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -138,7 +138,7 @@ public class MacOSApplicationProvider {
|
||||
});
|
||||
installAutoUpdateMenu();
|
||||
|
||||
TouchBarManager.initialize();
|
||||
TouchBarsManager.initialize();
|
||||
}
|
||||
|
||||
private static void installAutoUpdateMenu() {
|
||||
|
||||
@@ -49,7 +49,8 @@ import com.intellij.packageDependencies.ui.TreeExpansionMonitor;
|
||||
import com.intellij.ui.DoubleClickListener;
|
||||
import com.intellij.ui.FilterComponent;
|
||||
import com.intellij.ui.awt.RelativePoint;
|
||||
import com.intellij.ui.mac.touchbar.TouchBarManager;
|
||||
import com.intellij.ui.mac.touchbar.TouchBarsManager;
|
||||
import com.intellij.ui.mac.touchbar.SystemSettingsTouchBar;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.ui.EmptyIcon;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
@@ -212,11 +213,11 @@ public class KeymapPanel extends JPanel implements SearchableConfigurable, Confi
|
||||
}
|
||||
});
|
||||
|
||||
if (TouchBarManager.isTouchBarAvailable()) {
|
||||
final JCheckBox useFn = new JCheckBox("Always show FN-keys at TouchBar", TouchBarManager.isShowFnKeysEnabled());
|
||||
if (TouchBarsManager.isTouchBarAvailable()) {
|
||||
final JCheckBox useFn = new JCheckBox("Always show FN-keys at TouchBar", SystemSettingsTouchBar.isShowFnKeysEnabled());
|
||||
useFn.addChangeListener(new ChangeListener() {
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
TouchBarManager.setShowFnKeysEnabled(useFn.isSelected());
|
||||
SystemSettingsTouchBar.setShowFnKeysEnabled(useFn.isSelected());
|
||||
}
|
||||
});
|
||||
panel.add(useFn, BorderLayout.SOUTH);
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ui.mac.touchbar;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.ui.mac.foundation.ID;
|
||||
import com.intellij.util.lang.UrlClassLoader;
|
||||
import com.sun.jna.Native;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class NST {
|
||||
private static final Logger LOG = Logger.getInstance(NST.class);
|
||||
private static final NSTLibrary ourNSTLibrary;
|
||||
|
||||
static {
|
||||
final boolean isSystemSupportTouchbar = SystemInfo.isMac && SystemInfo.isOsVersionAtLeast("10.12.2");
|
||||
NSTLibrary lib = null;
|
||||
if (isSystemSupportTouchbar && Registry.is("ide.mac.touchbar.use", false) && SystemSettingsTouchBar.isTouchBarServerRunning()) {
|
||||
try {
|
||||
UrlClassLoader.loadPlatformLibrary("nst");
|
||||
|
||||
// Set JNA to convert java.lang.String to char* using UTF-8, and match that with
|
||||
// the way we tell CF to interpret our char*
|
||||
// May be removed if we use toStringViaUTF16
|
||||
System.setProperty("jna.encoding", "UTF8");
|
||||
|
||||
final Map<String, Object> nstOptions = new HashMap<>();
|
||||
lib = Native.loadLibrary("nst", NSTLibrary.class, nstOptions);
|
||||
} catch (Throwable e) {
|
||||
LOG.error("Failed to load nst library for touchbar: ", e);
|
||||
}
|
||||
}
|
||||
ourNSTLibrary = lib;
|
||||
}
|
||||
|
||||
public static boolean isAvailable() { return ourNSTLibrary != null; }
|
||||
|
||||
//
|
||||
// TODO: syncronization between AppKit and EDT will be implemented in next commit
|
||||
//
|
||||
|
||||
public static ID createTouchBar(String name, NSTLibrary.ItemCreator creator) {
|
||||
return ourNSTLibrary.createTouchBar(name, creator);
|
||||
}
|
||||
|
||||
public static void releaseTouchBar(ID tbObj) {
|
||||
ourNSTLibrary.releaseTouchBar(tbObj);
|
||||
}
|
||||
|
||||
public static void setTouchBar(TouchBar tb) {
|
||||
ourNSTLibrary.setTouchBar(tb == null ? ID.NIL : tb.getNativePeer());
|
||||
}
|
||||
|
||||
public static void selectItemsToShow(ID tbObj, String[] ids, int count) {
|
||||
ourNSTLibrary.selectItemsToShow(tbObj, ids, count);
|
||||
}
|
||||
|
||||
public static ID createButton(String uid,
|
||||
int buttWidth,
|
||||
String text,
|
||||
byte[] raster4ByteRGBA,
|
||||
int w,
|
||||
int h,
|
||||
NSTLibrary.Action action) {
|
||||
return ourNSTLibrary.createButton(uid, buttWidth, text, raster4ByteRGBA, w, h, action);
|
||||
}
|
||||
|
||||
public static ID createPopover(String uid,
|
||||
int itemWidth,
|
||||
String text,
|
||||
byte[] raster4ByteRGBA,
|
||||
int w,
|
||||
int h,
|
||||
ID tbObjExpand,
|
||||
ID tbObjTapAndHold) {
|
||||
return ourNSTLibrary.createPopover(uid, itemWidth, text, raster4ByteRGBA, w, h, tbObjExpand, tbObjTapAndHold);
|
||||
}
|
||||
|
||||
public static ID createScrubber(String uid,
|
||||
int itemWidth,
|
||||
NSTLibrary.ScrubberItemsSource source,
|
||||
NSTLibrary.ScrubberItemsCount count,
|
||||
NSTLibrary.ActionWithIndex actions) {
|
||||
return ourNSTLibrary.createScrubber(uid, itemWidth, source, count, actions);
|
||||
}
|
||||
|
||||
public static void updateButton(ID buttonObj,
|
||||
int buttWidth,
|
||||
String text,
|
||||
byte[] raster4ByteRGBA,
|
||||
int w,
|
||||
int h,
|
||||
NSTLibrary.Action action) {
|
||||
ourNSTLibrary.updateButton(buttonObj, buttWidth, text, raster4ByteRGBA, w, h, action);
|
||||
}
|
||||
|
||||
public static void updatePopover(ID popoverObj,
|
||||
int itemWidth,
|
||||
String text,
|
||||
byte[] raster4ByteRGBA,
|
||||
int w,
|
||||
int h,
|
||||
ID tbObjExpand, ID tbObjTapAndHold) {
|
||||
ourNSTLibrary.updatePopover(popoverObj, itemWidth, text, raster4ByteRGBA, w, h, tbObjExpand, tbObjTapAndHold);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ui.mac.touchbar;
|
||||
|
||||
import com.intellij.execution.ExecutionException;
|
||||
import com.intellij.execution.configurations.GeneralCommandLine;
|
||||
import com.intellij.execution.process.ProcessOutput;
|
||||
import com.intellij.execution.util.ExecUtil;
|
||||
import com.intellij.openapi.application.impl.ApplicationInfoImpl;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.ui.mac.foundation.Foundation;
|
||||
import com.intellij.ui.mac.foundation.ID;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class SystemSettingsTouchBar {
|
||||
private static final Logger LOG = Logger.getInstance(SystemSettingsTouchBar.class);
|
||||
|
||||
private static final String ourTBServerProcessName = "TouchBarServer";
|
||||
private static final String ourDefaultsDomain = "com.apple.touchbar.agent";
|
||||
private static final String ourDefaultsNode = "PresentationModePerApp";
|
||||
private static final String ourDefaultsValue = "functionKeys";
|
||||
private static final String ourApplicationId;
|
||||
|
||||
static {
|
||||
// TODO: obtain "OS X Application identifier' via platform api
|
||||
ourApplicationId = ApplicationInfoImpl.getInstanceEx().isEAP() ? "com.jetbrains.intellij-EAP" : "com.jetbrains.intellij";
|
||||
}
|
||||
|
||||
static boolean isTouchBarServerRunning() {
|
||||
final GeneralCommandLine cmdLine = new GeneralCommandLine("pgrep", ourTBServerProcessName);
|
||||
try {
|
||||
final ProcessOutput out = ExecUtil.execAndGetOutput(cmdLine);
|
||||
return !out.getStdout().isEmpty();
|
||||
} catch (ExecutionException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isShowFnKeysEnabled() {
|
||||
final ID defaults = Foundation.invoke("NSUserDefaults", "standardUserDefaults");
|
||||
final ID domain = Foundation.invoke(defaults, "persistentDomainForName:", Foundation.nsString(ourDefaultsDomain));
|
||||
final ID node = Foundation.invoke(domain, "objectForKey:", Foundation.nsString(ourDefaultsNode));
|
||||
final ID val = Foundation.invoke(node, "objectForKey:", Foundation.nsString(ourApplicationId));
|
||||
final String sval = Foundation.toStringViaUTF8(val);
|
||||
return sval != null && sval.equals(ourDefaultsValue);
|
||||
}
|
||||
|
||||
public static void setShowFnKeysEnabled(boolean val) {
|
||||
final ID defaults = Foundation.invoke("NSUserDefaults", "standardUserDefaults");
|
||||
final ID domain = Foundation.invoke(defaults, "persistentDomainForName:", Foundation.nsString(ourDefaultsDomain));
|
||||
final ID node = Foundation.invoke(domain, "objectForKey:", Foundation.nsString(ourDefaultsNode));
|
||||
final ID nsVal = Foundation.invoke(node, "objectForKey:", Foundation.nsString(ourApplicationId));
|
||||
final String sval = Foundation.toStringViaUTF8(nsVal);
|
||||
final boolean settingEnabled = sval != null && sval.equals(ourDefaultsValue);
|
||||
if (val == settingEnabled)
|
||||
return;
|
||||
|
||||
final ID mdomain = Foundation.invoke(domain, "mutableCopy");
|
||||
final ID mnode = Foundation.invoke(node, "mutableCopy");
|
||||
if (val)
|
||||
Foundation.invoke(mnode, "setObject:forKey:", Foundation.nsString(ourDefaultsValue), Foundation.nsString(ourApplicationId));
|
||||
else
|
||||
Foundation.invoke(mnode, "removeObjectForKey:", Foundation.nsString(ourApplicationId));
|
||||
Foundation.invoke(mdomain, "setObject:forKey:", mnode, Foundation.nsString(ourDefaultsNode));
|
||||
Foundation.invoke(defaults, "setPersistentDomain:forName:", mdomain, Foundation.nsString(ourDefaultsDomain));
|
||||
|
||||
try {
|
||||
ExecUtil.sudo(new GeneralCommandLine("pkill", ourTBServerProcessName), "");
|
||||
} catch (ExecutionException e) {
|
||||
LOG.error(e);
|
||||
} catch (IOException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,11 +33,11 @@ public class TBItemButton extends TBItem {
|
||||
|
||||
@Override
|
||||
protected void _updateNativePeer() {
|
||||
TouchBarManager.getNSTLibrary().updateButton(myNativePeer, myWidth, myText, getRaster(myIcon), getIconW(myIcon), getIconH(myIcon), myAction);
|
||||
NST.updateButton(myNativePeer, myWidth, myText, getRaster(myIcon), getIconW(myIcon), getIconH(myIcon), myAction);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ID _createNativePeer() {
|
||||
return TouchBarManager.getNSTLibrary().createButton(myUid, myWidth, myText, getRaster(myIcon), getIconW(myIcon), getIconH(myIcon), myAction);
|
||||
return NST.createButton(myUid, myWidth, myText, getRaster(myIcon), getIconW(myIcon), getIconH(myIcon), myAction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,12 +51,12 @@ public class TBItemPopover extends TBItem {
|
||||
|
||||
@Override
|
||||
protected void _updateNativePeer() {
|
||||
TouchBarManager.getNSTLibrary().updatePopover(myNativePeer, myWidthPix, myText, getRaster(myIcon), getIconW(myIcon), getIconH(myIcon), getNativePeer(myExpandTB), getNativePeer(myTapAndHoldTB));
|
||||
NST.updatePopover(myNativePeer, myWidthPix, myText, getRaster(myIcon), getIconW(myIcon), getIconH(myIcon), getNativePeer(myExpandTB), getNativePeer(myTapAndHoldTB));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ID _createNativePeer() {
|
||||
return TouchBarManager.getNSTLibrary().createPopover(myUid, myWidthPix, myText, getRaster(myIcon), getIconW(myIcon), getIconH(myIcon), getNativePeer(myExpandTB), getNativePeer(myTapAndHoldTB));
|
||||
return NST.createPopover(myUid, myWidthPix, myText, getRaster(myIcon), getIconW(myIcon), getIconH(myIcon), getNativePeer(myExpandTB), getNativePeer(myTapAndHoldTB));
|
||||
}
|
||||
|
||||
private static ID getNativePeer(TouchBar tb) { return tb == null ? ID.NIL : tb.getNativePeer(); }
|
||||
|
||||
@@ -42,7 +42,7 @@ public class TBItemScrubber extends TBItem {
|
||||
|
||||
@Override
|
||||
protected ID _createNativePeer() {
|
||||
return TouchBarManager.getNSTLibrary().createScrubber(myUid, myWidth, mySource, myCount, myActions);
|
||||
return NST.createScrubber(myUid, myWidth, mySource, myCount, myActions);
|
||||
}
|
||||
|
||||
public void executeAt(int index) {
|
||||
|
||||
@@ -18,7 +18,7 @@ public class TouchBar implements NSTLibrary.ItemCreator {
|
||||
|
||||
TouchBar(String touchbarName) {
|
||||
myName = touchbarName;
|
||||
myNativePeer = TouchBarManager.getNSTLibrary().createTouchBar(touchbarName, this);
|
||||
myNativePeer = NST.createTouchBar(touchbarName, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -37,7 +37,7 @@ public class TouchBar implements NSTLibrary.ItemCreator {
|
||||
void release() {
|
||||
for (TBItem item : myItems)
|
||||
item.releaseNativePeer();
|
||||
TouchBarManager.getNSTLibrary().releaseTouchBar(myNativePeer);
|
||||
NST.releaseTouchBar(myNativePeer);
|
||||
|
||||
myItems.clear();
|
||||
myNativePeer = ID.NIL;
|
||||
@@ -94,7 +94,7 @@ public class TouchBar implements NSTLibrary.ItemCreator {
|
||||
for (TBItem item : myItems)
|
||||
ids[c++] = item.myUid;
|
||||
|
||||
TouchBarManager.getNSTLibrary().selectItemsToShow(myNativePeer, ids, ids.length);
|
||||
NST.selectItemsToShow(myNativePeer, ids, ids.length);
|
||||
}
|
||||
|
||||
private TBItem findItem(String uid) {
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ui.mac.touchbar;
|
||||
|
||||
import com.intellij.execution.ExecutionListener;
|
||||
import com.intellij.execution.ExecutionManager;
|
||||
import com.intellij.execution.RunManager;
|
||||
import com.intellij.execution.RunnerAndConfigurationSettings;
|
||||
import com.intellij.execution.process.ProcessHandler;
|
||||
import com.intellij.execution.runners.ExecutionEnvironment;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.actionSystem.IdeActions;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.IconLoader;
|
||||
import com.intellij.ui.mac.foundation.Foundation;
|
||||
import com.intellij.ui.mac.foundation.ID;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class TouchBarGeneral extends TouchBar {
|
||||
private static final Map<Project, TouchBarGeneral> ourInstances = new HashMap<>();
|
||||
|
||||
private TBItemButton myButtonStop = null;
|
||||
|
||||
private TouchBarGeneral(Project project) {
|
||||
super("general");
|
||||
|
||||
addButton(AllIcons.Toolwindows.ToolWindowBuild, null, "CompileDirty"); // NOTE: IdeActions.ACTION_COMPILE doesn't work
|
||||
|
||||
final RunManager rm = RunManager.getInstance(project);
|
||||
final RunnerAndConfigurationSettings selected = rm.getSelectedConfiguration();
|
||||
if (selected != null) {
|
||||
final TouchBar tapHoldTB = new TouchBar("run_configs_popover_tap_and_hold");
|
||||
final TouchBar expandTB = new TouchBar("run_configs_popover_expand");
|
||||
final TBItemPopover popover = addPopover(selected.getConfiguration().getIcon(), selected.getName(), 143, expandTB, tapHoldTB);
|
||||
|
||||
tapHoldTB.addFlexibleSpacing();
|
||||
tapHoldTB.addButton(selected.getConfiguration().getIcon(), selected.getName(), (NSTLibrary.Action)null);
|
||||
tapHoldTB.selectAllItemsToShow();
|
||||
|
||||
expandTB.addButton(AllIcons.Actions.EditSource, null, IdeActions.ACTION_EDIT_RUN_CONFIGURATIONS);
|
||||
final TBItemScrubber scrubber = expandTB.addScrubber(500);
|
||||
List<RunnerAndConfigurationSettings> allRunCongigs = rm.getAllSettings();
|
||||
for (RunnerAndConfigurationSettings rc : allRunCongigs) {
|
||||
final Icon iconRc = rc.getConfiguration().getIcon();
|
||||
scrubber.addItem(iconRc, rc.getName(), () -> {
|
||||
rm.setSelectedConfiguration(rc);
|
||||
popover.update(iconRc, rc.getName());
|
||||
popover.dismiss();
|
||||
});
|
||||
}
|
||||
expandTB.addFlexibleSpacing();
|
||||
expandTB.selectAllItemsToShow();
|
||||
|
||||
addButton(AllIcons.Toolwindows.ToolWindowRun, null, IdeActions.ACTION_DEFAULT_RUNNER);
|
||||
addButton(AllIcons.Toolwindows.ToolWindowDebugger, null, IdeActions.ACTION_DEFAULT_DEBUGGER);
|
||||
myButtonStop = addButton(IconLoader.getDisabledIcon(AllIcons.Actions.Suspend), null, (NSTLibrary.Action)null);
|
||||
}
|
||||
|
||||
addSpacing(true);
|
||||
addButton(AllIcons.Actions.CheckOut, null, new PlatformAction("Vcs.UpdateProject")); // NOTE: IdeActions.ACTION_CVS_CHECKOUT doesn't works
|
||||
addButton(AllIcons.Actions.Commit, null, new PlatformAction("CheckinProject")); // NOTE: IdeActions.ACTION_CVS_COMMIT doesn't works
|
||||
|
||||
selectAllItemsToShow();
|
||||
|
||||
ApplicationManager.getApplication().getMessageBus().connect().subscribe(ExecutionManager.EXECUTION_TOPIC, new ExecutionListener() {
|
||||
@Override
|
||||
public void processStarted(@NotNull String executorId, @NotNull ExecutionEnvironment env, @NotNull ProcessHandler handler) {
|
||||
myButtonStop.update(AllIcons.Actions.Suspend, null, new PlatformAction("Stop"));
|
||||
// TODO: implement other items update
|
||||
}
|
||||
@Override
|
||||
public void processTerminated(@NotNull String executorId, @NotNull ExecutionEnvironment env, @NotNull ProcessHandler handler, int exitCode) {
|
||||
myButtonStop.update(IconLoader.getDisabledIcon(AllIcons.Actions.Suspend), null, (NSTLibrary.Action)null);
|
||||
// TODO: implement other items update
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static @NotNull TouchBarGeneral instance(@NotNull Project project) {
|
||||
// NOTE: called from EDT only
|
||||
TouchBarGeneral result = ourInstances.get(project);
|
||||
if (result == null) {
|
||||
final ID pool = Foundation.invoke("NSAutoreleasePool", "new");
|
||||
try {
|
||||
result = new TouchBarGeneral(project);
|
||||
ourInstances.put(project, result);
|
||||
} finally {
|
||||
Foundation.invoke(pool, "release");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void release(@NotNull Project project) {
|
||||
// NOTE: called from EDT only
|
||||
TouchBarGeneral result = ourInstances.remove(project);
|
||||
if (result != null)
|
||||
result.release();
|
||||
}
|
||||
}
|
||||
@@ -1,272 +0,0 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ui.mac.touchbar;
|
||||
|
||||
import com.intellij.execution.*;
|
||||
import com.intellij.execution.configurations.GeneralCommandLine;
|
||||
import com.intellij.execution.process.ProcessHandler;
|
||||
import com.intellij.execution.process.ProcessOutput;
|
||||
import com.intellij.execution.runners.ExecutionEnvironment;
|
||||
import com.intellij.execution.util.ExecUtil;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.actionSystem.IdeActions;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.impl.ApplicationInfoImpl;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.project.ProjectManagerListener;
|
||||
import com.intellij.openapi.util.IconLoader;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.ui.mac.foundation.Foundation;
|
||||
import com.intellij.ui.mac.foundation.ID;
|
||||
import com.intellij.util.lang.UrlClassLoader;
|
||||
import com.sun.jna.Native;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.image.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class TouchBarManager {
|
||||
private static final Logger ourLog = Logger.getInstance(TouchBar.class);
|
||||
|
||||
private static final String ourTBServerProcessName = "TouchBarServer";
|
||||
private static final String ourDefaultsDomain = "com.apple.touchbar.agent";
|
||||
private static final String ourDefaultsNode = "PresentationModePerApp";
|
||||
private static final String ourDefaultsValue = "functionKeys";
|
||||
private static final String ourApplicationId;
|
||||
private static final NSTLibrary ourNSTLibrary;
|
||||
private static TouchBar ourTouchbar;
|
||||
|
||||
static {
|
||||
// NOTE: can also check existence of process 'ControlStrip' to determine touchbar availability
|
||||
final boolean isSystemSupportTouchbar = SystemInfo.isMac && SystemInfo.isOsVersionAtLeast("10.12.1");
|
||||
NSTLibrary lib = null;
|
||||
if (isSystemSupportTouchbar && Registry.is("ide.mac.touchbar.use", false) && isTouchBarServerRunning()) {
|
||||
try {
|
||||
UrlClassLoader.loadPlatformLibrary("nst");
|
||||
|
||||
// Set JNA to convert java.lang.String to char* using UTF-8, and match that with
|
||||
// the way we tell CF to interpret our char*
|
||||
// May be removed if we use toStringViaUTF16
|
||||
System.setProperty("jna.encoding", "UTF8");
|
||||
|
||||
final Map<String, Object> nstOptions = new HashMap<>();
|
||||
lib = Native.loadLibrary("nst", NSTLibrary.class, nstOptions);
|
||||
} catch (Throwable e) {
|
||||
ourLog.error("Failed to load nst library for touchbar: ", e);
|
||||
}
|
||||
}
|
||||
ourNSTLibrary = lib;
|
||||
|
||||
// TODO: obtain "OS X Application identifier' via platform api
|
||||
ourApplicationId = ApplicationInfoImpl.getInstanceEx().isEAP() ? "com.jetbrains.intellij-EAP" : "com.jetbrains.intellij";
|
||||
}
|
||||
|
||||
public enum TOUCHBARS {
|
||||
main,
|
||||
debug,
|
||||
test; /*only for testing purposes*/
|
||||
|
||||
private TouchBar myTB = null;
|
||||
|
||||
TouchBar get(Project project) {
|
||||
if (myTB == null) {
|
||||
final ID pool = Foundation.invoke("NSAutoreleasePool", "new");
|
||||
try {
|
||||
if (this == main) {
|
||||
if (project == null) {
|
||||
ourLog.error("can't create 'main' touchbar: passed null project");
|
||||
return null;
|
||||
}
|
||||
|
||||
myTB = new TouchBar(name());
|
||||
myTB.addButton(AllIcons.Toolwindows.ToolWindowBuild, null, "CompileDirty"); // NOTE: IdeActions.ACTION_COMPILE doesn't work
|
||||
|
||||
final RunManager rm = RunManager.getInstance(project);
|
||||
final RunnerAndConfigurationSettings selected = rm.getSelectedConfiguration();
|
||||
if (selected != null) {
|
||||
final TouchBar tapHoldTB = new TouchBar("run_configs_popover_tap_and_hold");
|
||||
final TouchBar expandTB = new TouchBar("run_configs_popover_expand");
|
||||
final TBItemPopover popover = myTB.addPopover(selected.getConfiguration().getIcon(), selected.getName(), 143, expandTB, tapHoldTB);
|
||||
|
||||
tapHoldTB.addFlexibleSpacing();
|
||||
tapHoldTB.addButton(selected.getConfiguration().getIcon(), selected.getName(), () -> {}); // TODO: remove button, use NSView with 'image+text'
|
||||
tapHoldTB.selectAllItemsToShow();
|
||||
|
||||
expandTB.addButton(AllIcons.Actions.EditSource, null, IdeActions.ACTION_EDIT_RUN_CONFIGURATIONS);
|
||||
final TBItemScrubber scrubber = expandTB.addScrubber(500);
|
||||
List<RunnerAndConfigurationSettings> allRunCongigs = rm.getAllSettings();
|
||||
for (RunnerAndConfigurationSettings rc : allRunCongigs) {
|
||||
final Icon iconRc = rc.getConfiguration().getIcon();
|
||||
scrubber.addItem(iconRc, rc.getName(), () -> {
|
||||
rm.setSelectedConfiguration(rc);
|
||||
popover.update(iconRc, rc.getName());
|
||||
popover.dismiss();
|
||||
});
|
||||
}
|
||||
expandTB.addFlexibleSpacing();
|
||||
expandTB.selectAllItemsToShow();
|
||||
|
||||
myTB.addButton(AllIcons.Toolwindows.ToolWindowRun, null, IdeActions.ACTION_DEFAULT_RUNNER);
|
||||
myTB.addButton(AllIcons.Toolwindows.ToolWindowDebugger, null, IdeActions.ACTION_DEFAULT_DEBUGGER);
|
||||
myTB.addButton(IconLoader.getDisabledIcon(AllIcons.Actions.Suspend), null, (NSTLibrary.Action)null);
|
||||
}
|
||||
|
||||
myTB.addSpacing(true);
|
||||
myTB.addButton(AllIcons.Actions.CheckOut, null, new PlatformAction("Vcs.UpdateProject")); // NOTE: IdeActions.ACTION_CVS_CHECKOUT doesn't works
|
||||
myTB.addButton(AllIcons.Actions.Commit, null, new PlatformAction("CheckinProject")); // NOTE: IdeActions.ACTION_CVS_COMMIT doesn't works
|
||||
}
|
||||
else if (this == debug) {
|
||||
myTB = new TouchBar(name());
|
||||
myTB.addButton(null, "Step Over", "Step Over");
|
||||
myTB.addButton(null, "Step Into", "Step Into");
|
||||
myTB.addButton(AllIcons.Actions.Suspend, null, "Stop");
|
||||
}
|
||||
else if (this == test) {
|
||||
myTB = new TouchBar(name());
|
||||
myTB.addSpacing(true);
|
||||
myTB.addButton(null, "test1", createPrintTextCallback("pressed test1 button"));
|
||||
myTB.addButton(null, "test2", createPrintTextCallback("pressed test2 button"));
|
||||
myTB.addSpacing(false);
|
||||
myTB.addButton(AllIcons.Toolwindows.ToolWindowRun, null, createPrintTextCallback("pressed image button"));
|
||||
|
||||
|
||||
final TouchBar tapHoldTB = new TouchBar("test_popover_tap_and_hold");
|
||||
final TouchBar expandTB = new TouchBar("test_configs_popover_expand");
|
||||
final int configPopoverWidth = 143;
|
||||
myTB.addPopover(AllIcons.Toolwindows.ToolWindowBuild, "test-popover", configPopoverWidth, expandTB, tapHoldTB);
|
||||
|
||||
expandTB.addButton(AllIcons.Toolwindows.ToolWindowDebugger, null, createPrintTextCallback("pressed pimage button"));
|
||||
final TBItemScrubber scrubber = expandTB.addScrubber(450);
|
||||
for (int c = 0; c < 15; ++c) {
|
||||
String txt;
|
||||
if (c == 7) txt = "very very long configuration name (debugging type)";
|
||||
else txt = String.format("r%1.2f", Math.random());
|
||||
int finalC = c;
|
||||
scrubber.addItem(AllIcons.Toolwindows.ToolWindowPalette, txt,
|
||||
() -> System.out.println("JAVA: performed action of scrubber item at index " + finalC + " [thread:" + Thread.currentThread() + "]"));
|
||||
}
|
||||
expandTB.selectAllItemsToShow();
|
||||
|
||||
tapHoldTB.addButton(AllIcons.Toolwindows.ToolWindowPalette, null, createPrintTextCallback("pressed pimage button"));
|
||||
tapHoldTB.selectAllItemsToShow();
|
||||
}
|
||||
|
||||
if (myTB != null)
|
||||
myTB.selectAllItemsToShow();
|
||||
}
|
||||
finally {
|
||||
Foundation.invoke(pool, "release");
|
||||
}
|
||||
}
|
||||
return myTB;
|
||||
}
|
||||
|
||||
void release() {
|
||||
if (myTB == null)
|
||||
return;
|
||||
|
||||
myTB.release();
|
||||
myTB = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void initialize() {
|
||||
if (!isTouchBarAvailable())
|
||||
return;
|
||||
|
||||
final ID app = Foundation.invoke("NSApplication", "sharedApplication");
|
||||
Foundation.invoke(app, "setAutomaticCustomizeTouchBarMenuItemEnabled:", true);
|
||||
|
||||
ApplicationManager.getApplication().getMessageBus().connect().subscribe(ProjectManager.TOPIC, new ProjectManagerListener() {
|
||||
@Override
|
||||
public void projectOpened(Project project) {
|
||||
ourTouchbar = TOUCHBARS.main.get(project);
|
||||
if (ourTouchbar == null)
|
||||
return;
|
||||
|
||||
ourNSTLibrary.setTouchBar(ourTouchbar.getNativePeer());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void setCurrent(TOUCHBARS tbType) {
|
||||
if (tbType == null || !isTouchBarAvailable())
|
||||
return;
|
||||
|
||||
ourTouchbar = tbType.get(null);
|
||||
if (ourTouchbar == null)
|
||||
return;
|
||||
|
||||
ourNSTLibrary.setTouchBar(ourTouchbar.getNativePeer());
|
||||
}
|
||||
|
||||
static NSTLibrary getNSTLibrary() { return ourNSTLibrary; }
|
||||
|
||||
public static boolean isTouchBarAvailable() { return ourNSTLibrary != null; }
|
||||
|
||||
private static boolean isTouchBarServerRunning() {
|
||||
final GeneralCommandLine cmdLine = new GeneralCommandLine("pgrep", ourTBServerProcessName);
|
||||
try {
|
||||
final ProcessOutput out = ExecUtil.execAndGetOutput(cmdLine);
|
||||
return !out.getStdout().isEmpty();
|
||||
} catch (ExecutionException e) {
|
||||
ourLog.error(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isShowFnKeysEnabled() {
|
||||
final ID defaults = Foundation.invoke("NSUserDefaults", "standardUserDefaults");
|
||||
final ID domain = Foundation.invoke(defaults, "persistentDomainForName:", Foundation.nsString(ourDefaultsDomain));
|
||||
final ID node = Foundation.invoke(domain, "objectForKey:", Foundation.nsString(ourDefaultsNode));
|
||||
final ID val = Foundation.invoke(node, "objectForKey:", Foundation.nsString(ourApplicationId));
|
||||
final String sval = Foundation.toStringViaUTF8(val);
|
||||
return sval != null && sval.equals(ourDefaultsValue);
|
||||
}
|
||||
|
||||
public static void setShowFnKeysEnabled(boolean val) {
|
||||
final ID defaults = Foundation.invoke("NSUserDefaults", "standardUserDefaults");
|
||||
final ID domain = Foundation.invoke(defaults, "persistentDomainForName:", Foundation.nsString(ourDefaultsDomain));
|
||||
final ID node = Foundation.invoke(domain, "objectForKey:", Foundation.nsString(ourDefaultsNode));
|
||||
final ID nsVal = Foundation.invoke(node, "objectForKey:", Foundation.nsString(ourApplicationId));
|
||||
final String sval = Foundation.toStringViaUTF8(nsVal);
|
||||
final boolean settingEnabled = sval != null && sval.equals(ourDefaultsValue);
|
||||
if (val == settingEnabled)
|
||||
return;
|
||||
|
||||
final ID mdomain = Foundation.invoke(domain, "mutableCopy");
|
||||
final ID mnode = Foundation.invoke(node, "mutableCopy");
|
||||
if (val)
|
||||
Foundation.invoke(mnode, "setObject:forKey:", Foundation.nsString(ourDefaultsValue), Foundation.nsString(ourApplicationId));
|
||||
else
|
||||
Foundation.invoke(mnode, "removeObjectForKey:", Foundation.nsString(ourApplicationId));
|
||||
Foundation.invoke(mdomain, "setObject:forKey:", mnode, Foundation.nsString(ourDefaultsNode));
|
||||
Foundation.invoke(defaults, "setPersistentDomain:forName:", mdomain, Foundation.nsString(ourDefaultsDomain));
|
||||
|
||||
try {
|
||||
ExecUtil.sudo(new GeneralCommandLine("pkill", ourTBServerProcessName), "");
|
||||
} catch (ExecutionException e) {
|
||||
ourLog.error(e);
|
||||
} catch (IOException e) {
|
||||
ourLog.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static NSTLibrary.Action createPrintTextCallback(String text) {
|
||||
return new NSTLibrary.Action() {
|
||||
@Override
|
||||
public void execute() {
|
||||
System.out.println(text + " [thread:" + Thread.currentThread() + "]");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ui.mac.touchbar;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.project.ProjectManagerListener;
|
||||
import com.intellij.ui.mac.foundation.Foundation;
|
||||
import com.intellij.ui.mac.foundation.ID;
|
||||
|
||||
public class TouchBarsManager {
|
||||
private final static boolean IS_LOGGING_ENABLED = false;
|
||||
private static final Logger LOG = Logger.getInstance(TouchBar.class);
|
||||
|
||||
public static void initialize() {
|
||||
if (!isTouchBarAvailable())
|
||||
return;
|
||||
|
||||
final ID app = Foundation.invoke("NSApplication", "sharedApplication");
|
||||
Foundation.invoke(app, "setAutomaticCustomizeTouchBarMenuItemEnabled:", true);
|
||||
|
||||
ApplicationManager.getApplication().getMessageBus().connect().subscribe(ProjectManager.TOPIC, new ProjectManagerListener() {
|
||||
@Override
|
||||
public void projectOpened(Project project) {
|
||||
trace("opened project %s, set general touchbar", project);
|
||||
NST.setTouchBar(TouchBarGeneral.instance(project));
|
||||
}
|
||||
@Override
|
||||
public void projectClosed(Project project) {
|
||||
trace("closed project %s, hide touchbar", project);
|
||||
NST.setTouchBar(null);
|
||||
TouchBarGeneral.release(project);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static boolean isTouchBarAvailable() { return NST.isAvailable(); }
|
||||
|
||||
private static void trace(String fmt, Object... args) {
|
||||
if (IS_LOGGING_ENABLED)
|
||||
LOG.trace(String.format(fmt, args));
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.ui.mac.touchbar;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ui.mac.foundation.Foundation;
|
||||
import com.intellij.ui.mac.foundation.ID;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
@@ -9,8 +11,40 @@ public class TouchbarTest {
|
||||
public static void main(String[] args) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
Foundation.init();
|
||||
TouchBarManager.initialize();
|
||||
TouchBarManager.setCurrent(TouchBarManager.TOUCHBARS.test);
|
||||
|
||||
final ID pool = Foundation.invoke("NSAutoreleasePool", "new");
|
||||
try {
|
||||
final TouchBar testTB = new TouchBar("test");
|
||||
testTB.addSpacing(true);
|
||||
testTB.addButton(null, "test1", createPrintTextCallback("pressed test1 button"));
|
||||
testTB.addButton(null, "test2", createPrintTextCallback("pressed test2 button"));
|
||||
testTB.addSpacing(false);
|
||||
testTB.addButton(AllIcons.Toolwindows.ToolWindowRun, null, createPrintTextCallback("pressed image button"));
|
||||
|
||||
final TouchBar tapHoldTB = new TouchBar("test_popover_tap_and_hold");
|
||||
final TouchBar expandTB = new TouchBar("test_configs_popover_expand");
|
||||
final int configPopoverWidth = 143;
|
||||
testTB.addPopover(AllIcons.Toolwindows.ToolWindowBuild, "test-popover", configPopoverWidth, expandTB, tapHoldTB);
|
||||
|
||||
expandTB.addButton(AllIcons.Toolwindows.ToolWindowDebugger, null, createPrintTextCallback("pressed pimage button"));
|
||||
final TBItemScrubber scrubber = expandTB.addScrubber(450);
|
||||
for (int c = 0; c < 15; ++c) {
|
||||
String txt;
|
||||
if (c == 7) txt = "very very long configuration name (debugging type)";
|
||||
else txt = String.format("r%1.2f", Math.random());
|
||||
int finalC = c;
|
||||
scrubber.addItem(AllIcons.Toolwindows.ToolWindowPalette, txt,
|
||||
() -> System.out.println("JAVA: performed action of scrubber item at index " + finalC + " [thread:" + Thread.currentThread() + "]"));
|
||||
}
|
||||
expandTB.selectAllItemsToShow();
|
||||
|
||||
tapHoldTB.addButton(AllIcons.Toolwindows.ToolWindowPalette, null, createPrintTextCallback("pressed pimage button"));
|
||||
tapHoldTB.selectAllItemsToShow();
|
||||
|
||||
NST.setTouchBar(testTB);
|
||||
} finally {
|
||||
Foundation.invoke(pool, "release");
|
||||
}
|
||||
|
||||
final JFrame f = new JFrame();
|
||||
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
|
||||
@@ -18,5 +52,14 @@ public class TouchbarTest {
|
||||
f.setVisible(true);
|
||||
});
|
||||
}
|
||||
|
||||
private static NSTLibrary.Action createPrintTextCallback(String text) {
|
||||
return new NSTLibrary.Action() {
|
||||
@Override
|
||||
public void execute() {
|
||||
System.out.println(text + " [thread:" + Thread.currentThread() + "]");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user