MH & nmh: Email for Users & Programmers

May, 2006

Changing Buttons; Accelerators

xmh has a long list of action procedures that it runs when you click a mouse button, select a command from a menu, or click a button in a window. These are set in your system's Xmh resource file. You can change the way xmh works by adding entries to your own resource file (like .Xdefaults). For more information, see O'Reilly Media's Volume Four, X Toolkit Intrinsics Programming Manual, Chapter 8, Events, Translations, and Accelerators.

The Table below is an alphabetical list of xmh actions. For a list grouped by function, with longer descriptions, see the section called PROCESSING YOUR MAIL in the xmh(1) manual page.

Table: xmh Release 5 Actions

Add selected messages to selected sequence.
Check all mail drops.
Close main window.
Close view window or composition window.
Execute all deletions, moves and links.
Compose new message.
Create folder or subfolder.
Delete selected folder (with confirmation).
Remove selected sequence.
Edit viewed message.
Rebuild Table of Contents.
Forward selected or current message(s).
Incorporate new mail.
Insert message you're replying to.
Update menu button when pointer moves out.
Mark message(s) to link.
Mark message(s) to delete.
Mark message(s) to move.
Open foldername or selected folder.
Open selected folder in new window.
View selected sequence.
Renumber messages as 1, 2,....
Open Pick window to define new sequence.
Pop folder off stack, set selected folder.
Pop sequence off stack of sequence names.
Build folder button menu if any; open it.
Print selected or current message(s).
Print the viewed message.
"Click OK" for XmhCreateFolder()
XmhPushFolder([foldername, ...])
Push argument or selected folder(s) on stack.
XmhPushSequence([sequencename, ...])
Push argument or selected sequences(s) on stack.
Update sequence menu from public MH sequences in current folder.
Remove selected messages from selected sequence.
Reply to selected or current message.
New Headers button.
Save composition in drafts folder.
Save message in view window.
Send composition.
Set selected folder. (Menu widget buttons only.)
XmhShellCommand(parameter[, parameter])
Give parameters with full pathname of selected or current message(s) to UNIX shell.
Sort folder.
Remove link/delete/move marks from selected or current message(s).
Create composition window from current or first selected message.
Forward viewed message.
View current or first selected message in new window.
Mark viewed message for deletion.
View first selected message or first message after current.
View last selected message or first message before current.
Reply to viewed message.
Use message in view window as composition.
XmhWMProtocols([wm_delete_window] [wm_save_yourself])
For window manager communication protocols. See xmh(1) manual page.

New Accelerator for Compose Message

This section shows how to add and change resource entries for accelerators.

Let's add an accelerator for Compose Message.

The Example below shows the section of the online Xmh resource file that sets accelerators for commands on the Message menu. (You can also get this file from the book's online archive. It's in examples/xmh/X/resources-1.)

Example: Default message menu accelerators

    *messageMenu.Accelerators: #override\n\
             Meta<Key>space: XmhViewNextMessage()\n\
            :Meta<Key>c:    XmhMarkCopy()\n\
            :Meta<Key>d:    XmhMarkDelete()\n\
            :Meta<Key>f:    XmhForward()\n\
            :Meta<Key>m:    XmhMarkMove()\n\
            :Meta<Key>n:    XmhViewNextMessage()\n\
            :Meta<Key>p:    XmhViewPreviousMessage()\n\
            :Meta<Key>r:    XmhReply()\n\
            :Meta<Key>u:    XmhUnmark()\n
The first line has the name of the resource, *messageMenu.Accelerators. The other lines have entries in pairs, one pair per accelerator. Because each line except the last one ends with a backslash (\) (which is the line continuation character), all of these are part of the same resource entry.

For example, the third line defines the META-C accelerator. When you type META-C, that executes the XmhMarkCopy() action, which marks the selected messages for linking ("copying").

As the Table xmh Release 5 Actions shows, the action for composing a new message is XmhComposeMessage(). You'll want to pick an accelerator key that's not already used. Look through the list in the xmh manual page. Let's say that you choose META-SHIFT-M. You'll need to add a new accelerator/action pair to the resource list.

