/* * 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 #include #include #include #include #include #include #include #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 fake_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 (fake_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 (fake_power) lb_set_rgb(NUM_LEDS, 0, 0, 0); }; void lb_off(void) { fake_power = 0; update_window(); }; void lb_on(void) { fake_power = 1; update_window(); }; void lb_hc_cmd_dump(struct ec_response_lightbar *out) { printf("lightbar is %s\n", fake_power ? "on" : "off"); memset(out, fake_power, sizeof(*out)); }; void lb_hc_cmd_reg(const struct ec_params_lightbar *in) { }; int lb_power(int enabled) { return fake_power; } /*****************************************************************************/ /* 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; }