Как скрыть значок док-станции

Я хочу настроить скрытие значка Dock и отображение NSStatusItem. Я могу создать StatusItem, но не знаю, как удалить значок из Dock. : - /

Любые идеи?


person papr    schedule 06.03.2009    source источник
comment
если ваше приложение основано на Qt5, вам также необходимо установить envvar QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM   -  person Chris Dolan    schedule 01.05.2015


Ответы (7)


Я думаю, вы ищете LSUIElement в Info.plist

LSUIElement (Строка). Если для этого ключа установлено значение «1», Launch Services запускает приложение как приложение-агент. Приложения агента не отображаются в доке или в окне принудительного выхода. Хотя они обычно работают как фоновые приложения, при желании они могут выходить на передний план, чтобы представить пользовательский интерфейс.

См. Краткое обсуждение здесь о его включении и выключении.

person epatel    schedule 07.03.2009
comment
Ссылка мертвая. - person Pedro Paulo Amorim; 03.04.2019

Вы можете использовать то, что называется Политикой активации:

Цель-C

// The application is an ordinary app that appears in the Dock and may
// have a user interface.
[NSApp setActivationPolicy: NSApplicationActivationPolicyRegular];

// The application does not appear in the Dock and does not have a menu
// bar, but it may be activated programmatically or by clicking on one
// of its windows.
[NSApp setActivationPolicy: NSApplicationActivationPolicyAccessory];

// The application does not appear in the Dock and may not create
// windows or be activated.
[NSApp setActivationPolicy: NSApplicationActivationPolicyProhibited];

Swift 4

// The application is an ordinary app that appears in the Dock and may
// have a user interface.
NSApp.setActivationPolicy(.regular)

// The application does not appear in the Dock and does not have a menu
// bar, but it may be activated programmatically or by clicking on one
// of its windows.
NSApp.setActivationPolicy(.accessory)

// The application does not appear in the Dock and may not create
// windows or be activated.
NSApp.setActivationPolicy(.prohibited)

Это должно скрыть значок док-станции.

Смотрите также

person Albert    schedule 10.02.2012
comment
Это определенно самое элегантное решение. Прекрасно работает. - person codingFriend1; 06.06.2013
comment
+1. NSApplicationActivationPolicyAccessory фактически позволяет отображать главное меню. - person Mark Bao; 23.06.2013
comment
Из документации Apple: в настоящее время NSApplicationActivationPolicyNone и NSApplicationActivationPolicyAccessory можно изменить на NSApplicationActivationPolicyRegular, но другие модификации не поддерживаются. - person Scott Allen; 04.09.2013
comment
Единственный правильный путь. Другие решения - это некоторые виды взломов. Также можно изменять поведение док-станции на лету. - person Al Zonke; 08.12.2013
comment
отличный способ! самый простой способ! - person slboat; 31.05.2015
comment
В последнем комментарии заголовка говорится: В OS X 10.9 можно установить любую политику; до 10.9 политика активации может быть изменена на NSApplicationActivationPolicyProhibited или NSApplicationActivationPolicyRegular, но не может быть изменена на NSApplicationActivationPolicyAccessory. Это возвращает ДА, если установка политики активации прошла успешно, и НЕТ, если нет. - person jtbandes; 26.02.2017
comment
Похоже, это был способ Apple - person Ky Leggiero; 01.08.2018
comment
Это показывает значок приложения в документе и немедленно удаляет его из док-станции. Я не хочу вносить какие-либо изменения в док. Никаких намеков. - person meMadhav; 30.07.2019
comment
Удивительно полезно - person boraseoksoon; 21.10.2020

Чтобы сделать это при соблюдении руководящих принципов Apple о том, чтобы не изменять пакеты приложений и гарантировать, что приложения Mac App Store / (приложения Lion?) Не будут иметь свою подпись, нарушенную модификацией info.plist, вы можете установить LSUIElement на 1 по умолчанию, тогда, когда запуски приложений делают:

ProcessSerialNumber psn = { 0, kCurrentProcess };
TransformProcessType(&psn, kProcessTransformToForegroundApplication);

, чтобы отобразить значок док-станции, или обойти это, если пользователь решил, что значок не нужен.

Есть только один побочный эффект: меню приложения не отображается, пока оно не потеряет и не вернет фокус.

