Node:Programming special windows, Next:, Previous:Programming a new layout, Up:The layout-engine



All aspects of programming special windows

ECB offers a flexible programmable layout-engine for other packages to display their own contents and informations in special ECB-windows. An example could be a graphical debugger which offers a special window for displaying local variables and another special window for messages from the debugger-process (like JDEbug of JDEE1).

This section explains all aspects of programming new special windows, adding them to a new layout and synchronizing them with edit-window of ECB. This can be done best with an easy example which nevertheless covers all necessary aspects to be a good example and skeleton for complex tools (like a graphical debugger) which want to use the layout-engine of ECB do display their own information.

Here comes the example:

The outline of the example layout:

-------------------------------------------------------
|Bufferinfo for <filename>:            |[prior]       |
|Type: file                            |[next]        |
|Size: 23456                           |              |
|Modes: rw-rw-rw-                      |              |
|-----------------------------------------------------|
|                                                     |
|                                                     |
|                                                     |
|                                                     |
|                 edit-window                         |
|                                                     |
|                                                     |
|                                                     |
|                                                     |
-------------------------------------------------------
|                                                     |
|                 compilation-window                  |
|                                                     |
-------------------------------------------------------
The description of the layout-contents

The top-left window always displays informations about the current buffer in the selected edit-window. This window demonstrates how autom. synchronizing a special window/buffer of a layout with current edit-window.

The top-right window contains an read-only "action-buffer" and offers two buttons which can be used with the middle mouse-button to scroll the edit-window. This is not very senseful but it demonstrates how to control the edit-window with actions performed in a special window/buffer of a layout.

(If you have not set a compilation-window in ecb-compile-window-height then the layout contains no durable compilation window and the other windows get a little more place).

The example code

Now let have us a look at the several parts of the Elisp-program needed to program this new example layout. ECB contains a library ecb-examples.el which contains the full working code of this example. To test this example and to play with it you can load this library into Emacs (with load-library for example) and then calling ecb-change-layout (bound to C-c . lc) and inserting "example-layout1" as layout-name. An alternative is calling ecb-examples-activate and ecb-examples-deactivate. For details see file ecb-examples.el.

The following steps only contain code-skeletons to demonstrate the principle. The full working code is available in ecb-examples.el.

The bufferinfo buffer of the example

The name of the bufferinfo buffer:

(defconst ecb-examples-bufferinfo-buffer-name " *ECB buffer info*")

Two helper functions for displaying infos in a special buffer:

(defun ecb-examples-print-file-attributes (buffer filename)
  (ecb-with-readonly-buffer buffer
    (erase-buffer)
    (insert (format "Bufferinfo for %s:\n\n" filename))
    ;; insert with the function `file-attributes' some
    ;; informations about FILENAME.
    ))

(defun ecb-examples-print-non-filebuffer (buffer buffer-name)
  (ecb-with-readonly-buffer buffer
    (erase-buffer)
    ;; analogous to `ecb-examples-print-file-attributes'
    ))

The main synchronizing function added to ecb-current-buffer-sync-hook for autom. evaluation by ecb-current-buffer-sync which runs dependent on the values of ecb-window-sync and ecb-window-sync-delay. This function synchronizes the bufferinfo buffer with the current buffer of the edit-window if that buffer has changed.

