Window management requires a connection to Screen.
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. But since you're writing a window manager, you need a context type that will let you modify all the windows in the system. You need to use the 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 windowing system */ rc = screen_create_context(&screen_ctx, SCREEN_WINDOW_MANAGER_CONTEXT);
Without a window for your window manager, you can receive window manager events such as SCREEN_EVENT_CREATE and SCREEN_EVENT_CLOSE. However, you won't be able to receive any input events.
screen_window_t screen_win; /* native handle for our window */ rc = screen_create_window(&screen_win, screen_ctx);
Many window properties are available, but you don't need to set them all because most have defaults that are already appropriate. But for a window manager, there are some particular window properties that you'll need to set:
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 a plain 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 you render 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 the area of your buffer that has changed so that Screen will redraw only the parts of the framebuffer that need updating. When you're posting your first frame, you'll want to 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);