From d3dd15c7471fe27abf8babf3a79670b6e304bc0d Mon Sep 17 00:00:00 2001 From: Leonid Shalupov Date: Fri, 15 Dec 2017 16:48:05 +0100 Subject: [PATCH] RIDER-12147 Show elevation status in window title like Visual Studio does --- .../openapi/wm/impl/IdeFrameImpl.java | 9 +- .../impl/welcomeScreen/FlatWelcomeFrame.java | 2 + .../util/io/win32/WindowsElevationUtil.java | 84 +++++++++++++++++++ 3 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 platform/util/src/com/intellij/openapi/util/io/win32/WindowsElevationUtil.java diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeFrameImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeFrameImpl.java index c8b95a2428a5..c3d3b0388a59 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeFrameImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/IdeFrameImpl.java @@ -31,6 +31,7 @@ import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.util.io.win32.WindowsElevationUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.*; import com.intellij.openapi.wm.ex.IdeFrameEx; @@ -316,6 +317,10 @@ public class IdeFrameImpl extends JFrame implements IdeFrameEx, AccessibleContex updateTitle(this, myTitle, myFileTitle, myCurrentFile); } + public static String getElevationSuffix() { + return WindowsElevationUtil.isUnderElevation() ? " (Administrator)" : ""; + } + public static void updateTitle(@NotNull JFrame frame, @Nullable String title, @Nullable String fileTitle, @Nullable File currentFile) { if (ourUpdatingTitle) return; @@ -326,10 +331,10 @@ public class IdeFrameImpl extends JFrame implements IdeFrameEx, AccessibleContex Builder builder = new Builder().append(title).append(fileTitle); if (Boolean.getBoolean("ide.ui.version.in.title")) { - builder = builder.append(ApplicationNamesInfo.getInstance().getFullProductName() + ' ' + ApplicationInfo.getInstance().getFullVersion()); + builder = builder.append(ApplicationNamesInfo.getInstance().getFullProductName() + ' ' + ApplicationInfo.getInstance().getFullVersion() + getElevationSuffix()); } else if (!SystemInfo.isMac || builder.isEmpty()) { - builder = builder.append(ApplicationNamesInfo.getInstance().getFullProductName()); + builder = builder.append(ApplicationNamesInfo.getInstance().getFullProductName() + getElevationSuffix()); } frame.setTitle(builder.toString()); } diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/FlatWelcomeFrame.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/FlatWelcomeFrame.java index e0b57c2fe52c..62b48423184a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/FlatWelcomeFrame.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/FlatWelcomeFrame.java @@ -24,6 +24,7 @@ import com.intellij.openapi.ui.popup.ListItemDescriptorAdapter; import com.intellij.openapi.util.*; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.wm.*; +import com.intellij.openapi.wm.impl.IdeFrameImpl; import com.intellij.openapi.wm.impl.IdeGlassPaneImpl; import com.intellij.ui.*; import com.intellij.ui.border.CustomLineBorder; @@ -191,6 +192,7 @@ public class FlatWelcomeFrame extends JFrame implements IdeFrame, Disposable, Ac if (Boolean.getBoolean("ide.ui.version.in.title")) { title += ' ' + ApplicationInfo.getInstance().getFullVersion(); } + title += IdeFrameImpl.getElevationSuffix(); return title; } diff --git a/platform/util/src/com/intellij/openapi/util/io/win32/WindowsElevationUtil.java b/platform/util/src/com/intellij/openapi/util/io/win32/WindowsElevationUtil.java new file mode 100644 index 000000000000..07bee467f4a9 --- /dev/null +++ b/platform/util/src/com/intellij/openapi/util/io/win32/WindowsElevationUtil.java @@ -0,0 +1,84 @@ +package com.intellij.openapi.util.io.win32; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.AtomicNotNullLazyValue; +import com.intellij.openapi.util.SystemInfo; +import com.sun.jna.Structure; +import com.sun.jna.platform.win32.*; +import com.sun.jna.ptr.IntByReference; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class WindowsElevationUtil { + private static Logger LOG = Logger.getInstance(WindowsElevationUtil.class); + + private WindowsElevationUtil() { + } + + /** + * returns true if current user is having administrator privileges AND this code is running under elevation + */ + public static boolean isUnderElevation() { + return IS_UNDER_ELEVATION.getValue(); + } + + private static final AtomicNotNullLazyValue IS_UNDER_ELEVATION = new AtomicNotNullLazyValue() { + @NotNull + @Override + protected Boolean compute() { + if (!SystemInfo.isWindows) { + return false; + } + + try { + return isElevated(); + } catch (Throwable t) { + LOG.warn("Unexpected exception in WindowsElevationUtil.IS_UNDER_ELEVATION", t); + return false; + } + } + + private boolean isElevated() { + WinNT.HANDLEByReference processTokenHandle = new WinNT.HANDLEByReference(); + + boolean openProcessRc = Advapi32.INSTANCE.OpenProcessToken( + Kernel32.INSTANCE.GetCurrentProcess(), + WinNT.TOKEN_ADJUST_PRIVILEGES | WinNT.TOKEN_QUERY, processTokenHandle); + if (!openProcessRc) { + int lastError = Kernel32.INSTANCE.GetLastError(); + LOG.warn("Unable to OpenProcessToken: error " + lastError + ": " + Kernel32Util.formatMessageFromLastErrorCode(lastError)); + return false; + } + + try { + IntByReference cbNeeded = new IntByReference(0); + TOKEN_ELEVATION tokenElevation = new TOKEN_ELEVATION(); + boolean getTokenInformationRc = Advapi32.INSTANCE.GetTokenInformation( + processTokenHandle.getValue(), WinNT.TOKEN_INFORMATION_CLASS.TokenElevation, + tokenElevation, tokenElevation.size(), cbNeeded); + if (!getTokenInformationRc) { + int lastError = Kernel32.INSTANCE.GetLastError(); + LOG.warn("Unable to GetTokenInformation: error " + lastError + ": " + Kernel32Util.formatMessageFromLastErrorCode(lastError)); + return false; + } + + return tokenElevation.TokenIsElevated.intValue() != 0; + } finally { + Kernel32.INSTANCE.CloseHandle(processTokenHandle.getValue()); + } + } + }; + + public static class TOKEN_ELEVATION extends Structure { + @SuppressWarnings("WeakerAccess") + public WinDef.DWORD TokenIsElevated = new WinDef.DWORD(0); + + @Override + protected List getFieldOrder() { + return FIELDS; + } + + private static List FIELDS = createFieldsOrder("TokenIsElevated"); + } +}