Alicq Module Writing Reference

Author Ihar Viarheichyk

Content

I. Introduction

Module is a basic unit for extending functionality of Alicq. Alicq module is just a tcl script which is evaluated in alicq interpreter and has full access to internal valiables and procedures of Alicq. There is no restictions on content of the module, however, number of helper functions are designed for module writers to simplity module interoperability and integration.

II. Module Namespaces and Data Structures

On load, each module is placed into it's own child namespace of ::modules namespace. It is possible to override such behaviour by placing module into arbitrary namespace explicitly, e.g.:
		namespace eval ::my_cool_module {
			...
		}
	
However, overriding automatical namespace generation can cause side-effects which module designer should be aware of. Firts of all, module metainformation becames unavailable, and modules becames invisible for modules providing configuration dialogs, menu, etc. Then, module command can not detect if module was loaded to prevent loading of already loaded module. Later it can cause problems with module unloading (this feature is not implemented yet), thus such practice is hoghly deprecated.

Module can contain any number of child namespaces of arbitrary depth, however, some namespace names have special meaning.

Namespace meta contains module global metaingormation and metainformation about configurable parameters. Detailed description of metainformation is given in Metainformation section.

Namespace validate contains validation procedures for module-specific data types.

Module can operate with arbitrary data scructures within its namespaces, however, there is one data type which is used for module interoperability and configuration. It is called objects, though it is nothing more than standard Tcl arrays, which are defined in child namespaces of ::object namespace. Objects have metainformation which describes their fields, and Alicq provides two helper commands: ref and obj to convert object name to corresponding variable name and vice versa. Such mapping between object name and object variable makes object names more stable and independent from actual variable names. Detailed information about objects can be found in Objects section.

III. Interaction with Alicq and Other Modules

Module can interact with Alicq core and other modules in several ways. First of all, it can use all avalable commands and access all variables. Second, module can handle different events. There are several categories of events which alicq module can handle.

III.1. Windowing system events

Module can bind hook scripts to windowing system events using standard Tk command bind. This allows handing of UI events.

III.2. File events

Module can bind hook scripts to open file descriptors using standard Tcl command fileevent.

III.3. Traces

This is primary way to monitor changes in object variables and module configuration parameters. Use standard Tcl command trace for it.

III.4. Alicq events

This is only non-standard way of module intercommunication in Alicq. It uses helper commands Event and hook to generate and hook events with no pre-defined recipient. Purpose of this way of intercommunication is implementation of indirect calls, when event sender does not know which module or modules can handle certain procedure call. It allows co-existance of different implementations of same functionality, e.g. module providing dialogs has not know which module will handle Send event it generates to send message.

IV. Alicq Events and Hooks

Alicq Events and Hooks is a primary way of module intercommunication, when one module has to request another module or modules to perform any action, and does not exacly knows which modules should perform it.

Module can generate an event using Alicq helep command Event. Event is identified by unique name and can have any number of optional parameters, specific for each event.
		Event SetStatus online
	
Module can hook events using hook command, which binds one or more events to script which is invoked when matching event occurs. Unlike bind command used to intercept windowing system events, hooks not replaces old handler with new one, but adds new handler to list of handlers. These handlers are invoked according their priorities in foreach loop. This means that each handler can cancel low-priority handlers by finishig with
		return -code break
	
call, cancel parameters re-assigning in filtering hook using
		return -code continue
	
etc.

If hook is not needed any more, it can be removed using unhook.

V. Objects

Objects are commonn Tcl arrays resided in child namespaces of ::object namespace. Each object has unique name or UID - Unique IDentifier. UID of the object is constructed from its parent namespaces and array name within namespace, separated with colon:
		Contact:ICQ:47298730
		Contact:SMS:+375296xxxxxx
		Group:common:47298730
		Group:common:other
		Url:http
		Proxy:default
	
UID can be mapped to actual variable name using ref, and variable name can be mapped to object name using obj. Use ref when installing monitoring of object property, e.g:
		proc MonitorObject {uid} {
			trace variable [ref $uid](Alias) w [nc AliasChanged $uid]
		}
	

Alicq provides command select to select objects of given domain or matching any condition. For example
		select Contact:ICQ {![info exists Status]||$Status=="offline"}
	
selects ICQ contacts which has no status or offline.
		select {Contact Group:common}
	
selects all contacts and common groups.
		select Proxy {$type=="http"}
	
selects all http proxies.

Each object can have any number of fields. They are just array fields, however, developer can provide metainformation for some fields, which allow other modules to handle them properly, e.g. configure via configuration dialog, validate new value in startup file commands, save on change etc. For more information about metainformation see Metainformation section.

VI. Metainformation

Metainformation is a way to provide information describing module itself, its configurable parameters, available actions, object fields etc. Its main purpose is to provide uniform and simple interface for modules implementins such features as menus, configuration dialogs, etc, as well as module autodocumentation.

VI.1. Module metainformation

Module metainformation is stored in meta child of module namespace. It is processed by module loader after sourcing module into Alicq interpreter.

Module provides metainformation by means of Tcl variables and arrays.

Common Tcl variables are used to provide global module metainformation, such as author, description, icon, etc. Name of metavariables and their semantics depends on modules handling metainformation. No restrictions on metavariables names exist.
		namespace eval meta {
			set description "Very important module"
			set author "Vasiliy Pupkin"
		}
	
Tcl arrays are used to represent metainformation about module configurable parameters. Name of array should be same as name of Tcl variable, representing configurable parameters, and names of array fields represent names of metaproperties. Names of metaproperties and their semantics depends on modules handling metaproperties. No restrictions on metaproperties names exist.
		namespace eval meta {
			set description "Very important module"
			set author "Vasiliy Pupkin"
			array set logfile {
				description "File name to save log to"
				type file default my.log
				save change
			}
			array set logging {
				description "Logging activity flag"
				type boolean default no menu {Tools Logging Active}
				save exit
			}
			array set clean {
				description "Clear log"
				type action menu {Tools Loggin "Clean Log"}
			}
		}
	

VI.2. Object metainformation

Objects also have metainformation which is handled in slightly different manner. Object metainformation is also represented by Tcl variables and arrays. Unlike module metainformation, arrays are used to represent metainformation for object fields, not objects themself. Name of meta array should be same as name of object field.

Object metainformation is inheritable. It means that metainformation specified for Contact objects is used for Contact:ICQ objects as well.
		namespace eval [ref Contact]::meta {
			array set Alias {
				description "Contact Alias"
				save change
			}
			array set Send:text {
				description "Send simple text message"
				type action menu {Send Message}
			}
		}
		namespace eval [ref Contact:ICQ]::meta {
			array set rid {
				description "ICQ contact server-side roster ID"
				type integer save change
			}
		}
	

VII. Helper Commands Reference

VIII. Most Important Alicq Events

There is no way to describe all possible Alicq Events, because each module can use its own event for its purpose. This section descibes several important events which new module writer is probably interested in most of others.