Источник: Установка флажка для включения и выключения значка док-станции

Лично я предпочитаю не устанавливать никаких опций Info.plist и использовать TransformProcessType(&psn, kProcessTransformToForegroundApplication) или TransformProcessType(&psn, kProcessTransformToUIElementApplication) в зависимости от настроек пользователя.

person valexa    schedule 14.01.2011
comment
Спасибо! Именно то, что я искал! - person MrMage; 29.07.2011
comment
Отличный совет! Спасибо! Вы всегда захотите скрыть значок Dock таким образом, чтобы убедиться, что ваше подписанное приложение работает. - person Form; 17.11.2011
comment
Решения, основанные на этом кодовом пути, не позволяют приложению, которое на самом деле хочет быть LSUIElement YES (например, не имеет строки меню и т. Д.). Переключение процесса таким образом приведет к отображению меню, как указано в ответе. Я, конечно, уважаю, что это наиболее близкий ответ на упущенную из виду функциональность, но это не точное решение. Я говорю пользователям просто вручную добавить приложение в Dock, если они хотят, чтобы там был значок. - person SG1; 11.10.2012

В Xcode это показано как «Приложение является агентом» (UIElement) и является логическим.

В вашем Info.plist щелкните мышью на пустом месте и выберите «Добавить строку» в меню «Тип приложения - агент (UIElement)». Установите значение «ДА».

Чтобы сделать его необязательным, я добавил в свой код следующую строку (спасибо, Valexa!)

 // hide/display dock icon
if (![[NSUserDefaults  standardUserDefaults] boolForKey:@"hideDockIcon"]) {
    //hide icon on Dock
    ProcessSerialNumber psn = { 0, kCurrentProcess };
    TransformProcessType(&psn, kProcessTransformToForegroundApplication);
} 
person Tibidabo    schedule 24.05.2011

Обновление для Swift: (Используйте оба способа, представленные выше, они дают тот же результат)

public class func toggleDockIcon_Way1(showIcon state: Bool) -> Bool {
    // Get transform state.
    var transformState: ProcessApplicationTransformState
    if state {
        transformState = ProcessApplicationTransformState(kProcessTransformToForegroundApplication)
    }
    else {
        transformState = ProcessApplicationTransformState(kProcessTransformToUIElementApplication)
    }

    // Show / hide dock icon.
    var psn = ProcessSerialNumber(highLongOfPSN: 0, lowLongOfPSN: UInt32(kCurrentProcess))
    let transformStatus: OSStatus = TransformProcessType(&psn, transformState)
    return transformStatus == 0
}

public class func toggleDockIcon_Way2(showIcon state: Bool) -> Bool {
    var result: Bool
    if state {
        result = NSApp.setActivationPolicy(NSApplicationActivationPolicy.Regular)
    }
    else {
        result = NSApp.setActivationPolicy(NSApplicationActivationPolicy.Accessory)
    }
    return result
}
person Huy Nguyen    schedule 09.10.2014
comment
Это показывает значок приложения в документе и немедленно удаляет его из док-станции. Я не хочу вносить какие-либо изменения в док. Никаких намеков. - person meMadhav; 30.07.2019

Если вы хотите сделать это предпочтением пользователя, вы не можете использовать UIElement. UIElement находится в пакете приложения, вам не следует редактировать какие-либо файлы в пакете приложения, так как это сделает подпись пакета недействительной.

Лучшее решение, которое я нашел, основано на эту отличную статью. Мое решение основано на комментарии Дэна. Короче говоря, это невозможно сделать с помощью Какао, но это возможно с помощью крошечного фрагмента кода углерода.

В статье также предлагается создать вспомогательное приложение, которое обрабатывает только значок док-станции. Затем запускается основное приложение и завершает работу этого приложения в зависимости от предпочтений пользователя. Этот подход кажется мне более надежным, чем использование кода Carbon, но я еще не пробовал его.

person Benedict Cohen    schedule 10.03.2009

После того, как я попробовал разные варианты, у меня все еще были проблемы, показанные ниже:

  1. Меню приложения неактивно после того, как значок приложения в Dock был включен (после настройки NSApplication.ActivationPolicy.regular). Вам нужно сначала переключиться на другое приложение (например, Finder.app), а затем снова переключиться на свое приложение, чтобы меню приложения работало должным образом.
  2. Окна приложений переместились назад / скрылись после того, как значок приложения в Dock был отключен (после настройки NSApplication.ActivationPolicy.accessory). Вам нужно запустить Mission Control, чтобы открыть окна приложений.

