The design of a backend

Introduction

Each backend need to support the following functions. * Generate redraw events. * Generate keyboard events. * Generate mouse events. * Build the application window and talk to the window manager.

All events are modeled by the observer pattern.

Build the initial window

Currently, in the X backend, we need to construct the application in

rt  =  X_MB_new(":0.0", 800,600);
rdman = X_MB_rdman(rt);
svg2code = svg2code_new(rdman,rdman->root_coord);
ex_rt.rt = rt;
ex_rt.code = svg2code;
subject = coord_get_mouse_event(svg2code->file_button);
subject_add_observer(rdman_get_ob_factory, subject, file_button_handler, &ex_rt);
X_MB_handler_connection(rt);

In my point of view, we don't need to export the rt at all. It should be internal of the backend. Therefore, I suggest to rewrite the above code as

rdman  =  mb_new("X",":0.0",800,600);
svg2code = svg2code_new(rdman,rdman->root_coord);
subject = coord_get_mouse_event(svg2code->file_button);
subject_add_observer(rdman_get_ob_factory, subject, file_button_handler, svg2code);
mb_mainloop();

The mb_new will use the first argument to select the backend. In this case, it will select the "X" backend and call X_MB_new() to create the initial window. In addition, the X_runtime_t will not be returned at all. Instead, the rdman is returned. We can use the rdman object to load as many SVG objects as possible.

By using the dynamic loading API, the above code can be rewritten as

rdman  =  mb_new("X",":0.0",800,600);
svg2code = rdman_object_load(rdman,rdman->root_coord,"svg2code");
subject = coord_get_mouse_event(svg2code->file_button);
subject_add_observer(rdman_get_ob_factory, subject, file_button_handler, svg2code);
mb_mainloop();

In the last step, we can use the new sugbect API to get rid of the factory.

rdman  =  mb_new("X",":0.0",800,600);
svg2code = rdman_object_load(rdman,rdman->root_coord,"svg2code");
subject = coord_get_mouse_event(svg2code->file_button);
subject_add_observer(coord_get_mouse_event(svg2code->file_button), file_button_handler, svg2code);
mb_mainloop();

In the DOM model, the file_button will be accessed by the DOM API. The coord_get_mouse_event will become rdman_object_get_mouse_event.

rdman  =  mb_new("X",":0.0",800,600);
svg2code = rdman_object_load(rdman,rdman->root_coord,"svg2code");
subject = rdman_get_mouse_event(rdman_object_get_object(svg2code,"file_button"));
subject_add_observer(subject, file_button_handler, svg2code);
mb_mainloop();

In summary, we introduce the following new mechanism into the MadButterfly.

The final code is much ready to be ported to the different backend. We need to change a singe argument only. For example, if we have GTK backend. The above code will become

rdman  =  mb_new("GTK",":0.0",800,600);
svg2code = rdman_object_load(rdman,rdman->root_coord,"svg2code");
subject = rdman_get_mouse_event(rdman_object_get_object(svg2code,"file_button"));
subject_add_observer(subject, file_button_handler, svg2code);
mb_mainloop();

We can even simplify it by make the first argument to be NULL so that the MadButterfly will select a correct backend automatically. In this case, we can use the same executable in different backends.

Handle events

IO events