(defun ecb-examples-bufferinfo-sync ()
  (ecb-do-if-buffer-visible-in-ecb-frame
      'ecb-examples-bufferinfo-buffer-name

    ;; here we can be sure that the buffer with name
    ;; `ecb-examples-bufferinfo-buffer-name' is displayed in a
    ;; window of `ecb-frame'

    ;; The macro `ecb-do-if-buffer-visible-in-ecb-frame' locally
    ;; binds the variables visible-buffer and visible-window!! See
    ;; documentation of this macro!

    (let ((filename (buffer-file-name (current-buffer))))

      (if (and filename (file-readable-p filename))

          ;; real filebuffers
          ;; here we could add a smarter mechanism;
          ;; see ecb-examples.el
          (ecb-examples-print-file-attributes visible-buffer
                                              filename)

        ;; non file buffers like help-buffers etc...
        (setq ecb-examples-bufferinfo-last-file nil)
        (ecb-examples-print-non-filebuffer visible-buffer
                                           (buffer-name
                                             (current-buffer)))
        ))))

The function which makes the bufferinfo-buffer dedicated to a window.

(defun ecb-examples-set-bufferinfo-buffer ()
  (ecb-with-dedicated-window
      ecb-examples-bufferinfo-buffer-name
      'ecb-examples-set-bufferinfo-buffer
    (switch-to-buffer (get-buffer-create
                       ecb-examples-bufferinfo-buffer-name))
    (setq buffer-read-only t)))

This is all what we need for the special bufferinfo buffer. We have demonstrated already three of the important functions/macros of the layout-engine API of ECB: ecb-with-readonly-buffer, ecb-do-if-buffer-visible-in-ecb-frame and ecb-with-dedicated-window (see The layout-engine API. Especially the second macro is strongly recommended for programming good synchronizing functions which do not waste CPU!

The action buffer of the example

The name of the action-buffer:

(defconst ecb-examples-action-buffer-name " *ECB action buffer*")

Two helper functions for creating a readonly action-buffer with a special local key-map for the middle-mouse-button and two buttons [prior] and [next]:

(defun ecb-examples-insert-text-in-action-buffer (text)
  (let ((p (point)))
    (insert text)
    (put-text-property p (+ p (length text)) 'mouse-face
                                             'highlight)))

(defun ecb-examples-action-buffer-create ()
  (save-excursion
    (if (get-buffer ecb-examples-action-buffer-name)
        (get-buffer ecb-examples-action-buffer-name)

      (set-buffer (get-buffer-create
                    ecb-examples-action-buffer-name))

      ;; we setup a local key-map and bind middle-mouse-button
      ;; see ecb-examples.el for the full code

      ;; insert the action buttons [prior] and [next] and
      ;; make it read-only

      (ecb-with-readonly-buffer (current-buffer)
        (erase-buffer)
        (ecb-examples-insert-text-in-action-buffer "[prior]")
        ;; analogous for the [next] button
        )

      (current-buffer))))

The function which performs the actions in the action-buffer if clicked with the middle-mouse button onto a button [next] or [prior].

(defun ecb-examples-action-buffer-clicked (e)
  (interactive "e")
  (mouse-set-point e)
  (let ((line (buffer-substring (ecb-line-beginning-pos)
                                (ecb-line-end-pos))))
    (cond ((string-match "prior" line)
           (ecb-select-edit-window)
           (call-interactively 'scroll-down))
          ((string-match "next" line)
           ;; analogous for [next]
           ))))

The function which makes the action-buffer dedicated to a window.

(defun ecb-examples-set-action-buffer ()
  (let ((buf-name (buffer-name (ecb-examples-action-buffer-create))))
    (ecb-with-dedicated-window buf-name 'ecb-examples-set-action-buffer
      (switch-to-buffer (buffer-name
                         (ecb-examples-action-buffer-create))))))

We do not need more code for the action buffer. All of the code is standard emacs-lisp which would also needed if used without ECB.

Adding the bufferinfo- and action-buffer to a new layout

Now we add the bufferinfo- and the action-buffer to a new layout of type top with name "example-layout1":

(ecb-layout-define "example-layout1" top

  ;; dedicating the bufferinfo window to the bufferinfo-buffer
  (ecb-examples-set-bufferinfo-buffer)

  ;; creating the action-window
  (ecb-split-hor 0.75)

  ;; dedicate the action window to the action-buffer
  (ecb-examples-set-action-buffer)

  ;; select the edit-window
  (select-window (next-window)))

This all what we need to define the new layout. See Programming a new layout for more details of the pure layout-programming task.

Synchronizing the bufferinfo-buffer automatically

The last thing we have to do is to synchronize the bufferinfo-buffer with current edit-window. We do this by adding ecb-examples-bufferinfo-sync to the hook ecb-current-buffer-sync-hook' (The file ecb-examples.el shows a smarter mechanism for (de)activating the new layout and the synchronization but this works also very well).

(add-hook 'ecb-current-buffer-sync-hook 'ecb-examples-bufferinfo-sync)
Activating and deactivating new layouts

Because a set of new special windows integrated in a new layout is often just the GUI of a complete tool (like a graphical debugger) we demonstrate here the complete activation and deactivation of such a tool or at least of the tool-GUI. We decide that the GUI of our example "tool" needs a compile-window with height 5 lines and the height of the special windows "row" on top should be exactly 6 lines (normally width and height of the special windows should be a fraction of the frame, but here we use 6 lines2

Here comes the (de)activation code.

The code for saving and restoring the state before activation (the full code is available in ecb-examples.el:

(defun ecb-examples-preactivation-state(action)
  (cond ((equal action 'save)
         ;; code for saving the state
         )
        ((equal action 'restore)
        ;; code for restoring the state
        )))

The following function activates the GUI of our example tool:

(defun ecb-examples-activate ()
  (interactive)

  ;; activating the synchronization of the bufferinfo-window
  (add-hook 'ecb-current-buffer-sync-hook
            'ecb-examples-bufferinfo-sync)

  ;; saving the state
  (ecb-examples-preactivation-state 'save)

  ;; switch to our preferred layout
  (setq ecb-windows-height 6)
  (setq ecb-compile-window-height 5)
  (ecb-layout-switch "example-layout1"))

This function deactivates the GUI of our example-tool and restores the state as before activation:

(defun ecb-examples-deactivate ()
  (interactive)

  (remove-hook 'ecb-current-buffer-sync-hook
               'ecb-examples-bufferinfo-sync)
  (ecb-examples-preactivation-state 'restore)
  (ecb-layout-switch ecb-layout-name))

Now we have all code for the new layout and the new layout-buffers. The example is ready for use; just load ecb-examples.el (s.a.).


Footnotes

  1. JDEE is available at http://jdee.sunsite.dk/

  2. You can change the code in the file ecb-examples.el to use a frame-fraction of 0.2 instead of 6 hard lines, just try it!