Browse Source

Added manual for events (Russian and English).

Signed-off-by: Slava Zanko <slavazanko@gmail.com>
Slava Zanko 14 years ago
parent
commit
7df04e95e2
2 changed files with 282 additions and 0 deletions
  1. 129 0
      lib/event/event-ru.txt
  2. 153 0
      lib/event/event.txt

+ 129 - 0
lib/event/event-ru.txt

@@ -0,0 +1,129 @@
+= СОБЫТИЯ =
+
+В mc используется система событий, основанная на технологии быстрых бинарных деревьев.
+
+== Вступление ==
+
+Система событий, в первую очередь, призвана отвязать на уровне исходных текстов источник события и обработчик.
+Например, в модуле VFS используется функция вывода сообщений, которая определена в исходных текстах (не в lib).
+В lib определение этой функции будет затруднительным (потому что функция делает множество вызовов на другие
+функции из src). В данном случае можно представить эту функцию как обработчик события, а сам процесс вывода
+сообщения от VFS на экран как непосредственно событие. В начале запуска mc функцию вывода сообщений необходимо
+зарегистрировать как обработчик события; в последствии при необходимости выдачи сообщений нужно просто вызвать
+событие, абсолютно не волнуясь, привязан ли обработчик к событию, а также какая именно функция сейчас является
+обработчиком события (вероятна ситуация, при которой позже загрузился плагин и переопределил этот обработчик
+событий на себя).
+
+=== Использование ===
+
+Не везде и не всегда применимы события. Самое трудное порой бывает решить, это должна быть простая функция или это
+должно быть событие. Наиболее правильным будет заменить все функции (или части switch(){case:}), используемые при
+обработке кейбиндингов. Все кейбиндинги описаны в lib/keybind.h
+
+Вторым аргументом при выборе решения (обработчик события или функция) должна стать мысль, что функцию в обработчик
+события "превратить" легко; обратный процесс (обработчик в функцию) будет значительно сложнее - хотя бы потому,
+что на одном событии может "висеть" множество обработчиков, и каждый может зависеть от работы предыдущего.
+
+Третьим аргументом при выборе в пользу обработчиков событий могут стать плагины (когда появятся). В данном случае
+события - это способ дать плагинам доступ к внутренним ресурсам приложения, не "пуская" эти плагины в низкоуровневое
+API. Всё, что нужно будет знать "плагинам" - какое событие с какой структурой надо вызвать и как именно вызвать
+(#include "lib/event.h").
+
+== Структура ==
+
+В общем виде подсистему событий можно представить так:
+
+
+   ------------------------------------            }
+   |Группа1       Группа2  ...  ГруппаN|            }   Группы событий (GTree)
+   -------------------------------------           }
+       |             |             |
+      /|\           /|\           /|\
+     / | \         / | ...       ... событиеN      }
+    /  |  \       /  ...                            }
+   /   |   \      ...                                } События, разбитые на группы
+   |   |    событие3                                 } (GTree для каждой группы)
+   |   событие2                                     }
+   событие1                                        }
+   | | |  |
+   f1f2...fN                                       } список обработчиков события (GPtrArray на каждое событие)
+
+
+Такая схема позволяет группировать события и выполнять более одного обработчика на одно событие.
+
+== Требования к обработчикам событий ==
+
+Любой каллбэк должен быть вида:
+
+gboolean mc_event_callback_func_t (const gchar *event_group, const gchar *event_name, gpointer init_data, gpointer event_data);
+где:
+ event_group:
+    название группы, в которой было инициировано событие
+
+ event_name:
+    название события. Вместе с названием группы событий позволяют точно идентифицировать событие.
+    Эти параметры могут быть полезны в случае если обработчик события привязан сразу к нескольким событиям
+    и необходимо различать различные события (например, в функции логгирования)
+
+ init_data:
+    Произвольные данные, предоставляемые обработчикам события. Эти данные указываются при добавлении обработчика
+    к событию (инициализационные данные).
+ event_data:
+    Данные, предоставляемые обработчику событий в момент возникновения события.
+
+Каллбэк должен вернуть TRUE, чтобы разрешить исполниться всем последующим за ним каллбэкам в данном событии; либо
+FALSE если необходимо немедленно прекратить дальнейшую обработку события (оставшиеся каллбэки не вызываются).
+
+Если для одного и того же события будет привязано множество каллбэков, то порядок из исполнения будет следующим:
+"Последним добавился - первым выполнился". Это позволяет в последствии переопределять стандартные обработчики событий
+(например, в плагинах).
+
+=== Передача параметров в обработчики событий. Возврат результатов ===
+
+Из-за унификации обработчиков событий стало невозможным передать определённое количество параметров и
+получить результат выполнения. Если передачу одного параметра (или приём одного результата от обработчика события)
+можно произвести простым приведением типа на одну переменную при вызове событий, то при передаче нескольких параметров
+(или при получении нескольких результатов) такой метод неприменим.
+
+Для решения этой проблемы можно передавать ранее определённые структуры по универсальному указателю event_data.
+Все структуры, используемые в обработчиках событий, должны быть определены в файле lib/event-types.h.
+
+У данного метода (передача параметров указателем на структуру) есть как достоинства, так и недостатки.
+
+Достоинства:
+ * произвольное количество параметров и их типов;
+ * произвольное количество возвращаемых значений и их типов.
+
+Недостатки:
+ * вероятность ошибки: вызов события с неправильной структурой. В данном случае обработчик приведёт указатель к той
+   структуре, на которую он рассчитан. При этом возможны весёлые глюки с отладкой (особенно если нет сразу segfault);
+ * необходимость иметь ранее определённые структуры для того, чтобы и обработчик события, и инициатор события могли бы
+   без проблем "общаться" между собой.
+
+== Примеры использования ==
+
+=== Логгирование ===
+
+Рассмотрим пример временного каллбэка, который просто логгирует порядок вызова определённых событий (например,
+для выявления зацикливаний).
+
+Сам каллбэк:
+
+gboolean mc_temp_event_logger (const gchar *event_group, const gchar *event_name, gpointer init_data, gpointer data)
+{
+    (void) init_data;
+    (void) data;
+
+    mc_log("Event: %s:%s",event_group,event_name);
+    return TRUE;
+}
+
+Добавляем его в src/event_init.c в виде записей к инициализационной структуре
+перед строчкой "{NULL, NULL, NULL, NULL}":
+
+{MCEVENT_GROUP_CORE, "clipboard_file_to_ext_clip", mc_temp_event_logger, NULL},
+{MCEVENT_GROUP_CORE, "clipboard_file_from_ext_clip", mc_temp_event_logger, NULL},
+{MCEVENT_GROUP_CORE, "clipboard_text_to_file", mc_temp_event_logger, NULL},
+{MCEVENT_GROUP_CORE, "clipboard_text_from_file", mc_temp_event_logger, NULL},
+...(тут любые другие события, которые необходимо мониторить)...
+

