6.2. Tworzenie pluginów

Po przeczytaniu tego rozdziału powinieneś wiedzieć jak napisać własny plugin.

Pluginy mogą być ładowane podczas startu lub już po uruchomieniu programu (czyt. podczas jego działania). Mogą też być odładowane podczas działania, co oznacza, że należy zwalniać każdą przydzieloną pamięć. I cholera macie się tego trzymać, a nie później będziemy szukali czemu program segaulci lub zżera ogromną ilość zasobów!

Jeśli plugin ma być ładowany podczas startu to musi się znajdować w katalogu $HOME/$CONFIG_DIR/gg/modules/ lub $PREFIX/lib/gg2/ i jego nazwa pliku musi być zakończona na .so.

6.2.1. Nagłówek pliku

Nagłówek ma wyglądać tak:


#include "../gg-types.h"
#include "../plugins.h"
#include "../signals.h"
#include "../support.h"

Po zadeklarowaniu wszystkich zmiennych i stałych globalnych ma się znajdować poniższa linia:


GGadu_PLUGIN_INIT("main-gui", GGADU_PLUGIN_TYPE_UI);

Za main-gui podstawiamy nazwę naszego pluginu (np. "pierd"), a za GGadu_PLUGIN_TYPE_GUI jedno z poniższych:

Typy modułów

6.2.2. Inicjalizacja modułu

Każdy moduł musi deklarować funkcję initialize_plugin() w następujący sposób:


 *initialize_plugin(gpointer conf_ptr) {
  ...

Ta funkcja jest wywoływana podczas ładowania modułu. W niej należy określić jakie sygnały przyjmuje plugin, wczytać konfigurację itp.

W tej funkcji nie wywołujemy signal_emit_full (czyt. nie wysyłamy sygnałów).

W tej funkcji dokonujemy aktywacji pluginu za pomocą poniższego polecenia:


  GGadu_PLUGIN_ACTIVATE(conf_ptr);

Tak ma być i koniec.

Następnie rejestrujemy plugin:


gui_handler=( *)register_plugin(GGadu_PLUGIN_NAME,
"GTK User Interface");

Bez powyższego plugin nie będzie istniał jako plugin, czyli będzie bezużyteczny. Należy zaznaczyć, że niezarejestrowany plugin może być dobrym sposobem zżerania zasobów komputera.

Kolejnym krokiem jest określenie, która funkcja jest odpowiedzialna za odbieranie sygnałów:


  register_signal_receiver(( *)gui_handler,
			   (signal_func_ptr)gui_signal_receive);

Powyższe informuje program, że sygnały należy przekazywać funkcji gui_signal_receive.

Rejestrowanie sygnałów jest ważne, ponieważ informuje to program, że plugin jest w stanie odebrać dany sygnał. Zarejestrujemy przykładowo sygnał gui register menu:


  register_signal(gui_handler, "gui register menu");

Na koniec funkcji initialize_plugin() zwracamy utworzony uchwyt pluginu:


  return gui_handler;
}

6.2.3. Startowanie

Kolejną funkcją, którą plugin musi posiadać jest start_plugin(). Jest ona wywoływana po inicjalizacji wszystkich modułów. Dopiero w niej można zacząć wysyłać sygnały i takie tam.


void start_plugin() {
  ...
}

6.2.4. Zwalnianie pamięci

Należy utworzyć funkcję odpowiedzialną za zwalnianie pamięci po odładowywanym pluginie. Ma tu być zwalniana cała zaalokowana podczas działania pluginu pamięć, bo jak nie to Thrulliq albo zapal będzie wam truł bez przerwy.


void destroy_plugin()
{
  ...
}

6.2.5. Odbieranie sygnału

Funkcja odbierająca wszystkie sygnały wysyłane do tego pluginu:


void gui_signal_receive(gchar *name,  *signal_ptr) {
  ...
}

name zawiera nazwę sygnału. signal_ptr jest wskaźnikiem do struktury sygnału. O tym w rozdziale o sygnałach.

6.2.6. Dostępne funkcje, makra

W pluginie można używać poniższych funkcji, makr (zawsze aktualne dane znajdują się w plikach: plugins.h, signals.h, support.h):

Makro GGadu_PLUGIN_NAME zwraca nazwę aktualnie używanego pluginu (czyt. tego pluginu).

Funkcja signal_emit_full służąca do wysyłania sygnału. Jest opisana w rozdziale o sygnałach.

6.2.7. Korzystanie z plików konfiguracyjnych

Jeśli chcesz, żeby plugin korzystał z danych zawartych w pliku konfiguracyjnym, to musisz wykonać poniższe czynności.

Najpierw w funkcji initialize_plugin() ustal nazwę pliku konfiguracyjnego:


  set_config_file_name(( *)handler, "/ściezka/do/pliku/konfiguracyjnego");

Następnie określ, jakie zmienne będę wczytane z podanego pliku:


  config_var_add(plugin_handler, "uin",      VAR_INT);
  config_var_add(plugin_handler, "password", VAR_STR);
  config_var_add(plugin_handler, "dummy",    VAR_INT);

Powyższe wczyta wartośći "uin" typu gint, "password" typu gchar * oraz "dummy" typu gint.

Zmienne w pliku konfiguracyjnym mają format "<nazwa> <wartość>"

Kolejny krok to wywołanie funkcji config_read():


  config_read(( *)plugin_handler);

Zapisanie pliku konfiguracyjnego odbywa się za pomocą funkcji config_save():


  config_save(( *)plugin_handler);

Odczytywanie wartości danej opcji z pliku konfiguracyjnego:


  foo = config_var_get(plugin_handler, "uin");

przy założeniu, że foo jest typu gpointer.

Sprawdzenie jakiego typu jest zmienna z pliku konfiguracyjnego (w poniższym przykładzie typ powinien zostać ustawiony na VAR_INT):


  typ = config_var_get_type(plugin_handler, "uin");

Za pomocą funckji config_var_set() ustawiamy wartość jednej zmiennej:


  config_var_set(plugin_handler, "uin", wartosc);

Jeśli chcemy sprawdzić, czy dana zmienna została zadeklarowana użyj poniższej funkcji:


  config_var_check(plugin_handler, "uin");

Ta funkcja, w przeciwieństwie do config_var_get() jest poprawną funkcją sprawdzającą, czy dana zmienna została zadeklarowana, bowiem zwraca tylko TRUE lub FALSE. Natomiast config_var_get() może zwrócić NULL w dwóch przypadkach: gdy zmienna nie została zadeklarowana lub jej wartość jest równa NULL.