The order of the accelerators in a resource list doesn't matter. Let's add the new entry at the end. Copy all ten lines of the entry into your resource file (like .Xdefaults) and add a new pair for your new accelerator. I added a continuation character (a backslash (\)) to the end of the last existing line in the previous Example. Then I added the new META-SHIFT-M accelerator on a new line below it. The new lines in the resource file are shown in the next Example. (You can also get it from the book's online archive. Grab examples/xmh/X/resources-2.)

Example: Message menu accelerators with new ComposeMessage()

    *messageMenu.Accelerators: #override\n\
             Meta<Key>space: XmhViewNextMessage()\n\
            :Meta<Key>c:    XmhMarkCopy()\n\
            :Meta<Key>d:    XmhMarkDelete()\n\
            :Meta<Key>f:    XmhForward()\n\
            :Meta<Key>m:    XmhMarkMove()\n\
            :Meta<Key>n:    XmhViewNextMessage()\n\
            :Meta<Key>p:    XmhViewPreviousMessage()\n\
            :Meta<Key>r:    XmhReply()\n\
            :Meta<Key>u:    XmhUnmark()\n\
            :Meta<Key>M:    XmhComposeMessage()\n

Restarting xmh will bring in this new accelerator. Try it: type META-SHIFT-M and a composition window should open.

Redefining Composition Window Buttons

These examples show how to change the labels and actions of two buttons on the composition window buttonbox. They also add a new accelerator.

Accelerator to Send Draft and Close Window

This one defines META-S to send the draft and close the window. It uses two xmh actions. Add the following to your resource file:

    Xmh*comp.translations: #override\n\ :Meta<Key>s:
As you can see, to get more than one action from an accelerator, just list the actions one after the other. This was taken from the Xmh.sample file in the X directory tree -- see that file for many more examples.

Redefine New Headers Button to be Send and Close

The new META-S accelerator in the previous section speeds up a common thing you do from a composition window: send the draft and close the window. Next, let's see how to redefine a much less used button, New Headers, and make the button Send and Close instead.

Here are the two new resource entries for your resource file:

    xmh*compButtons.reset.Translations: #override\n\
            <Btn1Down>,<Btn1Up>: XmhSend()XmhCloseView()unset()\n
    xmh*compButtons.reset.label: Send and Close
Those entries do two things:
  1. When you point to the third composition window button (.reset), then press (<Btn1Down>) and release (<Btn1Up>) the first mouse button, xmh should perform the XmhSend() and XmhCloseView() actions, then unset() to finish.
  2. The resource entries change the label of the button from the default (New Headers) to Send and Close.
The first Figure below and the next Figure below are before-and-after pictures of the composition window buttonbox.

Figure: Default composition window buttonbox


Figure: Composition window New Headers changed to Send and Close


If you still would like the New Headers button, you can replace the Compose Message button with a New Headers button. I've always thought that New Headers was a misleading name because it removes all changes, not just the header. So I'll also rename New Headers to Start Over. Here are the new resource file entries (they work the same way as the button redefinitions above, but they redefine the fourth button, .compose). You can also get this file from the book's online archive. See examples/xmh/X/resources-6.)

    xmh*compButtons.compose.Translations: #override\n\
            <Btn1Down>,<Btn1Up>: XmhResetCompose()unset()\n
    xmh*compButtons.compose.label: Start Over
After that redefinition, the composition window buttonbox looks like the Figure below.

Figure: Composition window with two buttons redefined


A New Buttonbox for the Main Windows

You can set a resource called CommandButtonCount that lets you make completely new buttons on the main window. CommandButtonCount is the number of command buttons to create in a new buttonbox between the Table of Contents and the view areas of the main window. xmh will create these buttons with the names button1, button2, and so on, in a box with the name commandBox. You can specify labels and actions for the buttons in a private resource file.

The Figure below is an example of an uncustomized display.

Figure: Display (not customized yet) with *CommandButtonCount:5


It's made with this single resource file entry:

The default CommandButtonCount is 0, which gives no buttonbox. Now let's fill in the buttonbox. If you're an MH user, too, you may want buttons labeled with the MH command equivalents. If you know those names, this is a good way to get a lot of use out of a small area on the main window. (I like these buttons because sometimes I forget the accelerators.)

After you add entries for the buttons to your resource file, your main windows will look like the Figure after the Example.

Once you see the pattern, the buttons are easy to figure out yourself.

This next Example shows the parts of the resource file entries for the first and fourth buttons. You can also get the whole file from the book's online archive, at examples/xmh/X/resources-3. Putting an exclamation point (!) at the start of a line makes it a comment.

Example: Defining two of the new command buttons

    !# define the number of buttons in the buttonbox
    Xmh*CommandButtonCount: 12
    !# 1: left mouse button:                "inc" MH command
    Xmh*commandBox.button1.label:   inc
    Xmh*commandBox.button1.translations:    #override\n\
            <Btn1Down>,<Btn1Up>: XmhIncorporateNewMail()unset()
    !# 4: left or right mouse buttons:      "rmm" MH command
    Xmh*commandBox.button4.label:   rmm
    Xmh*commandBox.button4.translations:    #override\n\
            <Btn1Down>,<Btn1Up>: XmhMarkDelete()unset()\n\
            <Btn3Down>,<Btn3Up>: XmhMarkDelete()unset()

Figure: Main window with new buttonbox


Notice that the fourth button in the buttonbox can be activated with either the first or the third mouse button.

Adding Color

You can change foreground and background color of new buttons just the way you can change the color of other resources. For example, the following lines would change the colors of the first and last buttons (inc and quit) in the new buttonbox on the main window:

    xmh*commandBox.button1.foreground: yellow
    xmh*commandBox.button1.background: navy
    xmh*commandBox.button12.foreground: navy
    xmh*commandBox.button12.background: red
Using color is a nice way to group related buttons.

Moving a Message to a Specific Folder

Here's how to add a button that marks a message for moving directly to a specific folder or subfolder. The folder here is named todo/June (you can use another name, of course).

    xmh*commandButtonCount: 1
    xmh*commandBox.button1.label: Move to todo/June
    xmh*commandBox.button1.translations: #override\n\
            <Btn1Down>,<Btn1Up>: set() XmhPushFolder()\
            XmhPushFolder(todo/June) XmhPopFolder()\
            XmhMarkMove() XmhPopFolder() unset()

Changing Command Options with edprofile

xmh does some of its work, such as displaying messages, with internal routines. It calls MH commands to do everything else. (According to the xmh Revision 5 manual page, xmh uses at least the following MH commands: inc, msgchk, comp, send, repl, forw, refile, rmm, pick, pack, sort, and scan.) Those MH commands read options from your MH profile file. Some MH profile options are overridden by xmh; you can set the others in your MH profile. For example, you can change the options that scan uses to build the Table of Contents.

Before xmh introduced the XmhShellCommand() action in Release 5, the only way to change MH profile options was with a text editor. Now you can define buttons that call a shell script named edprofile -- and edit your MH profile from a main xmh window.

The details of setting up edprofile are below. The Section A New Buttonbox for the Main Windows shows how to add new buttons to the main window. The Example below has the lines to put in your resource file for making two buttons that change scan. (You can also get this file from the book's online archive. It's in examples/xmh/X/resources-4.)

Example: Changing sort order with edprofile

    Xmh*CommandButtonCount: 2
    Xmh*commandBox.button1.label: default toc
    Xmh*commandBox.button1.translations: #override\
      <Btn1Down>,<Btn1Up>: XmhShellCommand(edprofile -v scan --) unset()
    Xmh*commandBox.button2.label: size toc
    Xmh*commandBox.button2.translations: #override\
      <Btn1Down>,<Btn1Up>: XmhShellCommand(edprofile scan -form scan.size --) unset()
The first button, labeled size toc, adds the size of each message to the Table of Contents the next time the folder is rescanned. (The Section scan Format Files explains and shows examples of this.) The button runs the command:
    edprofile scan -form scan.size --
that changes the MH profile scan entry to look like this:
    scan: -form scan.size
Any switches on that MH profile scan entry before edprofile runs are deleted.

The second button, labeled default toc, will run the command:

    edprofile -v scan
The scan entry in the MH profile will be changed to this:
The next time a folder is rescanned, it will have the default format.

Unfortunately, there must be a current or selected message before you run XmhShellComand(). If there's not a message selected, choose any one before you click the button that runs edprofile.

NOTE: edprofile only works with the Release 5 and beyond; these versions have the xmhShellCommand() action.

The command-line syntax of edprofile is:

    edprofile [-v] entry [new-value] --
Brackets, like [-v], mean that part isn't required. The parts are: One last note: if you've defined the MH environment variable, edprofile will edit the file it points to. The default file is $HOME/.mh_profile.

This program is described in the Section Explanation of edprofile.

Use an External Editor

If you don't want to use the standard xmh editor on your drafts, and you can't use the patches for an external editor explained in the Section Use Another Editor, here's another way. Add the entries shown in the next Example to your resource file. (If you haven't added buttons before, there's help in the Section A New Buttonbox for the Main Windows.) You can also get this file from the book's online archive. See examples/xmh/X/resources-5.)

Example: Button to edit a message with vi

    Xmh*CommandButtonCount: 1
    Xmh*commandBox.button1.label: edit vi
    Xmh*commandBox.button1.translations: #override\
      <Btn1Down>,<Btn1Up>: XmhShellCommand(xterm -e vi) unset()
The button runs vi in an xterm window; it gives vi the full pathname of the message(s) you select. When you exit vi, the window will close. It's clumsy, but it works. The steps to use the button are:
  1. Start a draft message and Save it.
  2. Open the drafts folder in a main window.
  3. Select the draft message to edit.
  4. Click your vi editor button. An xterm window with the editor pops up.
  5. Do your edits. Save and quit vi.
  6. Select Use as Composition to bring up the draft again. Click Send to send the message.
If you use this a lot, you could bind more of the actions to the button. The list of xmh actions is in the Table xmh Release 5 Actions.

You can use this same technique to run spell-checking programs or any other UNIX program to help you edit.