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



9.5.2 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:

9.5.2.1 The outline of the example layout:
   -------------------------------------------------------
   |Bufferinfo for <filename>:            |[prior]       |
   |Type: file                            |[next]        |
   |Size: 23456                           |              |
   |Modes: rw-rw-rw-                      |              |
   |-----------------------------------------------------|
   |                                                     |
   |                                                     |
   |                                                     |
   |                                                     |
   |                 edit-window                         |
   |                                                     |
   |                                                     |
   |                                                     |
   |                                                     |
   -------------------------------------------------------
   |                                                     |
   |                 compilation-window                  |
   |                                                     |
   -------------------------------------------------------
9.5.2.2 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).

9.5.2.3 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.

9.5.2.4 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!

9.5.2.5 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.

9.5.2.6 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.

9.5.2.7 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)
9.5.2.8 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!