Complete sample: Using multiple displays

The complete code sample is listed below.

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <screen/screen.h>

const int barwidth = 32;

int ndisplays = 0;

struct {
	pthread_mutex_t mutex;
	pthread_cond_t cond;
	enum { detached, attached, focused } state;
} *displays;

screen_pixmap_t screen_pix = NULL;

screen_buffer_t screen_pbuf = NULL;

void pixmap(screen_context_t screen_ctx)
{
	int i, j;

	screen_create_pixmap(&screen_pix, screen_ctx);

	int format = SCREEN_FORMAT_RGBA8888;
	screen_set_pixmap_property_iv(screen_pix, SCREEN_PROPERTY_FORMAT, &format);

	int usage = SCREEN_USAGE_WRITE | SCREEN_USAGE_NATIVE;
	screen_set_pixmap_property_iv(screen_pix, SCREEN_PROPERTY_USAGE, &usage);

	int size[2] = { 100, 100 };
	screen_set_pixmap_property_iv(screen_pix, SCREEN_PROPERTY_BUFFER_SIZE, size);

	screen_create_pixmap_buffer(screen_pix);
	screen_get_pixmap_property_pv(screen_pix, SCREEN_PROPERTY_RENDER_BUFFERS, (void **)&screen_pbuf);

	unsigned char *ptr = NULL;
	screen_get_buffer_property_pv(screen_pbuf, SCREEN_PROPERTY_POINTER, (void **)&ptr);

	int stride = 0;
	screen_get_buffer_property_iv(screen_pbuf, SCREEN_PROPERTY_STRIDE, &stride);

	for (i = 0; i < size[1]; i++, ptr += stride) {
		for (j = 0; j < size[0]; j++) {
			ptr[j*4] = 0xa0;
			ptr[j*4+1] = 0xa0;
			ptr[j*4+2] = 0xa0;
			ptr[j*4+3] = ((j >= i && j <= size[1]-i) || (j <= i && j >= size[1]-i)) ? 0xff : 0;
		}
	}
}

void *display(void *arg)
{
	const int idx = (int)arg;
	int rect[4] = { 0, 0 };
	int realized = 0;
	int pos = 0;
	int attached;
	int focus;
	int i;

	screen_context_t screen_ctx;
	screen_create_context(&screen_ctx, SCREEN_APPLICATION_CONTEXT);

	screen_display_t *screen_dpy = calloc(ndisplays, sizeof(screen_display_t));
	screen_get_context_property_pv(screen_ctx, SCREEN_PROPERTY_DISPLAYS, (void **)screen_dpy);

	screen_window_t screen_win;
	screen_create_window(&screen_win, screen_ctx);
	screen_set_window_property_pv(screen_win, SCREEN_PROPERTY_DISPLAY, (void **)&screen_dpy[idx]);

	int usage = SCREEN_USAGE_NATIVE;
	screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_USAGE, &usage);

	pthread_mutex_lock(&displays[idx].mutex);
	attached = displays[idx].state != detached ? 1 : 0;
	focus = displays[idx].state == focused ? 1 : 0;
	pthread_mutex_unlock(&displays[idx].mutex);

	screen_event_t screen_ev;
	screen_create_event(&screen_ev);

	while (1) {
		if (attached) {
			if (!realized) {
				screen_get_display_property_iv(screen_dpy[idx], SCREEN_PROPERTY_SIZE, rect+2);
				screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_BUFFER_SIZE, rect+2);
				screen_create_window_buffers(screen_win, 2);
				realized = 1;
			}

			screen_buffer_t screen_buf[2];
			screen_get_window_property_pv(screen_win, SCREEN_PROPERTY_RENDER_BUFFERS, (void **)screen_buf);

			int bg[] = { SCREEN_BLIT_COLOR, 0xffffff00, SCREEN_BLIT_END };
			screen_fill(screen_ctx, screen_buf[0], bg);

			if (focus > 0) {
				int bar[] = {
					SCREEN_BLIT_COLOR, 0xff0000ff,
					SCREEN_BLIT_DESTINATION_X, pos,
					SCREEN_BLIT_DESTINATION_WIDTH, barwidth,
					SCREEN_BLIT_END };

				screen_fill(screen_ctx, screen_buf[0], bar);

				if (++pos > rect[2] - barwidth) {
					for (i = (idx+1) % ndisplays; i != idx; i = (i+1) % ndisplays) {
						pthread_mutex_lock(&displays[i].mutex);
						if (displays[i].state == attached) {
							displays[i].state = focused;
							pthread_cond_signal(&displays[i].cond);
							pthread_mutex_unlock(&displays[i].mutex);
							break;
						}
						pthread_mutex_unlock(&displays[i].mutex);
					}
					if (i != idx) {
						pthread_mutex_lock(&displays[idx].mutex);
						displays[idx].state = attached;
						pthread_mutex_unlock(&displays[idx].mutex);
						focus = -1;
					}
					pos = 0;
				}
			} else {
				focus = 0;
			}

			int hg[] = {
				SCREEN_BLIT_SOURCE_WIDTH, 100,
				SCREEN_BLIT_SOURCE_HEIGHT, 100,
				SCREEN_BLIT_DESTINATION_X, 10,
				SCREEN_BLIT_DESTINATION_Y, 10,
				SCREEN_BLIT_DESTINATION_WIDTH, 100,
				SCREEN_BLIT_DESTINATION_HEIGHT, 100,
				SCREEN_BLIT_TRANSPARENCY, SCREEN_TRANSPARENCY_SOURCE_OVER,
				SCREEN_BLIT_END
			};

			screen_blit(screen_ctx, screen_buf[0], screen_pbuf, hg);
			screen_post_window(screen_win, screen_buf[0], 1, rect, 0);
		}

		if (!attached && realized) {
			screen_destroy_window_buffers(screen_win);
			screen_flush_context(screen_ctx, 0);
			realized = 0;
		}

		if (focus != -1) {
			pthread_mutex_lock(&displays[idx].mutex);
			if (!focus) {
				printf("%s[%d]: idx=%d\n", __FUNCTION__, __LINE__, idx);
				pthread_cond_wait(&displays[idx].cond, &displays[idx].mutex);
				pos = 0;
			}
			attached = displays[idx].state != detached ? 1 : 0;
			focus = displays[idx].state == focused ? 1 : 0;
			pthread_mutex_unlock(&displays[idx].mutex);
		}
	}

	free(screen_dpy);

	return NULL;
}

