I'm not. The others are.(by sheer coincidence my next project is to put the finishing touches on an OS wrapper, similar I imagine to what average software is doing, so I too was curious as to what he had done).
I'm not writing an OS wrapper, as least not in the sense of libraries like SDL.
My programs consist of a back-end and several front-ends. The back-end is completely OS independent, and constitutes the vast bulk of the code (95%+). The front-ends are specific to each OS. The program entry point is in the front-end, and I provide a C interface between the two layers. For example, this is the interface my back-end uses to communicate with the front-ends:
package Front_End is
pragma Preelaborate;
-- Flip the OpenGL buffers.
procedure Swap_Buffer;
-- Confirm the ability to use vertical sync.
function VSync_Available return Integer;
-- Enable/disable vertical sync.
procedure Enable_VSync;
procedure Disable_VSync;
-- Bailout procedure.
procedure Die;
-- Display an error message.
procedure Error_Box(Message: in chars_ptr);
-- Retrieve the path to the user's data directory.
function Data_Path return String;
-- Enable and disable key repeat for typing.
procedure Enable_Typing;
procedure Disable_Typing;
private
pragma Import(C, Swap_Buffer, "front_end_swap_buffer");
pragma Import(C, VSync_Available, "front_end_vsync_available");
pragma Import(C, Enable_VSync, "front_end_enable_vsync");
pragma Import(C, Disable_VSync, "front_end_disable_vsync");
pragma Import(C, Die, "front_end_die");
pragma Import(C, Error_Box, "front_end_error_box");
pragma Import(C, Enable_Typing, "front_end_enable_typing");
pragma Import(C, Disable_Typing, "front_end_disable_typing");
end Front_End;
Each of my front-ends implement all of these functions, providing the OS-specific services that the back end needs.
Here's an example of what this looks like in each front-end:
Linux:
extern "C"
void front_end_swap_buffer()
try
{
// Wait for vertical sync, if enabled.
if (data->vsync_on)
{
unsigned retrace;
data->wait_video_sync(1, 0, &retrace);
}
// Flip the buffer.
gdk_gl_drawable_swap_buffers(data->drawable);
}
catch (...)
{
cerr << "Fatal front end interface error in front_end_swap_buffer" << endl;
exit(EXIT_FAILURE);
}
Mac:
void front_end_swap_buffer(void)
{
@try
{
[instance.current_context updateFrame];
}
@catch (NSException *error)
{
front_end_error_box([[error reason] UTF8String]);
[NSApp terminate:instance];
}
}
Windows:
extern "C"
void front_end_swap_buffer()
try
{
SwapBuffers(data->context);
}
catch (...)
{
cerr << "Fatal front end interface error in front_end_swap_buffers" << endl;
exit(EXIT_FAILURE);
}
The front-ends talk to the back-end through this interface:
#ifndef BACK_END_H
#define BACK_END_H
#ifdef __cplusplus
extern "C"
{
#endif
// One-time back end initialization.
void back_end_initialize(void);
// Run the main loop once. Returns 0 on failure.
int back_end_main_loop(void);
// Pass a key event to the back end.
void back_end_key_down(int key);
void back_end_key_up(int key);
void back_end_key_typed(char key);
// Refresh the main view.
void back_end_draw(void);
// Reset the time delta, usually after a front end delay.
void back_end_reset_delta(void);
// Halt all processing, due to loss of focus or something.
void back_end_freeze(void);
// Close down all back end operations.
void back_end_shutdown(void);
#ifdef __cplusplus
}
#endif
#endif
Hopefully that makes it more clear, all the code is available on my website, for further inspection.