menu/toolbar/key customization API (was Re: Unidentified subject!)

From: Tom Tromey <>

>Oskar> Alex Achenbach ( came up with an
>Oskar> idea that applications should bind its commands to abstract
>Oskar> symbols instead of "raw" keys.

(about making an API that takes care of initalizing and customizing menus,
toolbars, keyboard bindings etc)

>While I'm not completely sure that this can be meaningfully
>implemented via an API and simple (non-programmable) config files, I
>still think it's worth a shot.

While looking at Microsoft Word* and some other unix applications, I wrote
this draft of the API. Some basic but necessary calls are covered. I didn't
write any standards for the config files, but that could be done later. (It
really isn't of importance right now.) Tell me what you think.

* Believe it or not, in Word 97 you can create new toolbars or choose from a
set of 13 default. Menus are considered toolbars, and they can both be
modified with drag and drop. All keyboard accelerators are also
configurable. Funny, in Excel 97 you can't change the keyboard accelerators.

>Are you planning to work on this?

Yes, but I'd appreciate all comments & suggestions I could get. I must admit
I'm somewhat new to this field of programming.

Here's the first draft:


At least two new object classes need to be implemented, Command Manager and
Automatic User Interface classes. All function names and parameters are
preliminary and need better names.


Command Manager, "cmdman" (derrived from GtkObject):


  I think speed matters, that's why commands may be referenced by either
  name or uint32 id. (Should the command manager by implemented with one
  signal for each command? Or one signal for all commands? Or no signals at
  all - like it is now?)


    Create a new Command Manager instance. Use gtk_object_destroy() to
    destroy class.

  cmdman_call_command(cmdman, name, ...)
  cmdman_call_command_by_id(cmdman, id, ...)
  cmdman_callv_command(cmdman, name, argc, argv)
  cmdman_callv_command_by_id(cmdman, id, argc, argv)
    Calls the function bound to command 'name' or 'id'. fixme: command
    return codes, return codes if 'name' doesn't exist?

  cmdman_global_callback(cmdman, callback)
    The global callback is a function which will called instead of the
    function bound to a command. (To improve performance.) If callback==NULL
    remove the global callback. (fixme: will this function be necessary at

  cmdman_add_command(cmdman, name, id, callback, [long_name, help_string,
    Register a command by name and id. fixme: The extra options are used for
    help in the customization dialog. icon_pixmap could be used as the
    default toolbar/menu image.

  cmdman_remove_command(cmdman, name)
  cmdman_remove_command_by_id(cmdman, id)
    Remove the command denoted by 'name' or 'id'.

  cmdman_get_command_callback(cmdman, name)
  cmdman_get_command_callback_by_id(cmdman, id)
    Returns the callback associated with a command, or NULL if the command
    doesn't exist.

    Returns a list of installed commands.


Automatic User Interface, "autoui" (derrived from GtkObject)


  The autoui takes care of initialization and customization of menus,
  toolbars, and keyboard bindings. The application has to take care of
  providing reasonable defaults for these components, but the user can
  override these if he/she wishes. For convenience, multiple keyboard
  bindings are grouped into a 'keyset' (this may change).


    Initializes an instance of the autoui, using the specified command
    manager object.

  autoui_set_cmdman(autoui, cmdman)
    Returns or changes the command manager object for this autoui object.

  autoui_parse_config(autoui, lines)
  autoui_parse_subconfig(autoui, object_name, lines)
    Parses and installs configuration from a string. The *_subconfig
    function parses configuration and installs it for the menu, toolbar,
    or keyset specified by object_name (fixme: remove?).

  autoui_load_config(autoui, file)
  autoui_load_config_fd(autoui, fd)
    Loads and parses default or separate configuration, from either a named
    file or file descriptor. These functions use autoui_parse_config to
    parse what has been read.

  lines = autoui_generate_config(autoui)
  lines = autoui_generate_subconfig(autoui, object)
    Generates configure information based on current menus, toolbar and
    keysets. (*_subconfig for a specific menu, toolbar or keyset.) This
    information is user readable and modifyable, and can be parsed and
    installed with autoui_parse_*config.

  autoui_save_config(autoui, filename)
  autoui_save_config_fd(autoui, fd)
    Generates (and optionally saves) configure information based on current
    menus, toolbars and keysets.

  autoui_new_menutoolbar(title, data, userdata)
  autoui_new_keys(title, data, userdata)
    Creates a menu, toolbar, or keyset. This is almost always done before
    default configuration files are loaded and parsed, to create default

  autoui_customize_dialog_show([visible default])
    Show or hide the menu, toolbar, and keys customization dialog.

  container = autoui_menutoolbar_dialog_make([defaultmenu])
  container = autoui_keyset_dialog_make([defaultmenu])
    Creates a Gtk container/box that contains necessary widgets for
    creating, removing and modifying menus. (fixme lazy: How to handle
    OK/Apply/Cancel stuff?)

    Return a list of existing menus, toolbars, keys.


    Sent whenever one of the existing menus, toolbars, or keyset has been

    Sent whenever a new menu, toolbar or keyset has been created.


A simple pseudo application

(Note that function calls/datatypes marked pseudo have been simplified or
does not exist at all.)

int main(int argc, char **argv)
  AutoUI *autoui;
  CmdMan *cm;

  GnomeUIInfo defaultMenu = { ... };
  GnomeUIInfo defaultToolbar[] = { ... };
  GtkAcceleratorTable defaultKeys = { ... }; /* pseudo datatype (?) */
  GnomeUIInfo defaultContextMenu[] = { ... } ;

  ... gnome_init, etc ...

  cm = cmdman_new();
  cmdman_add_command(cm, "open", COMMAND_OPEN, command_open);
  cmdman_add_command(cm, "save", COMMAND_SAVE, command_save);
  cmdman_add_command(cm, "quit", COMMAND_QUIT, command_quit);

  autoui = autoui_new();
  gtk_signal_connect(autoui, "update", updated_autoui); /* pseudo call */
  gtk_signal_connect(autoui, "new", new_autoui); /* pseudo call */
  autoui_new_menutoolbar("Menubar", defaultMenu, some_userdata);
  autoui_new_menutoolbar("Standard", defaultToolbar, some_userdata);
  autoui_new_keyset("Standard", defaultKeys, userdata);
  autoui_new_menutoolbar("Document Context Menu", defaultContextMenu,

  ... main ...

new_autoui(type, name, data)
  switch (type) {
    case MENUTOOLBAR : gtk_add_item_to_toolbar_context_menu(name); break;

updated_autoui(type, name, data, userdata)
  switch (type) {
    case MENUTOOLBAR : gtk_update_menu(data); break; /* pseudo call */
    case KEYS : gtk_install_acceleratortable(data); break; /* pseudo */


Keyboard Accelerator Allocation

  The autoui utilizes these functions to get a keyboard accelerator for a
command, and an application may do so too. There are three databases which
describe commands and key bindings, system global, user global, and user
application specific. These databases are searched backwards (i.e. user
application specific first).


  key_accel = allocate_key(command_name, default_key1, [default_key2, ...])
    Get the prefered key for command specified by command_name. If that
command doesn't exist or has no default key, try default_key1. If that key
is already taken, try default_key2 and so on. When no more default_key's are
available, automaticly allocate the nearest free key.

  string = get_key_string(key_accel)
    Return a string describing key_accel, usually for insertion in menus and
tooltips. For example, "Ctrl+A", "Ctrl+Alt+Q", "Shift+B" are possible return


Oskar Liljeblad (

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]