+ 153 - 0
lib/event/event.txt

@@ -0,0 +1,153 @@
+= EVENTS =
+
+The subsystem of events used in mc is based on fast binary trees engine.
+
+
+== Introduction ==
+
+Subsystem of events is primarily designed to detach event source and event
+handler in source code level. For example, VFS module uses function to show
+messages, which is defined in the source code (not in the lib). In the lib,
+definition of this function will be difficult (because the function does
+a lot of calls of other functions from src). In this case, the transform
+of this function to event handler is needed, and the display messages process
+can be used as an event. Function as event handler should be registered
+at early stage of mc start. Later just call the event, absolutely without
+worrying whether the handler is tied to the event, and which function
+is an event handler now (in some situation, plugin will load and reassign
+this event handler to itself).
+
+
+=== Usage ===
+
+Events are applicable in any case. Sometimes it is hard to decide whether
+it should be a common function or it should be an event handler. The replacement
+of all functions used in keybindings process to event handler is good choice
+(or parts of the 'switch () {case:}' in keybindings handlers). All keybindings
+are described in lib/keybind.h.
+
+The second argument to choose the solution (event handler or function) should be
+thought whether that transformation of function to the event handler is easy,
+the inverse process (handler to function) would be more difficult because
+one event can have multiple handlers and each handler may depend to another.
+
+A third argument in the choice in favor of the event handlers can be a plug-ins
+(in future). In this case events is a way to give access to internal application
+resources without providing a low-level API. All plug-ins need is to know what and how
+call the event with proper structure type (#include "lib/event.h").
+
+
+== Structure ==
+
+In general, the subsystem of events can be represented as following:
+
+   ------------------------------------            }
+   |Group1        Group2   ...   GroupN|            }   Event groups (GTree)
+   -------------------------------------           }
+       |             |             |
+      /|\           /|\           /|\
+     / | \         / | ...       ... eventN        }
+    /  |  \       /  ...                            }
+   /   |   \      ...                                } Events by groups
+   |   |    event3                                   } (GTree for any group)
+   |   event2                                       }
+   event1                                          }
+   | | |  |
+   f1f2...fN                                       } list of event handlers (GPtrArray for any event)
+
+
+This scheme allows to group events, and perform several handlers for one event.
+
+
+== Requirements for event handlers ==
+
+The following function prototype is event handler:
+
+gboolean mc_event_callback_func_t (
+    const gchar *event_group,
+    const gchar *event_name,
+    gpointer init_data,
+    gpointer event_data
+);
+
+where:
+ event_group:
+    name of the group, where event was initiated
+
+ event_name:
+    event name. event_name ans event_group uniquely identify an event.
+    These parameters can be useful if event handler is tied to several events
+    and the distinguish between different events (for example, function of logging)
+    is required.
+
+ init_data:
+    Arbitrary data, provided to the event handler.
+    This data is provided by adding a handler to the event (the initialization data).
+
+ event_data:
+    Data provided to the handler when the event occurred.
+
+Handler should return TRUE to allow running all other handlers tied to this event;
+or FALSE if it is necessary to stop further processing of event (the remaining
+handlers are not called).
+
+If one event will have multiple handlers, the order of execution is "Last added - first
+executed". This allows to override the standard event handlers (eg, in plug-ins).
+
+
+=== Passing parameters to event handlers. Returning rezults ==
+
+Due to the unification of the event handlers, there is no possibility to pass
+a certain number of parameters and get the results of execution. Pass of a single
+parameter (or get one result of an event handler) can be made as simple type casting
+for one variable when event is called. But this way isn't applicable if pass
+of several parameters (or get multiple return values) is required.
+
+To solve this problem, you can pass the previously defined structure as universal
+pointer event_data. All structures used in the event handlers should be defined
+in the lib/event-types.h.
+
+This way (the pass parameters as pointer to structure) has advantages and disadvantages.
+
+Advantages:
+ * any number of parameters and their types;
+ * any number of return values and their types.
+
+Disadvantages:
+ * probability of error: call the event with the wrong structure. In this case,
+   the handler will cast pointer to the structure on which it was designed.
+   At this point funny bugs and very long debugging process (especially if segfault
+   doesn't occur immediately) are possible;
+ * in order for an event handler and the initiator of the event to "communicate"
+   with each other, previously defined structures is needed.
+
+
+== Examples ==
+
+=== Logging ===
+
+Consider the example of a temporary handler which simply logged the order
+of certain events (for example, to detect infinite loop).
+
+Here event handler:
+
+gboolean
+mc_temp_event_logger (const gchar *event_group, const gchar *event_name,
+                      gpointer init_data, gpointer data)
+{
+    (void) init_data;
+    (void) data;
+
+    mc_log("Event: %s:%s",event_group,event_name);
+    return TRUE;
+}
+
+Add the following lines into src/event_init.c before "{NULL, NULL, NULL, NULL}" line
+as one record to the initialization structure.
+
+{MCEVENT_GROUP_CORE, "clipboard_file_to_ext_clip", mc_temp_event_logger, NULL},
+{MCEVENT_GROUP_CORE, "clipboard_file_from_ext_clip", mc_temp_event_logger, NULL},
+{MCEVENT_GROUP_CORE, "clipboard_text_to_file", mc_temp_event_logger, NULL},
+{MCEVENT_GROUP_CORE, "clipboard_text_from_file", mc_temp_event_logger, NULL},
+
+...(there any other events which you want to monitor)...