Чтобы решить вышеуказанные проблемы, я сделал расширение:

import AppKit

extension NSApplication {
   public enum Dock {
   }
}

extension NSApplication.Dock {

   public enum MenuBarVisibiityRefreshMenthod: Int {
      case viaMenuVisibilityToggle, viaSystemAppActivation
   }

   public static func refreshMenuBarVisibiity(method: MenuBarVisibiityRefreshMenthod) {
      switch method {
      case .viaMenuVisibilityToggle:
         DispatchQueue.main.async { // Async call not reaaly needed. But intuition tells to leave it.
            // See: cocoa - Hiding the dock icon without hiding the menu bar - Stack Overflow: https://stackoverflow.com/questions/23313571/hiding-the-dock-icon-without-hiding-the-menu-bar
            NSMenu.setMenuBarVisible(false)
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { // Without delay windows were not always been brought to front.
               NSMenu.setMenuBarVisible(true)
               NSRunningApplication.current.activate(options: [.activateAllWindows, .activateIgnoringOtherApps])
            }
         }
      case .viaSystemAppActivation:
         DispatchQueue.main.async { // Async call not reaaly needed. But intuition tells to leave it.
            if let dockApp = NSRunningApplication.runningApplications(withBundleIdentifier: "com.apple.dock").first {
               dockApp.activate(options: [])
            } else if let finderApp = NSRunningApplication.runningApplications(withBundleIdentifier: "com.apple.finder").first {
               finderApp.activate(options: [])
            } else {
               assertionFailure("Neither Dock.app not Finder.app is found in system.")
            }
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { // Without delay windows were not always been brought to front.
               NSRunningApplication.current.activate(options: [.activateAllWindows, .activateIgnoringOtherApps])
            }
         }
      }
   }

   public enum AppIconDockVisibilityUpdateMethod: Int {
      case carbon, appKit
   }

   @discardableResult
   public static func setAppIconVisibleInDock(_ shouldShow: Bool, method: AppIconDockVisibilityUpdateMethod = .appKit) -> Bool {
      switch method {
      case .appKit:
         return toggleDockIconViaAppKit(shouldShow: shouldShow)
      case .carbon:
         return toggleDockIconViaCarbon(shouldShow: shouldShow)
      }
   }

   private static func toggleDockIconViaCarbon(shouldShow state: Bool) -> Bool {
      // Get transform state.
      let transformState: ProcessApplicationTransformState
      if state {
         transformState = ProcessApplicationTransformState(kProcessTransformToForegroundApplication)
      } else {
         transformState = ProcessApplicationTransformState(kProcessTransformToUIElementApplication)
      }

      // Show / hide dock icon.
      var psn = ProcessSerialNumber(highLongOfPSN: 0, lowLongOfPSN: UInt32(kCurrentProcess))
      let transformStatus: OSStatus = TransformProcessType(&psn, transformState)
      return transformStatus == 0
   }

   private static func toggleDockIconViaAppKit(shouldShow state: Bool) -> Bool {
      let newPolicy: NSApplication.ActivationPolicy = state ? .regular : .accessory
      let result = NSApplication.shared.setActivationPolicy(newPolicy)
      return result
   }
}

Использование:

Предварительное условие: Info.plist параметр LSUIElement отсутствует или установлен на значение NO.

   private func hideDock() {
      log.debug("Will hide app from dock.")
      let status = Self.Dock.setAppIconVisibleInDock(false)
      log.debug("Status is: \(status)")
      Self.Dock.refreshMenuBarVisibiity(method: .viaMenuVisibilityToggle)
   }

   private func showDock() {
      log.debug("Will show app in dock.")
      let status = Self.Dock.setAppIconVisibleInDock(true)
      log.debug("Status is: \(status)")
      // The method `viaMenuVisibilityToggle` not working. Menu itens non-clickable
      Self.Dock.refreshMenuBarVisibiity(method: .viaSystemAppActivation)
   }
person Vlad    schedule 20.06.2021