int main(int argc, char **argv)
{
	int i, j, idx = -1;

	screen_context_t screen_ctx;
	screen_create_context(&screen_ctx, SCREEN_APPLICATION_CONTEXT);
	screen_get_context_property_iv(screen_ctx, SCREEN_PROPERTY_DISPLAY_COUNT, &ndisplays);

	pixmap(screen_ctx);

	screen_display_t *screen_dpy = calloc(ndisplays, sizeof(screen_display_t));
	screen_get_context_property_pv(screen_ctx, SCREEN_PROPERTY_DISPLAYS, (void **)screen_dpy);

	displays = calloc(ndisplays, sizeof(*displays));
	for (i = 0; i < ndisplays; i++) {
		int active = 0;
		screen_get_display_property_iv(screen_dpy[i], SCREEN_PROPERTY_ATTACHED, &active);
		if (active) {
			if (idx == -1) {
				displays[i].state = focused;
				idx = i;
			} else {
				displays[i].state = attached;
			}
		} else {
			displays[i].state = detached;
		}

		pthread_mutex_init(&displays[i].mutex, NULL);
		pthread_cond_init(&displays[i].cond, NULL);

		pthread_t thread;
		pthread_create(&thread, NULL, display, (void *)i);
	}

	screen_event_t screen_ev;
	screen_create_event(&screen_ev);

	while (1) {
		int type = SCREEN_EVENT_NONE;
		screen_get_event(screen_ctx, screen_ev, ~0);
		screen_get_event_property_iv(screen_ev, SCREEN_PROPERTY_TYPE, &type);
		if (type == SCREEN_EVENT_DISPLAY) {
			screen_display_t tmp = NULL;
			screen_get_event_property_pv(screen_ev, SCREEN_PROPERTY_DISPLAY, (void **)&tmp);
			for (i = 0; i < ndisplays; i++) {
				if (tmp == screen_dpy[i]) {
					int active = 0;
					screen_get_event_property_iv(screen_ev, SCREEN_PROPERTY_ATTACHED, &active);

					if (active) {
						int size[2];
						screen_get_display_property_iv(tmp, SCREEN_PROPERTY_SIZE, size);
						if (size[0] == 0 || size[1] == 0) {
							active = 0;
						}
					}

					pthread_mutex_lock(&displays[i].mutex);
					if ((active && displays[i].state == detached) ||
						(!active && displays[i].state != detached)) {
						if (active) {
							for (j = 0; j < ndisplays; j++) {
								printf("%s[%d]: j=%d\n", __FUNCTION__, __LINE__, j);
								if (i != j) {
									pthread_mutex_lock(&displays[j].mutex);
									if (displays[j].state == focused) {
										displays[i].state = attached;
										pthread_mutex_unlock(&displays[j].mutex);
										break;
									}
									pthread_mutex_unlock(&displays[j].mutex);
								}
							}
							if (displays[i].state == detached) {
								displays[i].state = focused;
							}
						} else {
							if (displays[i].state == focused) {
								for (j = (i+1) % ndisplays; j != i; j = (j+1) % ndisplays) {
									printf("%s[%d]: j=%d\n", __FUNCTION__, __LINE__, j);
									pthread_mutex_lock(&displays[j].mutex);
									if (displays[j].state == attached) {
										displays[j].state = focused;
										pthread_cond_signal(&displays[j].cond);
										pthread_mutex_unlock(&displays[j].mutex);
										break;
									}
									pthread_mutex_unlock(&displays[j].mutex);
								}
							}
							displays[i].state = detached;
						}
						pthread_cond_signal(&displays[i].cond);
					}
					pthread_mutex_unlock(&displays[i].mutex);

					break;
				}
			}
		}
	}

	screen_destroy_pixmap(screen_pix);
	screen_destroy_event(screen_ev);
	screen_destroy_context(screen_ctx);

	free(displays);

	return EXIT_SUCCESS;
}