> Это вам виндовс надо.
Туда я уже заглядывал и эту проблему давно успешно решал там старыми средствами. Но вот туда уже точно не надо. Не та система.
Вопрос был именно о Линукс и FreeePascal, а не Win + Delphi.
Именно здесь нужно решить эту задачу. И она здесь и современнее и мощнее, но и сложнее. Тем более, что разработчики FPC в упор не видят самой проблемы, а она есть.
Решается обработкой PrepareForShutdown. С применением
Замки-ингибиторы
systemd 183 и новее включают логику, запрещающую завершение работы системы и переходы в спящий режим. Это реализовано как часть systemd-logind.daemon(8). Для этого существует несколько различных вариантов использования:
Приложение для записи компакт-дисков хочет гарантировать, что система не будет выключена или приостановлена во время процесса записи.
Менеджер пакетов хочет гарантировать, что система не будет выключена во время обновления пакета.
Офисный пакет хочет получать уведомления перед приостановкой системы, чтобы сохранить все данные на диск, и задерживать логику приостановки до тех пор, пока все данные не будут записаны.
Веб-браузер хочет получить уведомление перед переходом системы в спящий режим, чтобы освободить его кэш и минимизировать объем памяти, которую необходимо виртуализировать.
Инструмент блокировки экрана хочет активировать блокировку экрана непосредственно перед приостановкой и отложить приостановку до ее завершения.
Приложения, которые хотят использовать логику блокировки, должны использовать блокировку блокировки через API входа в систему D-Bus.
Можно использовать семь различных типов блокировок-ингибиторов или их комбинацию:
сон запрещает приостановку работы системы и переход в спящий режим, запрошенные (непривилегированными) пользователями
завершение работы запрещает высокоуровневое выключение системы и перезагрузку по запросу (непривилегированных) пользователей.
«idle» запрещает переход системы в режим ожидания, что может привести к автоматической приостановке или выключению системы в зависимости от конфигурации.
handle-power-key запрещает низкоуровневую (т. е. логин-внутреннюю) обработку аппаратного ключа питания системы, позволяя вместо этого (возможно, непривилегированному) внешнему коду обрабатывать событие.
Аналогичным образом, handle-suspend-key запрещает низкоуровневую обработку аппаратной клавиши приостановки системы.
Аналогичным образом, handle-hibernate-key запрещает низкоуровневую обработку аппаратного ключа гибернации системы.
Аналогичным образом, handle-lid-switch запрещает низкоуровневую обработку аппаратного переключателя крышки systemd.
Поддерживаются два различных режима блокировок:
блокировка полностью запрещает операции до тех пор, пока блокировка не будет снята. Если такая блокировка будет принята, операция завершится неудачно (но ее все же можно переопределить, если пользователь обладает необходимыми привилегиями).
Задержка запрещает операции только временно, либо до тех пор, пока блокировка не будет снята, либо до определенного периода времени. Параметр InhibitDelayMaxSec= в файле logind.conf(5) управляет таймаутом для этого. Это предназначено для использования приложениями, которым требуется синхронный способ выполнения действий перед приостановкой системы, но им не разрешено блокировать приостановку на неопределенный срок. Этот режим доступен только для блокировки сна и выключения.
Блокировки ингибитора выполняются с помощью вызова D-Bus Inhibit() объекта logind Manager:
Inhibit() — единственный API, необходимый для блокировки. Требуется четыре аргумента:
Что такое список типов блокировки, разделенных двоеточиями, т. е. выключение, спящий режим, режим ожидания, ручка-ключ-питание, ручка-ключ-приостановка, ручка-ключ-спящий режим, ручка-крышка-переключатель. Пример: «выключение: холостой ход»
Кто — удобочитаемая строка описания того, кто берет блокировку. Пример: «Программа обновления пакетов».
«Почему» — удобочитаемая строка с описанием причины блокировки. Пример: «Выполняется обновление пакета».
Режим — блокировка или задержка, см. выше. Пример: «блокировать».
Inhibit() возвращает одно значение — файловый дескриптор, инкапсулирующий блокировку. Как только файловый дескриптор закрывается (и все его дубликаты), блокировка автоматически снимается. Если клиент умирает во время блокировки, ядро автоматически закрывает дескриптор файла, и блокировка автоматически снимается. Принятая таким образом блокировка задержки должна быть снята как можно скорее при получении AcceptForShutdown(true) (см. ниже), но, конечно, только после выполнения действий, для которых приложение изначально хотело отложить операцию.
ListInhibitors() выводит список всех активных в данный момент блокировок-ингибиторов. Он возвращает массив структур, каждая из которых состоит из What, Who,Why, Mode, как указано выше, а также PID и UID процесса, запросившего блокировку.
Сигналы ПодготовкаForShutdown() и ПодготовкаForSleep() подаются, когда приостановка или завершение работы системы запрошена и вот-вот будет выполнена, а также после того, как приостановка/выключение была завершена (или не удалась). Сигналы содержат логический аргумент. Если True, было запрошено завершение работы/переход в спящий режим, и начинается фаза подготовки к нему, если False, операция завершилась (или завершилась неудачей). Если принимает значение True, это следует использовать как указание приложениям быстро выполнить операции, которые они хотели выполнить, перед приостановкой/завершением работы, а затем снять любую блокировку задержки. Если значение равно False, операция приостановки/выключения завершена успешно или неудачно (конечно, этот сигнал никогда не будет отправлен, если запрос на выключение был успешным). Сигнал с значением False обычно доставляется только после того, как система возвращается из режима ожидания, а также сигнал с значением True, например, когда изначально не была установлена блокировка задержки, и поэтому приостановка системы выполняется без какой-либо задержки. Сигнал с значением False обычно является сигналом, по которому приложения запрашивают новую блокировку задержки, чтобы быть синхронно уведомленными о следующем цикле приостановки/выключения. Обратите внимание, что просмотр «PrepareForShutdown(true)?/PrepareForSleep(true)» без блокировки задержки является грубым и не должен выполняться, поскольку любой код, который приложение может захотеть выполнить по этому сигналу, может фактически не завершиться до завершения цикла приостановки/выключения. казнен. Опять же: если вы смотрите «ПодготовкаForSuspend(true)», то вам действительно следовало сначала использовать блокировку задержки. На AcceptForShutdown(false) могут подписываться приложения, которые хотят получать уведомления о событиях возобновления работы системы. Обратите внимание, что это будет отправлено только для циклов приостановки/возобновления, выполняемых через вход в систему, т. е., как правило, только для циклов приостановки высокого уровня, вызванных пользователем, а не автоматических циклов приостановки низкого уровня, индуцируемых ядром, которые могут существовать на определенных устройствах с более агрессивной мощностью. управление.
Свойства BlockInhibited и DelayInhibited определяют, какие типы блокировок используются в данный момент. Эти поля представляют собой список, разделенный двоеточиями: выключение, спящий режим, режим ожидания, ручка-клавиша включения, ручка-клавиша приостановки, ручка-клавиша гибернации, ручка-крышка-переключатель. По сути, список представляет собой объединение полей «Что» всех активных в данный момент блокировок определенного режима.
InhibitDelayMaxUSec содержит значение тайм-аута задержки, настроенное в файле logind.conf(5).
Логические свойства PreparingForShutdown и PreparingForSleep являются истинными между двумя отправляемыми сигналами AcademicForShutdown() и PreparingForSleep(). Обратите внимание, что эти свойства не вызывают сигналы PropertyChanged.
Взятие блокирующих замков
Вот базовая схема для приложений, которым требуется блокировка блокировок, таких как менеджер пакетов или приложение для записи компакт-дисков:
Возьмите замок
Выполняйте свою работу, которую не хотите прерывать спящим режимом или выключением системы.
Отпустите замок
Пример псевдокода:
Взятие блокировки задержки
Вот базовая схема для приложений, которым требуется блокировка с задержкой, таких как веб-браузер или офисный пакет:
Открывая документ, используйте блокировку задержки.
Как только вы увидите AcceptForSleep(true), сохраните данные, а затем снимите блокировку.
Как только вы увидите «ПодготовкаForSleep(false»), снова включите блокировку задержки и продолжайте, как прежде.
Пример псевдокода:
Взятие замков с ключами
По умолчанию logind управляет клавишами питания и сна машины, а также переключателем крышки во всех состояниях. Это гарантирует, что это базовое поведение системы гарантированно будет работать при любых обстоятельствах, как на текстовых консолях, так и во всех графических средах. Однако некоторые DE могут захотеть самостоятельно обрабатывать эти клавиши, например, чтобы показать красивое диалоговое окно перед выполнением соответствующей операции или просто отключить действие при определенных условиях. Для этих случаев доступны блокировки типа «ручка-ключ-питание», «ручка-ключ-приостановка», «ручка-клавиша гибернации» и «ручка-крышка-выключатель». При использовании эти блокировки просто отключают низкоуровневую обработку ключей, они не влияют на приостановку/гибернацию/выключение системы, выполняемую с помощью других механизмов, кроме аппаратных клавиш (например, когда пользователь вводит «systemctl suspend» в оболочке). DE, намеревающийся самостоятельно обрабатывать эти ключи, должен просто снимать блокировки во время входа в систему и снимать их при выходе из системы; в качестве альтернативы может иметь смысл использовать эту блокировку только временно при определенных обстоятельствах (например, использовать блокировку переключателя крышки только тогда, когда подключен второй монитор, чтобы поддерживать обычную настройку, при которой люди закрывают свои ноутбуки, когда у них подключен большой экран) .
Эти блокировки нужно снимать в режиме «блок», «задержка» для них не поддерживается.
Если DE хочет, чтобы экран блокировки для возможного возобновления отображался на экране до того, как система перейдет в состояние ожидания, ему следует сделать это с помощью блока ингибитора задержки приостановки (см. выше).
Разное
Взлом блокировочных замков — привилегированная операция. В зависимости от действия org.freedesktop.login1.inhibit-block-shutdown, org.freedesktop.login1.inhibit-delay-shutdown, org.freedesktop.login1.inhibit-block-sleep, org.freedesktop.login1.inhibit-delay- сон, org.freedesktop.login1.inhibit-block-idle, org.freedesktop.login1.inhibit-handle-power-key, org.freedesktop.login1.inhibit-handle-suspend-key, org.freedesktop.login1.inhibit- handle-hibernate-key,org.freedesktop.login1.inhibit-handle-lid-switch. В целом следует предположить, что блокировки с задержкой получить легче, чем блокировки блокировки, просто потому, что их влияние гораздо минимальнее. Обратите внимание, что проверки политики для Inhibit() никогда не бывают интерактивными.
Замки-ингибиторы не следует использовать неправильно. Например, блокировка бездействующей блокировки без уважительной причины может привести к тому, что мобильные устройства никогда не будут автоматически приостанавливать работу. Это может быть весьма вредно для аккумулятора.
Если приложение обнаруживает, что блокировка отклонена, ему не следует считать это большой ошибкой и просто продолжать свою работу без защитной блокировки.
Инструмент systemd-inhibit(1) можно использовать для снятия блокировок или получения списка активных блокировок из командной строки.
Обратите внимание, что gnome-session также предоставляет API-интерфейс ингибитора, который очень похож на API-интерфейс systemd. Внутренние блокировки, установленные на интерфейсе gnome-session, будут перенаправлены на вход в систему, поэтому поддерживаются оба API. Хотя оба предлагают схожие функциональные возможности, они в некоторых отношениях различаются. По очевидным причинам gnome-session может предлагать блокировки выхода из системы и блокировки блокировки заставки, которых нет в Logind. API OTOH входа в систему поддерживает блокировки с задержкой в дополнение к блокировкам блоков, таким как GNOME. Кроме того, logind доступен для компонентов системы и централизует блокировки всех пользователей, а не только конкретного. В общем: если есть сомнения, вероятно, рекомендуется придерживаться блокировок GNOME, если только нет веской причины напрямую использовать API входа в систему. Однако, когда необходимо перечислить блокировки, лучше использовать API-интерфейсы входа в систему, поскольку они также включают блокировки, выполняемые системными службами и другими пользователями.