Next: , Previous: , Up: Hello Emacsy   [Contents][Index]


4.2 The Simplest Application Ever

Let’s exercise these functions in a minimal FreeGLUT program we’ll call hello-emacsy.4. This simple program will display an integer, the variable counter, that one can increment or decrement.

images/minimal-emacsy-example
Variable: int counter = 0;

Hello Emacsy’s state is captured by one global variable. Hello Emacsy will display this number.

Initialize everything in main and enter our runloop.

C Function: glutInit (&argc, argv);

Initialize GLUT.

C Function: void scm_init_guile ();

Initialize Guile.

C Function: emacsy_initialize (…);

Initialize Emacsy.

C Function: primitives_init ();

Register primitives.

C Function: char * try_load_startup (…);

Try to load hello-emacsy.scm

C Function: void glutMainLoop ();

Enter GLUT main loop, not return.

4.2.1 Runloop Interaction

Let’s look at how Emacsy interacts with your application’s runloop since that’s probably the most concerning part of embedding. First, let’s pass some input to Emacsy.

C Function: void keyboard_func (unsigned char glut_key, int x, int y)

Send key events to Emacsy.

int key; // The Key event (not processed yet).

The keys C-a and C-b return 1 and 2 respectively. We want to map these to their actual character values.

C Function: void display_func ()

The function display_func is run for every frame that’s drawn. It’s effectively our runloop, even though the actual runloop is in FreeGLUT.

Our application has just one job: Display the counter variable.

C Function: glClear (GL_COLOR_BUFFER_BIT);

Setup the display buffer the drawing.

Process events in Emacsy.

Display Emacsy message/echo area.

Display Emacsy mode line.

C Function: void draw_string (int x, int y, char *string)

Draw a string function. Draws a string at (x, y) on the screen.

At this point, our application can process key events, accept input on the minibuffer, and use nearly all of the facilities that Emacsy offers, but it can’t change any application state, which makes it not very interesting yet.

4.2.2 Plugging Into Your App

Scheme Procedure: get-counter
C Function: SCM scm_get_counter ()

Let’s define a new primitive Scheme procedure get-counter, so Emacsy can access the application’s state. This will define a C function SCM scm_get_counter (void) and a Scheme procedure (get-counter).

Scheme Procedure: set-counter! value
C Function: SCM scm_set_counter_x (SCM value)

Let’s define another primitive Scheme procedure to alter the application’s state.

C Function: void primitives_init ()

Once we have written these primitive procedures, we need to register them with the Scheme runtime.

C Function: char * try_load_startup (char const* prefix, char const* dir, char const* startup_script)

Locate the hello-emacsy.scm Guile initialization and load it.

We generate the file example/hello-emacsy.c.x by running the command: guile-snarf example/hello-emacsy.c. Emacsy can now access and alter the application’s internal state.

Interactive Procedure: incr-counter #:optional (n (universal-argument-pop!))
Interactive Procedure: decr-counter #:optional (n (universal-argument-pop!))
Scheme Procedure: global-map

Bind inc-counter to =.

Scheme Procedure: global-map

Bind inc-counter to -.

Let’s implement another command that will ask the user for a number to set the counter to.

Interactive Procedure: change-counter

Now we can hit M-x change-counter and we’ll be prompted for the new value we want. There we have it. We have made the simplest application ever more Emacs-y.

We can add commands easily by changing and reloading the file. But we can do better. Let’s start a REPL we can connect to. example/hello-emacsy.scm.

(use-modules (system repl server))
(spawn-server)

Start a server on port 37146.


Footnotes

(4)

Note: Emacsy does not rely on FreeGLUT. One could use Gtk+, Ncurses, Qt, or whatever


Next: , Previous: , Up: Hello Emacsy   [Contents][Index]