Complete sample: a window screenshot example

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 background 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 <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 and Windowing 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 and Windowing
	 * 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 and Windowing 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;
}