The complete code sample for a window screenshot is listed below.
In the following code sample, an hourglass is placed in the top left corner of an application window while a vertical bar sweeps from left to right across the screen. The ground window is of type SCREEN_APPLICATION_WINDOW, while the hourglass and the bar are implemented as windows of type SCREEN_CHILD_WINDOW.
This code sample performs a screenshot of the hourglass window upon a MTOUCH touch event. The screenshot of the hourglass window is written to a designated bitmap on the system.
#include <ctype.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <screen/screen.h>
const char *hg_id_string = "hourglass";
const char *bar_id_string = "bar";
const int barwidth = 32;
screen_window_t screen_bg_win = NULL;
screen_window_t screen_hg_win = NULL;
screen_window_t screen_bar_win = NULL;
/* Create the background window in this example */
screen_window_t create_bg_window(const char *group, int dims[2], screen_context_t screen_ctx)
{
/* Start by creating the context, application window and window group. */
screen_window_t screen_win;
screen_create_window(&screen_win, screen_ctx);
screen_create_window_group(screen_win, group);
/* Set the visibility of this window to FALSE; we want to make all windows
* invisible until all the windows have been created and are ready to be displayed.*/
int vis = 0;
screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_VISIBLE, &vis);
/* Set the color of the background window. */
int color = 0xffffff00;
screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_COLOR, &color);
/* Screen API
* requires all visible windows to have at least one buffer, so
* here we will create the smallest possible buffer since you don't need to use this buffer
* in this example.*/
int rect[4] = { 0, 0, 1, 1 };
screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_BUFFER_SIZE, rect+2);
screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_SOURCE_SIZE, dims);
/* Move the source viewport to outside the bounds of the window buffer to allow the
* windowing system to replace all areas outside of the buffer with the window color.*/
int pos[2] = { -dims[0], -dims[1] };
screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_SOURCE_POSITION, pos);
/* Create and post the window buffer to make this window visible when we are ready. */
screen_buffer_t screen_buf;
screen_create_window_buffers(screen_win, 1);
screen_get_window_property_pv(screen_win, SCREEN_PROPERTY_RENDER_BUFFERS, (void **)&screen_buf);
screen_post_window(screen_win, screen_buf, 1, rect, 0);
return screen_win;
}
/* Create the bar window in this example.*/
void create_bar_window(const char *group, const char *id, int dims[2])
{
/* Start by creating the another context. A separate context for each child window
* emphasizes the steps required on how to deal with child windows created by other processes.*/
screen_context_t screen_ctx;
screen_create_context(&screen_ctx, SCREEN_APPLICATION_CONTEXT);
/* Create a child window. */
screen_window_t screen_win;
screen_create_window_type(&screen_win, screen_ctx, SCREEN_CHILD_WINDOW);
screen_join_window_group(screen_win, group);
screen_set_window_property_cv(screen_win, SCREEN_PROPERTY_ID_STRING, strlen(id), id);
/* Set the visibility to FALSE. */
int vis = 0;
screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_VISIBLE, &vis);
/* Set the color of the bar window. */
int color = 0xff0000ff;
screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_COLOR, &color);
/* Screen API requires all visible windows to have at
* least one buffer, so here we will create the smallest possible buffer
* since you don't need to use this buffer in this example.*/
int rect[4] = { 0, 0, 1, 1 };
screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_BUFFER_SIZE, rect+2);
/* Move the source viewport to outside the bounds of the window buffer to allow the
windowing system to replace all areas outside of the buffer with the window color.*/
int pos[2] = { -rect[2], -rect[3] };
screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_SOURCE_POSITION, pos);
/* Create and post the window buffer to make this window visible when we are ready. */
screen_buffer_t screen_buf;
screen_create_window_buffers(screen_win, 1);
screen_get_window_property_pv(screen_win, SCREEN_PROPERTY_RENDER_BUFFERS, (void **)&screen_buf);
screen_post_window(screen_win, screen_buf, 1, rect, 0);
}
/* Create the hourglass window in this example. */
void create_hg_window(const char *group, const char *id, int dims[2])
{
int i, j;
/* Start by creating the another context. A separate context for each child window
emphasizes the steps required on how to deal with child windows created by other processes.*/
screen_context_t screen_ctx;
screen_create_context(&screen_ctx, SCREEN_APPLICATION_CONTEXT);
/* Create a child window. */
screen_window_t screen_win;
screen_create_window_type(&screen_win, screen_ctx, SCREEN_CHILD_WINDOW);
screen_join_window_group(screen_win, group);
screen_set_window_property_cv(screen_win, SCREEN_PROPERTY_ID_STRING, strlen(id), id);
/* Set the static window property to indicate that the contents of this window buffer
will not change and therefore posting will not be expected.*/
int flag = 1;
screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_STATIC, &flag);
/* Set the visibility to FALSE. */
int vis = 0;
screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_VISIBLE, &vis);
/* Set the pixel format. The hourglass shape will have transparency, so we need
* a pixel format with an alpha channel; here we choose RGBA8888.*/
int format = SCREEN_FORMAT_RGBA8888;
screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_FORMAT, &format);
/* Set usage flag. Usage flag must be set to write in order for us to draw to the
* window buffer. */
int usage = SCREEN_USAGE_WRITE;
screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_USAGE, &usage);
/* Set the transparency mode.
* By default, RGBA8888 formats will have the transparency mode set to
* source over. The windowing system assumes that if an application chooses
* rgba over rgbx, it's because it wants to do some blending. However,
* it is good practice to set the transparency mode. */
int transparency = SCREEN_TRANSPARENCY_SOURCE_OVER;
screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_TRANSPARENCY, &transparency);
/* Set the window buffer size for the hourglass. */
int rect[4] = { 0, 0, 100, 100 };
screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_BUFFER_SIZE, rect+2);
/* Create the window buffer and then get a handle to this buffer. */
screen_buffer_t screen_buf;
screen_create_window_buffers(screen_win, 1);
screen_get_window_property_pv(screen_win, SCREEN_PROPERTY_RENDER_BUFFERS, (void **)&screen_buf);
/* Get the pointer to this buffer in order to fill the hourglass shape. */
char *ptr = NULL;
screen_get_buffer_property_pv(screen_buf, SCREEN_PROPERTY_POINTER, (void **)&ptr);
/* Get the stride (the number of bytes between pixels on different rows) so that we can
* use it to draw the hourglass shape. */
int stride = 0;
screen_get_buffer_property_iv(screen_buf, SCREEN_PROPERTY_STRIDE, &stride);
/* Draw the hourglass shape. */
for (i = 0; i < rect[3]; i++, ptr += stride) {
for (j = 0; j < rect[2]; j++) {
ptr[j*4] = 0xa0;
ptr[j*4+1] = 0xa0;
ptr[j*4+2] = 0xa0;
ptr[j*4+3] = ((j >= i && j <= rect[3]-i) || (j <= i && j >= rect[3]-i)) ? 0xff : 0;
}
}
/* Post the window. */
screen_post_window(screen_win, screen_buf, 1, rect, 0);
}
void write_bitmap_header(int nbytes, int fd, const int size[])
{
char header[54];
/* Set standard bitmap header */
header[0] = 'B';
header[1] = 'M';
header[2] = nbytes & 0xff;
header[3] = (nbytes >> 8) & 0xff;
header[4] = (nbytes >> 16) & 0xff;
header[5] = (nbytes >> 24) & 0xff;
header[6] = 0;
header[7] = 0;
header[8] = 0;
header[9] = 0;
header[10] = 54;
header[11] = 0;
header[12] = 0;
header[13] = 0;
header[14] = 40;
header[15] = 0;
header[16] = 0;
header[17] = 0;
header[18] = size[0] & 0xff;
header[19] = (size[0] >> 8) & 0xff;
header[20] = (size[0] >> 16) & 0xff;
header[21] = (size[0] >> 24) & 0xff;
header[22] = -size[1] & 0xff;
header[23] = (-size[1] >> 8) & 0xff;
header[24] = (-size[1] >> 16) & 0xff;
header[25] = (-size[1] >> 24) & 0xff;
header[26] = 1;
header[27] = 0;
header[28] = 32;
header[29] = 0;
header[30] = 0;
header[31] = 0;
header[32] = 0;
header[33] = 0;
header[34] = 0; /* image size*/
header[35] = 0;
header[36] = 0;
header[37] = 0;
header[38] = 0x9;
header[39] = 0x88;
header[40] = 0;
header[41] = 0;
header[42] = 0x9l;
header[43] = 0x88;
header[44] = 0;
header[45] = 0;
header[46] = 0;
header[47] = 0;
header[48] = 0;
header[49] = 0;
header[50] = 0;
header[51] = 0;
header[52] = 0;
header[53] = 0;
/* Write bitmap header to file */
write(fd, header, sizeof(header));
}
void write_bitmap_file(const int size[], const char* screenshot_ptr, const int screenshot_stride)
{
int nbytes; /* number of bytes of the bimap */
int fd /* file descriptor */
int i; /* iterator to iterate over the screenshot buffer */
char *fname = "/accounts/1000/appdata/com.example.Tutorial_WindowApp."
"testDev_l_WindowApp85f8001_/data/hourglass_window_screenshot.bmp"; /* bitmap filename */
/* Calculate the size of the bitmap */
nbytes = size[0] * size[1] * 4;
/* Open file*/
fd = creat(fname, S_IRUSR | S_IWUSR);
/* Write the standard bitmap header */
write_bitmap_header(nbytes, fd, size);
/* Write screenshot buffer contents to file */
for (i = 0; i < size[1]; i++) {
write(fd, screenshot_ptr + i * screenshot_stride, size[0] * 4);
}
}
/* Take window screenshot. */
void take_window_screenshot(screen_window_t screenshot_win, screen_context_t screenshot_ctx)
{
/* Variables for setting up taking a screenshot. */
screen_pixmap_t screen_pix;
screen_buffer_t screenshot_buf;
char *screenshot_ptr = NULL;
int screenshot_stride = 0;
int usage, format;
int size[2];
/* Create pixmap. */
screen_create_pixmap(&screen_pix, screenshot_ctx);
/* Set Usage Flags. */
usage = SCREEN_USAGE_READ | SCREEN_USAGE_NATIVE;
screen_set_pixmap_property_iv(screen_pix, SCREEN_PROPERTY_USAGE, &usage);
/* Set format. */
format = SCREEN_FORMAT_RGBA8888;
screen_set_pixmap_property_iv(screen_pix, SCREEN_PROPERTY_FORMAT, &format);
/* Set pixmap buffer size */
size[0] = 200;
size[1] = 200;
screen_set_pixmap_property_iv(screen_pix, SCREEN_PROPERTY_BUFFER_SIZE, size);
/* Create pixmap buffer and get handle to the buffer. */
screen_create_pixmap_buffer(screen_pix);
screen_get_pixmap_property_pv(screen_pix, SCREEN_PROPERTY_RENDER_BUFFERS, (void**)&screenshot_buf);
/* Get a pointer to the buffer. */
screen_get_buffer_property_pv(screenshot_buf, SCREEN_PROPERTY_POINTER, (void**)&screenshot_ptr);
/* Get the stride. */
screen_get_buffer_property_iv(screenshot_buf, SCREEN_PROPERTY_STRIDE, &screenshot_stride);
/* Take the window screenshot. */
screen_read_window(screenshot_win, screenshot_buf, 0, NULL ,0);
/* Write the screenshot buffer to a bitmap file*/
write_bitmap_file(size, screenshot_ptr, screenshot_stride);
/* Perform necessary Screen API clean-up. */
screen_destroy_pixmap(screen_pix);
}
int main(int argc, char **argv)
{
int pos[2], size[2];
int vis = 0;
int type;
/* Create the context to set up connection with the windowing system. */
screen_context_t screen_ctx;
screen_create_context(&screen_ctx, SCREEN_APPLICATION_CONTEXT);
/* Specify the dimensions when creating our child windows. */
/* Get all displays available for the context. */
int count = 0;
screen_get_context_property_iv(screen_ctx, SCREEN_PROPERTY_DISPLAY_COUNT, &count);
screen_display_t *screen_disps = calloc(count, sizeof(screen_display_t));
screen_get_context_property_pv(screen_ctx, SCREEN_PROPERTY_DISPLAYS, (void **)screen_disps);
screen_display_t screen_disp = screen_disps[0];
free(screen_disps);
/* Get the size of the display; we will use this as the dimensions for our windows. */
int dims[2] = { 0, 0 };
screen_get_display_property_iv(screen_disp, SCREEN_PROPERTY_SIZE, dims);
/* Construct a unique name for the window group. */
char str[16];
snprintf(str, sizeof(str), "%d", getpid());
/* Create the parent window; in this example the background window is the parent. */
screen_bg_win = create_bg_window(str, dims, screen_ctx);
/* Create the child windows. */
create_bar_window(str, bar_id_string, dims);
create_hg_window(str, hg_id_string, dims);
/* Create a screen event handle to be used to receive events from the windowing system. */
screen_event_t screen_ev;
screen_create_event(&screen_ev);
while (1) {
do {
/* Wait for next event. */
screen_get_event(screen_ctx, screen_ev, vis ? 0 : ~0);
screen_get_event_property_iv(screen_ev, SCREEN_PROPERTY_TYPE, &type);
/* We are interested only in post, close and mtouch events in this example. */
if (type == SCREEN_EVENT_POST) {
/* Get the handle for the window for this post event. */
screen_window_t screen_win;
screen_get_event_property_pv(screen_ev, SCREEN_PROPERTY_WINDOW, (void **)&screen_win);
screen_get_window_property_cv(screen_win, SCREEN_PROPERTY_ID_STRING, sizeof(str), str);
/* Determine which window is posting. */
if (!screen_bar_win && !strcmp(str, bar_id_string)) {
screen_bar_win = screen_win;
} else if (!screen_hg_win && !strcmp(str, hg_id_string)) {
screen_hg_win = screen_win;
}
/* Once the child windows have been created and posted, switch
* all windows to be visible.*/
if (screen_bar_win && screen_hg_win) {
vis = 1;
/* Set the screen size to full screen, except for the hourglass which will be 100x100
* and positioned at 10, 10. */
screen_get_window_property_iv(screen_hg_win, SCREEN_PROPERTY_BUFFER_SIZE, size);
screen_set_window_property_iv(screen_hg_win, SCREEN_PROPERTY_SIZE, size);
pos[0] = pos[1] = 10;
screen_set_window_property_iv(screen_hg_win, SCREEN_PROPERTY_POSITION, pos);
pos[0] = pos[1] = 0;
screen_set_window_property_iv(screen_bar_win, SCREEN_PROPERTY_POSITION, pos);
screen_set_window_property_iv(screen_bg_win, SCREEN_PROPERTY_POSITION, pos);
size[0] = barwidth;
size[1] = dims[1];
screen_set_window_property_iv(screen_bar_win, SCREEN_PROPERTY_SIZE, size);
size[0] = dims[0];
screen_set_window_property_iv(screen_bg_win, SCREEN_PROPERTY_SIZE, size);
int zorder = 0;
screen_set_window_property_iv(screen_bg_win, SCREEN_PROPERTY_ZORDER, &zorder);
zorder++;
screen_set_window_property_iv(screen_bar_win, SCREEN_PROPERTY_ZORDER, &zorder);
zorder++;
screen_set_window_property_iv(screen_hg_win, SCREEN_PROPERTY_ZORDER, &zorder);
/* Set all windows visible. */
screen_set_window_property_iv(screen_bg_win, SCREEN_PROPERTY_VISIBLE, &vis);
screen_set_window_property_iv(screen_hg_win, SCREEN_PROPERTY_VISIBLE, &vis);
screen_set_window_property_iv(screen_bar_win, SCREEN_PROPERTY_VISIBLE, &vis);
screen_flush_context(screen_ctx, SCREEN_WAIT_IDLE);
}
} else if (type == SCREEN_EVENT_CLOSE) {
/* Handle the window that just posted the close event. */
screen_window_t screen_win;
screen_get_event_property_pv(screen_ev, SCREEN_PROPERTY_WINDOW, (void **)&screen_win);
/* Track the window that just closed. */
if (screen_win == screen_bar_win) {
screen_bar_win = NULL;
} else if (screen_win == screen_hg_win) {
screen_hg_win = NULL;
}
/* Destroy the window that just closed, so that resources that
* were allocated locally can be freed. */
screen_destroy_window(screen_win);
/* Update visibility for that window. */
if (!screen_bar_win || !screen_hg_win) {
vis = 0;
}
}else if (type == SCREEN_EVENT_MTOUCH_TOUCH){
/* Handle the mtouch event to take screenshot of hourglass window. */
take_window_screenshot(screen_hg_win, screen_ctx);
}
} while (type != SCREEN_EVENT_NONE);
/* Wrap the position of the bar window back at the origin of the buffer before
* the bar goes off the edge. Also, to prevent the animation from moving the
* bar too fast, we will call screen_flush_context with the appropriate flags.
* This will limit the animation to the refresh rate of the display. */
if (vis) {
if (++pos[0] > dims[0] - barwidth) {
pos[0] = 0;
}
screen_set_window_property_iv(screen_bar_win, SCREEN_PROPERTY_POSITION, pos);
screen_flush_context(screen_ctx, SCREEN_WAIT_IDLE);
}
}
/* Perform necessary cleanup. In this example we will rely on the windowing system
* to release the resources for the bar and hourglass window contexts when the
* process exits. */
screen_destroy_event(screen_ev);
screen_destroy_context(screen_ctx);
return EXIT_SUCCESS;
}