/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Author: Daniel van Vugt */ #define _DEFAULT_SOURCE #define _BSD_SOURCE /* for usleep() */ #include "mir_toolkit/mir_client_library.h" #include #include #include #include #include /* sleep() */ #include #define BYTES_PER_PIXEL(f) ((f) == mir_pixel_format_bgr_888 ? 3 : 4) #define MIN(a, b) ((a) <= (b) ? (a) : (b)) typedef struct { uint8_t r, g, b, a; } Color; static const Color blue = {0, 0, 255, 255}; static const Color white = {255, 255, 255, 255}; static const Color *const foreground = &white; static const Color *const background = &blue; static volatile sig_atomic_t running = 1; static void shutdown(int signum) { if (running) { running = 0; printf("Signal %d received. Good night.\n", signum); } } static void blend(uint32_t *dest, uint32_t src, int alpha_shift) { uint8_t *d = (uint8_t*)dest; uint8_t *s = (uint8_t*)&src; uint32_t src_alpha = (uint32_t)(src >> alpha_shift) & 0xff; uint32_t dest_alpha = 0xff - src_alpha; int i; for (i = 0; i < 4; i++) { d[i] = (uint8_t) ( ( ((uint32_t)d[i] * dest_alpha) + ((uint32_t)s[i] * src_alpha) ) >> 8 /* Close enough, and faster than /255 */ ); } *dest |= (0xff << alpha_shift); /* Restore alpha 1.0 in the destination */ } static void put_pixels(void *where, int count, MirPixelFormat format, const Color *color) { uint32_t pixel = 0; int alpha_shift = -1; int n; /* * We are blending in software, so can pretend that * mir_pixel_format_abgr_8888 == mir_pixel_format_xbgr_8888 * mir_pixel_format_argb_8888 == mir_pixel_format_xrgb_8888 */ switch (format) { case mir_pixel_format_abgr_8888: case mir_pixel_format_xbgr_8888: alpha_shift = 24; pixel = (uint32_t)color->a << 24 | (uint32_t)color->b << 16 | (uint32_t)color->g << 8 | (uint32_t)color->r; break; case mir_pixel_format_argb_8888: case mir_pixel_format_xrgb_8888: alpha_shift = 24; pixel = (uint32_t)color->a << 24 | (uint32_t)color->r << 16 | (uint32_t)color->g << 8 | (uint32_t)color->b; break; case mir_pixel_format_bgr_888: for (n = 0; n < count; n++) { uint8_t *p = (uint8_t*)where + n * 3; p[0] = color->b; p[1] = color->g; p[2] = color->r; } count = 0; break; default: count = 0; break; } if (alpha_shift >= 0 && color->a < 255) { for (n = 0; n < count; n++) blend((uint32_t*)where + n, pixel, alpha_shift); } else { for (n = 0; n < count; n++) ((uint32_t*)where)[n] = pixel; } } static void clear_region(const MirGraphicsRegion *region, const Color *color) { int y; char *row = region->vaddr; for (y = 0; y < region->height; y++) { put_pixels(row, region->width, region->pixel_format, color); row += region->stride; } } static void draw_box(const MirGraphicsRegion *region, int x, int y, int size, const Color *color) { if (x >= 0 && y >= 0 && x+size < region->width && y+size < region->height) { int j; char *row = region->vaddr + (y * region->stride) + (x * BYTES_PER_PIXEL(region->pixel_format)); for (j = 0; j < size; j++) { put_pixels(row, size, region->pixel_format, color); row += region->stride; } } } static void copy_region(const MirGraphicsRegion *dest, const MirGraphicsRegion *src) { int height = MIN(src->height, dest->height); int width = MIN(src->width, dest->width); int y; const char *srcrow = src->vaddr; char *destrow = dest->vaddr; int copy = width * BYTES_PER_PIXEL(dest->pixel_format); for (y = 0; y < height; y++) { memcpy(destrow, srcrow, copy); srcrow += src->stride; destrow += dest->stride; } } static void redraw(MirSurface *surface, const MirGraphicsRegion *canvas) { MirGraphicsRegion backbuffer; mir_surface_get_graphics_region(surface, &backbuffer); clear_region(&backbuffer, background); copy_region(&backbuffer, canvas); mir_surface_swap_buffers_sync(surface); } int main(int argc, char *argv[]) { MirConnection *conn; MirSurface *surf; MirGraphicsRegion canvas; unsigned int f; unsigned int const pf_size = 32; MirPixelFormat formats[pf_size]; unsigned int valid_formats; int sleep_usec = 50000; if (argc > 1) { int rate; if (sscanf(argv[1], "%d", &rate) == 1 && rate > 0) { sleep_usec = 1000000 / rate; } else { fprintf(stderr, "Usage: %s [repeat rate in Hz]\n" "Default repeat rate is %d\n", argv[0], 1000000 / sleep_usec); return 1; } } conn = mir_connect_sync(NULL, argv[0]); if (!mir_connection_is_valid(conn)) { fprintf(stderr, "Could not connect to a display server.\n"); return 1; } mir_connection_get_available_surface_formats(conn, formats, pf_size, &valid_formats); MirPixelFormat pixel_format = mir_pixel_format_invalid; for (f = 0; f < valid_formats; f++) { if (BYTES_PER_PIXEL(formats[f]) == 4) { pixel_format = formats[f]; break; } } if (pixel_format == mir_pixel_format_invalid) { fprintf(stderr, "Could not find a fast 32-bit pixel format\n"); mir_connection_release(conn); return 1; } int width = 500; int height = 500; MirSurfaceSpec *spec = mir_connection_create_spec_for_normal_surface(conn, width, height, pixel_format); if (spec == NULL) { fprintf(stderr, "Could not create a surface spec.\n"); mir_connection_release(conn); return 1; } mir_surface_spec_set_name(spec, "Progress Bars"); mir_surface_spec_set_buffer_usage(spec, mir_buffer_usage_software); surf = mir_surface_create_sync(spec); mir_surface_spec_release(spec); if (surf != NULL) { canvas.width = width; canvas.height = height; canvas.stride = canvas.width * BYTES_PER_PIXEL(pixel_format); canvas.pixel_format = pixel_format; canvas.vaddr = (char*)malloc(canvas.stride * canvas.height); if (canvas.vaddr != NULL) { int t = 0; signal(SIGINT, shutdown); signal(SIGTERM, shutdown); signal(SIGHUP, shutdown); while (running) { static const int box_width = 8; static const int space = 1; const int grid = box_width + 2 * space; const int row = width / grid; const int square = row * row; const int x = (t % row) * grid + space; const int y = (t / row) * grid + space; if (t % square == 0) clear_region(&canvas, background); t = (t + 1) % square; draw_box(&canvas, x, y, box_width, foreground); redraw(surf, &canvas); usleep(sleep_usec); } free(canvas.vaddr); } else { fprintf(stderr, "Failed to malloc canvas\n"); } mir_surface_release_sync(surf); } else { fprintf(stderr, "mir_connection_create_surface_sync failed\n"); } mir_connection_release(conn); return 0; }