Сигналы
Last updated
Was this helpful?
Last updated
Was this helpful?
Сигналы GObject не имеют никакого отношения к стандартным сигналам UNIX: они подключают произвольные события определённые приложением с любым количеством слушающих. Например, в GTK+, каждое пользовательское событие (нажатие клавиши или перемещение курсора) происходит из X сервера и генерирует GTK+ событие через форму эмиссии сигнала в данном экземпляре объекта.
Каждый сигнал регистрируется в системе типов вместе с типом который может его издать: пользователи типа, как говорится подключают в данный экземпляр типа когда он регистрирует замыкание вызываемое при эмиссии сигнала. Пользователи могут так же издать сигнал или остановить эмиссию сигнала изнутри одного из замыканий к которому подключен сигнал.
Когда сигнал издаётся на данном экземпляре типа, вызываются все замыкания подключенные в данном типовом экземпляре. Все замыкания связанные с такими сигналами представляют callback-функцию следующей сигнатуры:return_type function_callback (gpointer instance, ... , gpointer user_data);
Для регистрации сигнала в существующем типе, мы можем использовать одну из функций , или :
Количество параметров у этих функций является немного запутывающим, но они достаточно просты:
signal_name: строка которая может использоваться для уникальной идентификации данного сигнала.
itype: экземпляр типа который может издавать данный сигнал.
signal_flags: частично определённый порядок в котором вызываются замыкания связанные с сигналом.
class_closure: замыкание по умолчанию для сигнала: если эмиссия сигнала не NULL, она будет вызвана в этой эмиссии сигнала. Момент вызова этого замыкания по сравнению с вызовом других замыканий связанных с этим игналом, частично зависит от signal_flags.
accumulator: указатель функции которая вызывается после каждого вызванного замыкания. Если она возвращает FALSE, эмиссия сигнала останавливается. Если возвращает TRUE, эмиссия сигнала выполняется нормально. Это также используется для вычисления возвращаемого значения сигнала, основываясь на возвращённом значении всех вызванных замыканий.
accumulator_data: этот указатель будет передан в каждый запрос accumulator в течение эмиссии.
c_marshaller: C маршаллер по умолчанию для любого замыкания которое подключено к этому сигналу.
return_type: тип значения возвращаемого сигналом.
n_params: количество принимаемых сигналом параметров.
param_types: массив GTypes который указывает тип каждого параметра сигнала. Длина массива указывается с помощью n_params.
Как вы видите в выше приведённых определениях, сигнал - это в основном описание замыканий которые могут быть подключены к этому сигналу и описание порядка в котором вызываются замыкания подключенные к данному сигналу.
Если вы хотите подключить к сигналу замыкание, у вас есть три возможности:
Вы можете зарегистрировать классовое замыкание при регистрации сигнала: это системная операция. То есть: class_closure будет вызван в течение каждой эмиссии данного сигнала на всех экземплярах типа которые поддерживают этот сигнал.
Массив instance_and_params GValues содержит список вводимых в сигнал параметров. Первый элемент массива это указатель экземпляра для вызова сигнала. Следующие элементы массива содержат список параметров для сигнала.
signal_id идентифицирует вызываемый сигнал.
Внутренне, массив GValue помещается в надлежащую функцию эмиссии, signal_emit_unlocked_R
(реализована в gsignal.c
). Эмиссия сигнала может быть разделена на 5 шагов:
RUN_FIRST: если был использован флаг G_SIGNAL_RUN_FIRST при регистрации сигнала вызывается class_closure для этого сигнала если есть. Переходим в состояние EMISSION_HOOK.
EMISSION_HOOK: если обработчики прерывания эмиссии были добавлены в сигнал, они вызываются от первого добавленного до последнего. Аккумулируем возвращаемые значения и переходим в состояние HANDLER_RUN_FIRST.
RUN_LAST: если флаг G_SIGNAL_RUN_LAST был установлен в течение регистрации и если было установлено замыкание class_closure, оно вызывается. Переходим в состояние HANDLER_RUN_LAST.
HANDLER_RUN_LAST: если есть замыкания подключенные с помощью семейства функций g_signal_connect_after
, если они не вызваны в течение HANDLER_RUN_FIRST и не заблокированы, они выполняются здесь, от первого до последнего подключения. Переходим в состояние RUN_CLEANUP.
RUN_CLEANUP: если флаг G_SIGNAL_RUN_CLEANUP был установлен в процессе регистрации и если было установлено class_closure, оно вызывается. Здесь эмиссия сигнала завершается.
Если в какой нибудь точке выполнения эмиссии (исключая состояние RUN_CLEANUP), одно из замыканий или обработчиков прерывания эмиссии остановят эмиссию сигнала с помощью g_signal_stop
, эмиссия переходит в состояние CLEANUP.
Если, в какой нибудь точке выполнения эмиссии, одно из замыканий или обработчиков прерывания издаст тот же сигнал в том же экземпляре, эмиссия перегрузится в состояние RUN_FIRST.
Функция суммирования вызывается во всех состояниях, после вызова каждого замыкания (исключая EMISSION_HOOK и CLEANUP). Это суммирует возвращаемые значения замыканий в возвращаемое значение сигнала и возвращает TRUE или FALSE. Если, в каком нибудь пункте, не возвращено TRUE, эмиссия переходит в состояние CLEANUP.
Все функции связанные с эмиссией сигнала или подключением сигнала имеют параметр с названием детальный. Иногда этот параметр скрыт с помощью API, но он всегда присутствует в той или иной форме.
Две другие функции скрывают детальный параметр в идентифицирующем имени сигнала:
Здесь параметр detailed_signal - это строка которая идентифицирует имя подключаемого сигнала. Однако, формат этой строки структурирован как signal_name::detail_name. Подключение к сигналу с именем notify::cursor_position будет фактически подключением к сигналу notify с именем cursor_position. Внутренне, строка преобразуется в GQuark если она представлена.
Четвёртая функция скрывает его в параметре имени сигнала:
Если детальный параметр обеспечивается пользователем в функции эмиссии, он используется в течение эмиссии вместо соответствующего детального параметра обеспеченного замыканиями. Если детальный параметр замыкания не соответствует детальному параметру предоставленного пользователем, то они будут вызваны (даже если они подключены к издаваемому сигналу).
Это полностью опциональный механизм фильтрации главным образом используется как оптимизация сигналов которые часто издаются по разным причинам: клиенты могут фильтровать вывод который интересует их перед выполнением кода маршаллера замыкания. Например, это используется экстенсивно сигналом notify GObject: каждый раз когда изменяется свойство в GObject, вместо простого издания сигнала notify, GObject привязывается как детальный параметр для этой эмиссии сигнала с именем изменённого свойства. Это позволяет клиентам, которые желают получать уведомления об изменениях только к одному свойству, фильтровать большинство сообщений перед их получением.
Как простое правило, пользователи могут и должны установить детальный параметр в ноль: это полностью отключит дополнительную фильтрацию.
Вы можете использовать которая отменит class_closure полученного типа. Эту функцию возможно вызвать только в унаследованном типе, типе в котором сигнал был зарегистрирован. Эта функция используется только языковыми привязками.
Вы можете зарегистрировать замыкание с помощью семейства функций . Это экземпляро-специфичная операция: замыкание будет вызвано только в течение эмиссии данного сигнала в данном экземпляре.
Также возможно подключить различные виды callback-функций к данному сигналу: обработчики прерываний эмиссии вызываются всякий раз когда издаётся данный сигнал для экземпляра на котором он издаётся. Обработчики прерываний эмиссии используются например чтобы заставить все эмиссии mouse_clicked в приложении издавать звук небольшого нажатия кнопки мыши. Обработчики прерываний эмиссии подключаются с помощью и удаляются с помощью .
Эмиссия сигнала выполняется через использование семейства функций .
подробную идентификацию определяют детали вызываемого сигнала. Деталь - это своего рода магическая пара символ/параметр которая помещается в течение эмиссии сигнала и которая используется замыканием подключённым к сигналу для фильтрации нежелательных эмиссий сигнала. В большинстве случаев, вы можете безопасно установить это значение в ноль. Смотрите для подробностей об этом параметре.
return_value содержит возвращаемое значение последнего вызванного замыкания в течение эмиссии если не был определён accumulator. Если accumulator был определён в процессе создания сигнала, этот сумматор используется для вычисления return_value как функция возвращаемых значений всех замыканий вызываемых в течение эмиссии. [] Если нет замыканий вызываемых в течение эмиссии, return_value тем не менее инициализируется в null.
HANDLER_RUN_FIRST: если есть замыкания подключенные с помощью семейства функций , и если они не заблокированы (с помощью семейства функций ) они выполняются, от первого до последнего подключения. Переходим в состояние RUN_LAST.
Если нет суммирующей функции, возвращаемое значение последнего обработчика будет возвращено функцией .
Из трёх основных функций подключения, только одна имеет явный детальный параметр в виде []:
Из четырёх основных функций эмиссии сигнала, три имеют явный детальный параметр как :
Формат параметра detailed_signal такой же как формат используемый функциями : signal_name::detail_name.
[] James (снова!!) привёл несколько нетривиальных примеров сумматоров: “ Например, вы можете иметь сумматор который игнорирует возвращаемый NULL из замыкания, а только суммирует не-NULL значения. Другой сумматор может попытаться вернуть список возвращенных замыканиями значений. ”
[] GQuark это целочисленное которое представлено уникальной строкой. Оно может преобразовываться между строкой и целочисленным с помощью функций и .