diff options
Diffstat (limited to 'extra/windows.c')
-rw-r--r-- | extra/windows.c | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/extra/windows.c b/extra/windows.c new file mode 100644 index 0000000000..fd09af53f5 --- /dev/null +++ b/extra/windows.c @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2014 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include <assert.h> +#include <pthread.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <xcb/xcb.h> + +#include "simulation.h" + +/*****************************************************************************/ +/* Window drawing stuff */ + +/* Dimensions - may change */ +static int win_w = 1024; +static int win_h = 32; + +static xcb_connection_t *c; +static xcb_screen_t *screen; +static xcb_drawable_t win; +static xcb_gcontext_t foreground; +static xcb_colormap_t colormap_id; + +static int lb_power; + +void init_windows(void) +{ + uint32_t mask = 0; + uint32_t values[2]; + + /* Open the connection to the X server */ + c = xcb_connect(NULL, NULL); + + /* Get the first screen */ + screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data; + + /* Get a colormap */ + colormap_id = xcb_generate_id(c); + xcb_create_colormap(c, XCB_COLORMAP_ALLOC_NONE, + colormap_id, screen->root, screen->root_visual); + + /* Create foreground GC */ + foreground = xcb_generate_id(c); + mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES; + values[0] = screen->white_pixel; + values[1] = 0; + xcb_create_gc(c, foreground, screen->root, mask, values); + + /* Create the window */ + win = xcb_generate_id(c); + mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; + values[0] = screen->black_pixel; + values[1] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS; + xcb_create_window(c, /* Connection */ + XCB_COPY_FROM_PARENT, /* depth */ + win, /* window Id */ + screen->root, /* parent window */ + 0, 0, /* x, y */ + win_w, win_h, /* width, height */ + 10, /* border_width */ + XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */ + screen->root_visual, /* visual */ + mask, values); /* masks */ + + /* Map the window on the screen */ + xcb_map_window(c, win); + + /* We flush the request */ + xcb_flush(c); +} + +void cleanup(void) +{ + xcb_destroy_window(c, win); + xcb_free_gc(c, foreground); + xcb_free_colormap(c, colormap_id); + xcb_disconnect(c); +} + +/*****************************************************************************/ +/* Draw the lightbar elements */ + +/* xcb likes 16-bit colors */ +uint16_t leds[NUM_LEDS][3] = { + {0xffff, 0x0000, 0x0000}, + {0x0000, 0xffff, 0x0000}, + {0x0000, 0x0000, 0xffff}, + {0xffff, 0xffff, 0x0000}, +}; +pthread_mutex_t leds_mutex = PTHREAD_MUTEX_INITIALIZER; + +void change_gc_color(uint16_t red, uint16_t green, uint16_t blue) +{ + uint32_t mask = 0; + uint32_t values[2]; + xcb_alloc_color_reply_t *reply; + + reply = xcb_alloc_color_reply(c, + xcb_alloc_color(c, colormap_id, + red, green, blue), + NULL); + assert(reply); + + mask = XCB_GC_FOREGROUND; + values[0] = reply->pixel; + xcb_change_gc(c, foreground, mask, values); + free(reply); +} + +void update_window(void) +{ + xcb_segment_t segments[] = { + {0, 0, win_w, win_h}, + {0, win_h, win_w, 0}, + }; + xcb_rectangle_t rect; + int w = win_w / NUM_LEDS; + int i; + uint16_t copyleds[NUM_LEDS][3]; + + if (lb_power) { + pthread_mutex_lock(&leds_mutex); + memcpy(copyleds, leds, sizeof(leds)); + pthread_mutex_unlock(&leds_mutex); + + for (i = 0; i < NUM_LEDS; i++) { + rect.x = i * w; + rect.y = 0; + rect.width = w; + rect.height = win_h; + + change_gc_color(copyleds[i][0], + copyleds[i][1], + copyleds[i][2]); + + xcb_poly_fill_rectangle(c, win, foreground, 1, &rect); + } + } else { + rect.x = 0; + rect.y = 0; + rect.width = win_w; + rect.height = win_h; + + change_gc_color(0, 0, 0); + xcb_poly_fill_rectangle(c, win, foreground, 1, &rect); + + change_gc_color(0x8080, 0, 0); + + for (i = 0; i < NUM_LEDS; i++) { + segments[0].x1 = i * w; + segments[0].y1 = 0; + segments[0].x2 = segments[0].x1 + w; + segments[0].y2 = win_h; + segments[1].x1 = segments[0].x1; + segments[1].y1 = win_h; + segments[1].x2 = segments[0].x2; + segments[1].y2 = 0; + xcb_poly_segment(c, win, foreground, 2, segments); + } + } + + xcb_flush(c); +} + +void setrgb(int led, int red, int green, int blue) +{ + led %= NUM_LEDS; + + pthread_mutex_lock(&leds_mutex); + leds[led][0] = red << 8 | red; + leds[led][1] = green << 8 | green; + leds[led][2] = blue << 8 | blue; + pthread_mutex_unlock(&leds_mutex); + + update_window(); +} + +/*****************************************************************************/ +/* lb_common stubs */ + + + +/* Brightness serves no purpose here. It's automatic on the Chromebook. */ +static int brightness = 0xc0; +void lb_set_brightness(unsigned int newval) +{ + brightness = newval; +} +uint8_t lb_get_brightness(void) +{ + return brightness; +} + +void lb_set_rgb(unsigned int led, int red, int green, int blue) +{ + int i; + if (led >= NUM_LEDS) + for (i = 0; i < NUM_LEDS; i++) + setrgb(i, red, green, blue); + else + setrgb(led, red, green, blue); +} + +int lb_get_rgb(unsigned int led, uint8_t *red, uint8_t *green, uint8_t *blue) +{ + led %= NUM_LEDS; + pthread_mutex_lock(&leds_mutex); + *red = leds[led][0]; + *green = leds[led][1]; + *blue = leds[led][2]; + pthread_mutex_unlock(&leds_mutex); + return 0; +} + +void lb_init(void) +{ + if (lb_power) + lb_set_rgb(NUM_LEDS, 0, 0, 0); +}; +void lb_off(void) +{ + lb_power = 0; + update_window(); +}; +void lb_on(void) +{ + lb_power = 1; + update_window(); +}; +void lb_start_builtin_cycle(void) { }; +void lb_hc_cmd_dump(struct ec_response_lightbar *out) +{ + printf("lightbar is %s\n", lb_power ? "on" : "off"); + memset(out, lb_power, sizeof(*out)); +}; +void lb_hc_cmd_reg(const struct ec_params_lightbar *in) { }; + + +/*****************************************************************************/ +/* Event handling stuff */ + +void *entry_windows(void *ptr) +{ + xcb_generic_event_t *e; + xcb_expose_event_t *ev; + xcb_button_press_event_t *bv; + int chg = 1; + + while ((e = xcb_wait_for_event(c))) { + + switch (e->response_type & ~0x80) { + case XCB_EXPOSE: + ev = (xcb_expose_event_t *)e; + if (win_w != ev->width || win_h != ev->height) { + win_w = ev->width; + win_h = ev->height; + } + update_window(); + break; + case XCB_BUTTON_PRESS: + bv = (xcb_button_press_event_t *)e; + switch (bv->detail) { + case 1: + demo_battery_level(-1); + break; + case 3: + demo_battery_level(+1); + break; + case 2: + chg = !chg; + demo_is_charging(chg); + break; + } + break; + } + + free(e); + } + + cleanup(); + exit(0); + return 0; +} |