Window management requires a connection to Screen, configuration of a window, and creation of a window buffer.
The first step is to establish a connection between your window manager and the underlying windowing system, Screen. To set up this connection, you need to create a Screen context.
There are different context types. A standard application would use SCREEN_APPLICATION_CONTEXT. Because you're writing a window manager, you need a context type that lets you modify all the windows in the system. Specifically, you need to use SCREEN_WINDOW_MANAGER_CONTEXT; this context type enables the receipt of events when application windows are created and destroyed and when applications change their window properties.
Note that root permission is required to use the SCREEN_WINDOW_MANAGER_CONTEXT context type.
int rc = 0; screen_context_t screen_ctx; /* connection to Screen */ rc = screen_create_context(&screen_ctx, SCREEN_WINDOW_MANAGER_CONTEXT);
Without a window for your window manager, you can still receive SCREEN_EVENT_CREATE and SCREEN_EVENT_CLOSE window manager events, but you can't receive any input events.
screen_window_t screen_win; /* native handle for our window */ rc = screen_create_window(&screen_win, screen_ctx);
Although many window properties are available, you don't need to set them all because most have defaults that are appropriate. For a window manager, however, you need to set some particular window properties:
int val = 0; val = SCREEN_USAGE_WRITE; rc = screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_USAGE, &val); ... int size[2] = { 64, 64 }; /* size of the window on screen */ rc = screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_SIZE, size); ... int pos[2] = { 0, 0 }; /* position of the window on screen */ rc = screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_POSITION, pos); ... int zorder = 0; rc = screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_ZORDER, &zorder);
You need at least one buffer to hold the contents of your window so that your window will be visible.
In the simplest case, you can fill your window with a solid color so that you can see the window. Before you can do this, you'll need to query some properties of the window buffer.
For the sake of simplicity, you can just fill the window buffer with a solid color pattern. To do this, you can use memset():
screen_buffer_t screen_buf; /* renderable buffer for the window */ rc = screen_create_window_buffers(screen_win, 1); rc = screen_get_window_property_pv(screen_win, SCREEN_PROPERTY_RENDER_BUFFERS, (void **)&screen_buf); rc = screen_get_buffer_property_pv(screen_buf, SCREEN_PROPERTY_POINTER, &pointer); int stride; /* size of each window line in bytes */ memset(pointer, 0x80, stride * size[1]);
To make the content rendered on your window visible, you need to post your changes to Screen. Posting to Screen indicates that you have completed drawing to your render buffer and you wish to have the changes made visible. When you post, you need to specify which area of your buffer has changed so that Screen will redraw only the parts of the framebuffer that need updating. When posting your first frame, you must post the entire buffer.
To ensure that any delayed Screen commands are processed, flush the command queue of your context after you post:
int rect[4] = { 0, 0, size[0], size[1] }; rc = screen_post_window(screen_win, screen_buf, 1, rect, 0); rc = screen_flush_context(screen_ctx, SCREEN_WAIT_IDLE);