static PyObject * _cairo_create(PyObject *self, PyObject *args) { xcb_connection_t *connection; xcb_visualtype_t *visual; xcb_window_t window; cairo_surface_t * surface; cairo_t * cairo; int width, height; if (!PyArg_ParseTuple(args, "lIlii", &connection, &window, &visual, &width, &height)) return NULL; surface = cairo_xcb_surface_create(connection, window, visual, width, height); cairo = cairo_create(surface); cairo_set_antialias(cairo, CAIRO_ANTIALIAS_NONE); cairo_surface_destroy(surface); return Py_BuildValue("l", cairo); }
static EventdNdSurface * _eventd_nd_xcb_surface_new(EventdNdBackendContext *context, EventdNdNotification *notification, gint width, gint height) { guint32 selmask = XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP; guint32 selval[] = { 0, 0, 1, XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE, context->map }; EventdNdSurface *self; self = g_new0(EventdNdSurface, 1); self->notification = notification; self->context = context; self->width = width; self->height = height; self->window = xcb_generate_id(context->xcb_connection); xcb_create_window(context->xcb_connection, context->depth->depth, /* depth */ self->window, context->screen->root, /* parent window */ 0, 0, /* x, y */ width, height, /* width, height */ 0, /* border_width */ XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */ context->visual->visual_id, /* visual */ selmask, selval); /* masks */ self->surface = cairo_xcb_surface_create(self->context->xcb_connection, self->window, self->context->visual, self->width, self->height); g_hash_table_insert(context->bubbles, GUINT_TO_POINTER(self->window), self); _eventd_nd_xcb_surface_shape(self); return self; }
static void drawin_update_drawing(drawin_t *w) { /* If this drawin isn't visible, we don't need an up-to-date cairo surface * for it. (drawin_map() will later make sure we are called again) */ if(!w->visible) return; /* Clean up old stuff */ if(w->surface) { /* In case lua still got a reference to the surface, it still won't be * able to do anything with it because we finish it. */ cairo_surface_finish(w->surface); cairo_surface_destroy(w->surface); } if(w->pixmap) xcb_free_pixmap(globalconf.connection, w->pixmap); /* Create a pixmap */ xcb_screen_t *s = globalconf.screen; w->pixmap = xcb_generate_id(globalconf.connection); xcb_create_pixmap(globalconf.connection, globalconf.default_depth, w->pixmap, s->root, w->geometry.width, w->geometry.height); /* and create a surface for that pixmap */ w->surface = cairo_xcb_surface_create(globalconf.connection, w->pixmap, globalconf.visual, w->geometry.width, w->geometry.height); /* Make sure the pixmap doesn't contain garbage by filling it with black */ cairo_t *cr = cairo_create(w->surface); cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); cairo_paint(cr); cairo_destroy(cr); }
/** Create a new Pango font. * \param fontname Pango fontname (e.g. [FAMILY-LIST] [STYLE-OPTIONS] [SIZE]). * \return A new font. */ font_t * draw_font_new(const char *fontname) { cairo_surface_t *surface; xcb_screen_t *s = xutil_screen_get(globalconf.connection, globalconf.default_screen); cairo_t *cr; PangoLayout *layout; font_t *font = p_new(font_t, 1); /* Create a dummy cairo surface, cairo context and pango layout in * order to get font informations */ surface = cairo_xcb_surface_create(globalconf.connection, globalconf.default_screen, globalconf.screens.tab[0].visual, s->width_in_pixels, s->height_in_pixels); cr = cairo_create(surface); layout = pango_cairo_create_layout(cr); /* Get the font description used to set text on a PangoLayout */ font->desc = pango_font_description_from_string(fontname); pango_layout_set_font_description(layout, font->desc); /* Get height */ pango_layout_get_pixel_size(layout, NULL, &font->height); g_object_unref(layout); cairo_destroy(cr); cairo_surface_destroy(surface); return font; }
void drawable_set_geometry(lua_State *L, int didx, area_t geom) { drawable_t *d = luaA_checkudata(L, didx, &drawable_class); area_t old = d->geometry; d->geometry = geom; bool size_changed = (old.width != geom.width) || (old.height != geom.height); if (size_changed) drawable_unset_surface(d); if (size_changed && geom.width > 0 && geom.height > 0) { d->pixmap = xcb_generate_id(globalconf.connection); xcb_create_pixmap(globalconf.connection, globalconf.default_depth, d->pixmap, globalconf.screen->root, geom.width, geom.height); d->surface = cairo_xcb_surface_create(globalconf.connection, d->pixmap, globalconf.visual, geom.width, geom.height); luaA_object_emit_signal(L, didx, "property::surface", 0); } if (old.x != geom.x) luaA_object_emit_signal(L, didx, "property::x", 0); if (old.y != geom.y) luaA_object_emit_signal(L, didx, "property::y", 0); if (old.width != geom.width) luaA_object_emit_signal(L, didx, "property::width", 0); if (old.height != geom.height) luaA_object_emit_signal(L, didx, "property::height", 0); }
/* font_new - create a new font {{{ * * \return a new font_t struct */ font_t * font_new(const char *font_name) { xcb_screen_t *s = screen_get(rootconf.connection, rootconf.screen_default); cairo_surface_t *surface; cairo_t *cr; PangoLayout *layout; font_t *font; font = malloc(sizeof(font_t)); /* Create a cairo surface */ surface = cairo_xcb_surface_create(rootconf.connection, rootconf.screen_default, visual_get_from_screen(s), s->width_in_pixels, s->height_in_pixels); cr = cairo_create(surface); /* Pango layout */ layout = pango_cairo_create_layout(cr); /* Get the font descriptionription used to set text on a PangoLayout */ font->description = pango_font_description_from_string(font_name); pango_layout_set_font_description(layout, font->description); /* Get height */ pango_layout_get_pixel_size(layout, NULL, &font->height); g_object_unref(layout); cairo_destroy(cr); cairo_surface_destroy(surface); return font; } /* }}} */
void Titlebar::draw() { // fill the background cairo_surface_t *surface = cairo_xcb_surface_create(Screen::conn(), id(), Screen::visual(), width(), height()); cairo_t *cr = cairo_create(surface); cairo_rectangle(cr, 0, 0, width(), height()); cairo_set_source_rgb(cr, 0.9, 0.9, 0.9); cairo_fill(cr); cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); cairo_set_line_width(cr, 1.0); cairo_move_to(cr, 0.0, height()); cairo_line_to(cr, width(), height()); cairo_stroke(cr); // draw the text // nice couple pixel padding between the text and the edge cairo_move_to(cr, 2, 2); PangoLayout *layout = pango_cairo_create_layout(cr); pango_layout_set_text(layout, _text.c_str(), _text.size()); PangoFontDescription *font_description = pango_font_description_from_string(CLIENT_TITLEBAR_FONT); pango_layout_set_font_description(layout, font_description); pango_font_description_free(font_description); cairo_set_source_rgb(cr, 0.1, 0.1, 0.1); pango_cairo_show_layout(cr, layout); g_object_unref(layout); cairo_destroy(cr); cairo_surface_destroy(surface); xcb_flush(Screen::conn()); }
/* * Draws global image with fill color onto a pixmap with the given * resolution and returns it. */ xcb_pixmap_t draw_image(uint32_t *resolution) { xcb_pixmap_t bg_pixmap = XCB_NONE; int button_diameter_physical = ceil(scaling_factor() * BUTTON_DIAMETER); DEBUG("scaling_factor is %.f, physical diameter is %d px\n", scaling_factor(), button_diameter_physical); if (!vistype) vistype = get_root_visual_type(screen); bg_pixmap = create_bg_pixmap(conn, screen, resolution, color); /* * Initialize cairo: Create one in-memory surface to render the unlock * indicator on, create one XCB surface to actually draw (one or more, * depending on the amount of screens) unlock indicators on. */ cairo_surface_t *output = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, button_diameter_physical, button_diameter_physical); cairo_t *ctx = cairo_create(output); cairo_surface_t *xcb_output = cairo_xcb_surface_create(conn, bg_pixmap, vistype, resolution[0], resolution[1]); cairo_t *xcb_ctx = cairo_create(xcb_output); /* Creates color array from command line arguments */ uint32_t * color_array(char* colorarg) { uint32_t *rgb16 = malloc(sizeof(uint32_t)*3); char strgroups[3][3] = {{colorarg[0], colorarg[1], '\0'}, {colorarg[2], colorarg[3], '\0'}, {colorarg[4], colorarg[5], '\0'}}; for (int i=0; i < 3; i++) { rgb16[i] = strtol(strgroups[i], NULL, 16); } return rgb16; }
static void towel_window_init_cairo(towel_window_t *win) { xcb_visualtype_t *vt; xcb_get_geometry_cookie_t cookie = xcb_get_geometry_unchecked(win->conn, win->id); xcb_get_geometry_reply_t *geo = xcb_get_geometry_reply(win->conn, cookie, NULL); vt = xcb_aux_find_visual_by_id(win->screen, win->screen->root_visual); win->cs = cairo_xcb_surface_create(win->conn, win->id, vt, geo->width, geo->height); win->cr = cairo_create(win->cs); free(geo); }
/* * Initialize the surface to represent the given drawable. * */ void draw_util_surface_init(xcb_connection_t *conn, surface_t *surface, xcb_drawable_t drawable, xcb_visualtype_t *visual, int width, int height) { surface->id = drawable; surface->visual_type = ((visual == NULL) ? visual_type : visual); surface->width = width; surface->height = height; surface->gc = xcb_generate_id(conn); xcb_void_cookie_t gc_cookie = xcb_create_gc_checked(conn, surface->gc, surface->id, 0, NULL); xcb_generic_error_t *error = xcb_request_check(conn, gc_cookie); if (error != NULL) { ELOG("Could not create graphical context. Error code: %d. Please report this bug.\n", error->error_code); } surface->surface = cairo_xcb_surface_create(conn, surface->id, surface->visual_type, width, height); surface->cr = cairo_create(surface->surface); }
void lock_screen_input(xcb_connection_t * c, xcb_screen_t * s, xcb_window_t w, const int len) { // cached visual_type if (!visual_type) visual_type = get_root_visualitype(s); cairo_surface_t * xcb_cs = cairo_xcb_surface_create(c, w, visual_type, s->width_in_pixels, s->height_in_pixels); cairo_t * xcb_cc = cairo_create(xcb_cs); cairo_set_source_uint32(xcb_cc, len? COLOR_INPUT: COLOR_LOCK); cairo_rectangle(xcb_cc, 0, 0, s->width_in_pixels, s->height_in_pixels); cairo_fill(xcb_cc); if (len) draw_input_box(xcb_cc, s->width_in_pixels, s->height_in_pixels, COLOR_INPUT_FG, COLOR_INPUT, TEXT_SIZE / 5, len); cairo_surface_destroy(xcb_cs); cairo_destroy(xcb_cc); }
void shutdown_init() { xcb_void_cookie_t void_cookie; shutdown_win.surface=NULL; shutdown_win.window = xcb_generate_id(conn); uint32_t values[1] = {XCB_EVENT_MASK_EXPOSURE|XCB_EVENT_MASK_BUTTON_RELEASE}; void_cookie=xcb_create_window_checked (conn,XCB_COPY_FROM_PARENT,shutdown_win.window,scr->root,0,height-1,width,1,0,XCB_WINDOW_CLASS_INPUT_OUTPUT,scr->root_visual,XCB_CW_EVENT_MASK,values); xcb_flush(conn); if (xcb_request_check(conn,void_cookie)) { printf("Can't create the shutdown window\n"); shutdown_win.window = 0; } else { uint32_t v[4]; uint32_t value_mask; value_mask=XCB_CONFIG_WINDOW_X|XCB_CONFIG_WINDOW_Y|XCB_CONFIG_WINDOW_WIDTH|XCB_CONFIG_WINDOW_HEIGHT; v[0]=width/4;; v[1]=height/4; v[2]=width/2; v[3]=height/2; shutdown_win.width=v[2]; shutdown_win.height=v[3]; xcb_configure_window(conn,shutdown_win.window,value_mask,v); xcb_change_property(conn,XCB_PROP_MODE_REPLACE,shutdown_win.window,atoms[TWM_ATOM__NET_WM_NAME],XCB_ATOM_STRING,8,strlen(TWM_NAME),TWM_NAME); xcb_change_property(conn,XCB_PROP_MODE_REPLACE,shutdown_win.window,atoms[TWM_ATOM__NET_WM_WINDOW_TYPE],XCB_ATOM_ATOM,32,1,&atoms[TWM_ATOM__NET_WM_WINDOW_TYPE_DOCK]); shutdown_win.cache=wincache_fill_element(shutdown_win.window); shutdown_win.cache->mapped=0; xcb_flush(conn); shutdown_win.surface=cairo_xcb_surface_create(conn,shutdown_win.window,visual_type,width/2,height/2); cairo_xcb_surface_set_size(shutdown_win.surface,v[2],v[3]); xcb_flush(conn); } }
void lock_screen_error(xcb_connection_t * c, xcb_screen_t * s, xcb_window_t w) { // cached visual_type if (!visual_type) visual_type = get_root_visualitype(s); cairo_surface_t * xcb_cs = cairo_xcb_surface_create(c, w, visual_type, s->width_in_pixels, s->height_in_pixels); cairo_t * xcb_cc = cairo_create(xcb_cs); // draw a red background cairo_set_source_uint32(xcb_cc, COLOR_WRONG); cairo_rectangle(xcb_cc, 0, 0, s->width_in_pixels, s->height_in_pixels); cairo_fill(xcb_cc); draw_stripes(xcb_cc, s->width_in_pixels, s->height_in_pixels, COLOR_WRONG_FG, COLOR_WRONG, STRIPE_WIDTH, "ACESS DENIED"); // reset pass_wrong timer wtimer_rearm(pass_wrong_timer, 0, NULL); cairo_surface_destroy(xcb_cs); cairo_destroy(xcb_cc); }
/* * Draws global image with fill color onto a pixmap with the given * resolution and returns it. * */ xcb_pixmap_t draw_image(uint32_t *resolution) { xcb_pixmap_t bg_pixmap = XCB_NONE; int button_diameter_physical = ceil(scaling_factor() * BUTTON_DIAMETER); DEBUG("scaling_factor is %.f, physical diameter is %d px\n", scaling_factor(), button_diameter_physical); if (!vistype) vistype = get_root_visual_type(screen); bg_pixmap = create_bg_pixmap(conn, screen, resolution, color); /* Initialize cairo: Create one in-memory surface to render the unlock * indicator on, create one XCB surface to actually draw (one or more, * depending on the amount of screens) unlock indicators on. */ cairo_surface_t *output = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, button_diameter_physical, button_diameter_physical); cairo_t *ctx = cairo_create(output); cairo_surface_t *xcb_output = cairo_xcb_surface_create(conn, bg_pixmap, vistype, resolution[0], resolution[1]); cairo_t *xcb_ctx = cairo_create(xcb_output); if (img) { if (!tile) { cairo_set_source_surface(xcb_ctx, img, 0, 0); cairo_paint(xcb_ctx); } else { /* create a pattern and fill a rectangle as big as the screen */ cairo_pattern_t *pattern; pattern = cairo_pattern_create_for_surface(img); cairo_set_source(xcb_ctx, pattern); cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); cairo_rectangle(xcb_ctx, 0, 0, resolution[0], resolution[1]); cairo_fill(xcb_ctx); cairo_pattern_destroy(pattern); } } else { char strgroups[3][3] = {{color[0], color[1], '\0'}, {color[2], color[3], '\0'}, {color[4], color[5], '\0'}}; uint32_t rgb16[3] = {(strtol(strgroups[0], NULL, 16)), (strtol(strgroups[1], NULL, 16)), (strtol(strgroups[2], NULL, 16))}; cairo_set_source_rgb(xcb_ctx, rgb16[0] / 255.0, rgb16[1] / 255.0, rgb16[2] / 255.0); cairo_rectangle(xcb_ctx, 0, 0, resolution[0], resolution[1]); cairo_fill(xcb_ctx); } if (unlock_indicator && (unlock_state >= STATE_KEY_PRESSED || auth_state > STATE_AUTH_IDLE)) { cairo_scale(ctx, scaling_factor(), scaling_factor()); /* Draw a (centered) circle with transparent background. */ cairo_set_line_width(ctx, 10.0); cairo_arc(ctx, BUTTON_CENTER /* x */, BUTTON_CENTER /* y */, BUTTON_RADIUS /* radius */, 0 /* start */, 2 * M_PI /* end */); /* Use the appropriate color for the different PAM states * (currently verifying, wrong password, or default) */ switch (auth_state) { case STATE_AUTH_VERIFY: case STATE_AUTH_LOCK: cairo_set_source_rgba(ctx, 0, 114.0 / 255, 255.0 / 255, 0.75); break; case STATE_AUTH_WRONG: case STATE_I3LOCK_LOCK_FAILED: cairo_set_source_rgba(ctx, 250.0 / 255, 0, 0, 0.75); break; default: cairo_set_source_rgba(ctx, 0, 0, 0, 0.75); break; } cairo_fill_preserve(ctx); switch (auth_state) { case STATE_AUTH_VERIFY: case STATE_AUTH_LOCK: cairo_set_source_rgb(ctx, 51.0 / 255, 0, 250.0 / 255); break; case STATE_AUTH_WRONG: case STATE_I3LOCK_LOCK_FAILED: cairo_set_source_rgb(ctx, 125.0 / 255, 51.0 / 255, 0); break; case STATE_AUTH_IDLE: cairo_set_source_rgb(ctx, 51.0 / 255, 125.0 / 255, 0); break; } cairo_stroke(ctx); /* Draw an inner seperator line. */ cairo_set_source_rgb(ctx, 0, 0, 0); cairo_set_line_width(ctx, 2.0); cairo_arc(ctx, BUTTON_CENTER /* x */, BUTTON_CENTER /* y */, BUTTON_RADIUS - 5 /* radius */, 0, 2 * M_PI); cairo_stroke(ctx); cairo_set_line_width(ctx, 10.0); /* Display a (centered) text of the current PAM state. */ char *text = NULL; /* We don't want to show more than a 3-digit number. */ char buf[4]; cairo_set_source_rgb(ctx, 0, 0, 0); cairo_select_font_face(ctx, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_set_font_size(ctx, 28.0); switch (auth_state) { case STATE_AUTH_VERIFY: text = "verifying…"; break; case STATE_AUTH_LOCK: text = "locking…"; break; case STATE_AUTH_WRONG: text = "wrong!"; break; case STATE_I3LOCK_LOCK_FAILED: text = "lock failed!"; break; default: if (show_failed_attempts && failed_attempts > 0) { if (failed_attempts > 999) { text = "> 999"; } else { snprintf(buf, sizeof(buf), "%d", failed_attempts); text = buf; } cairo_set_source_rgb(ctx, 1, 0, 0); cairo_set_font_size(ctx, 32.0); } break; } if (text) { cairo_text_extents_t extents; double x, y; cairo_text_extents(ctx, text, &extents); x = BUTTON_CENTER - ((extents.width / 2) + extents.x_bearing); y = BUTTON_CENTER - ((extents.height / 2) + extents.y_bearing); cairo_move_to(ctx, x, y); cairo_show_text(ctx, text); cairo_close_path(ctx); } if (auth_state == STATE_AUTH_WRONG && (modifier_string != NULL)) { cairo_text_extents_t extents; double x, y; cairo_set_font_size(ctx, 14.0); cairo_text_extents(ctx, modifier_string, &extents); x = BUTTON_CENTER - ((extents.width / 2) + extents.x_bearing); y = BUTTON_CENTER - ((extents.height / 2) + extents.y_bearing) + 28.0; cairo_move_to(ctx, x, y); cairo_show_text(ctx, modifier_string); cairo_close_path(ctx); } /* After the user pressed any valid key or the backspace key, we * highlight a random part of the unlock indicator to confirm this * keypress. */ if (unlock_state == STATE_KEY_ACTIVE || unlock_state == STATE_BACKSPACE_ACTIVE) { cairo_new_sub_path(ctx); double highlight_start = (rand() % (int)(2 * M_PI * 100)) / 100.0; cairo_arc(ctx, BUTTON_CENTER /* x */, BUTTON_CENTER /* y */, BUTTON_RADIUS /* radius */, highlight_start, highlight_start + (M_PI / 3.0)); if (unlock_state == STATE_KEY_ACTIVE) { /* For normal keys, we use a lighter green. */ cairo_set_source_rgb(ctx, 51.0 / 255, 219.0 / 255, 0); } else { /* For backspace, we use red. */ cairo_set_source_rgb(ctx, 219.0 / 255, 51.0 / 255, 0); } cairo_stroke(ctx); /* Draw two little separators for the highlighted part of the * unlock indicator. */ cairo_set_source_rgb(ctx, 0, 0, 0); cairo_arc(ctx, BUTTON_CENTER /* x */, BUTTON_CENTER /* y */, BUTTON_RADIUS /* radius */, highlight_start /* start */, highlight_start + (M_PI / 128.0) /* end */); cairo_stroke(ctx); cairo_arc(ctx, BUTTON_CENTER /* x */, BUTTON_CENTER /* y */, BUTTON_RADIUS /* radius */, (highlight_start + (M_PI / 3.0)) - (M_PI / 128.0) /* start */, highlight_start + (M_PI / 3.0) /* end */); cairo_stroke(ctx); } } if (xr_screens > 0) { /* Composite the unlock indicator in the middle of each screen. */ for (int screen = 0; screen < xr_screens; screen++) { int x = (xr_resolutions[screen].x + ((xr_resolutions[screen].width / 2) - (button_diameter_physical / 2))); int y = (xr_resolutions[screen].y + ((xr_resolutions[screen].height / 2) - (button_diameter_physical / 2))); cairo_set_source_surface(xcb_ctx, output, x, y); cairo_rectangle(xcb_ctx, x, y, button_diameter_physical, button_diameter_physical); cairo_fill(xcb_ctx); } } else { /* We have no information about the screen sizes/positions, so we just * place the unlock indicator in the middle of the X root window and * hope for the best. */ int x = (last_resolution[0] / 2) - (button_diameter_physical / 2); int y = (last_resolution[1] / 2) - (button_diameter_physical / 2); cairo_set_source_surface(xcb_ctx, output, x, y); cairo_rectangle(xcb_ctx, x, y, button_diameter_physical, button_diameter_physical); cairo_fill(xcb_ctx); } cairo_surface_destroy(xcb_output); cairo_surface_destroy(output); cairo_destroy(ctx); cairo_destroy(xcb_ctx); return bg_pixmap; }
/* * Draws global image with fill color onto a pixmap with the given * resolution and returns it. * */ xcb_pixmap_t draw_image(uint32_t *resolution) { xcb_pixmap_t bg_pixmap = XCB_NONE; if (!vistype) vistype = get_root_visual_type(screen); if (fuzzy) { bg_pixmap = create_fg_pixmap(conn, screen, resolution); } else { bg_pixmap = create_bg_pixmap(conn, screen, resolution, color); } /* Initialize cairo: Create one in-memory surface to render the unlock * indicator on, create one XCB surface to actually draw (one or more, * depending on the amount of screens) unlock indicators on. */ cairo_surface_t *xcb_output = cairo_xcb_surface_create(conn, bg_pixmap, vistype, resolution[0], resolution[1]); cairo_t *xcb_ctx = cairo_create(xcb_output); if (img||fuzzy) { if (fuzzy) { blur_image_gl(0, bg_pixmap, last_resolution[0],last_resolution[1], blur_radius, blur_sigma); cairo_surface_t * tmp = cairo_xcb_surface_create(conn, bg_pixmap, get_root_visual_type(screen), last_resolution[0], last_resolution[1]); cairo_set_source_surface(xcb_ctx, tmp, 0, 0); cairo_paint(xcb_ctx); cairo_surface_destroy(tmp); } else if (!tile) { cairo_set_source_surface(xcb_ctx, img, 0, 0); cairo_paint(xcb_ctx); } else { /* create a pattern and fill a rectangle as big as the screen */ cairo_pattern_t *pattern; pattern = cairo_pattern_create_for_surface(img); cairo_set_source(xcb_ctx, pattern); cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); cairo_rectangle(xcb_ctx, 0, 0, resolution[0], resolution[1]); cairo_fill(xcb_ctx); cairo_pattern_destroy(pattern); } } else { char strgroups[3][3] = {{color[0], color[1], '\0'}, {color[2], color[3], '\0'}, {color[4], color[5], '\0'}}; uint32_t rgb16[3] = {(strtol(strgroups[0], NULL, 16)), (strtol(strgroups[1], NULL, 16)), (strtol(strgroups[2], NULL, 16))}; cairo_set_source_rgb(xcb_ctx, rgb16[0] / 255.0, rgb16[1] / 255.0, rgb16[2] / 255.0); cairo_rectangle(xcb_ctx, 0, 0, resolution[0], resolution[1]); cairo_fill(xcb_ctx); } if (xr_screens > 0) { /* Composite the unlock indicator in the middle of each screen. */ for (int screen = 0; screen < xr_screens; screen++) { int x = (xr_resolutions[screen].x + ((xr_resolutions[screen].width / 2) - (button_diameter_physical / 2))); int y = (xr_resolutions[screen].y + ((xr_resolutions[screen].height / 2) - (button_diameter_physical / 2))); cairo_set_source_surface(xcb_ctx, unlock_indicator_surface, x, y); cairo_rectangle(xcb_ctx, x, y, button_diameter_physical, button_diameter_physical); cairo_fill(xcb_ctx); } } else { /* We have no information about the screen sizes/positions, so we just * place the unlock indicator in the middle of the X root window and * hope for the best. */ int x = (last_resolution[0] / 2) - (button_diameter_physical / 2); int y = (last_resolution[1] / 2) - (button_diameter_physical / 2); cairo_set_source_surface(xcb_ctx, unlock_indicator_surface, x, y); cairo_rectangle(xcb_ctx, x, y, button_diameter_physical, button_diameter_physical); cairo_fill(xcb_ctx); } cairo_surface_destroy(xcb_output); cairo_destroy(xcb_ctx); return bg_pixmap; }
/* * Draws global image with fill color onto a pixmap with the given * resolution and returns it. * */ xcb_pixmap_t draw_image(uint32_t *resolution) { xcb_pixmap_t bg_pixmap = XCB_NONE; int button_diameter_physical = ceil(scaling_factor() * BUTTON_DIAMETER); DEBUG("scaling_factor is %.f, physical diameter is %d px\n", scaling_factor(), button_diameter_physical); if (!vistype) vistype = get_root_visual_type(screen); bg_pixmap = create_bg_pixmap(conn, screen, resolution, color); /* Initialize cairo: Create one in-memory surface to render the unlock * indicator on, create one XCB surface to actually draw (one or more, * depending on the amount of screens) unlock indicators on. */ cairo_surface_t *output = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, resolution[0], resolution[1]); cairo_t *ctx = cairo_create(output); cairo_surface_t *xcb_output = cairo_xcb_surface_create(conn, bg_pixmap, vistype, resolution[0], resolution[1]); cairo_t *xcb_ctx = cairo_create(xcb_output); if (img) { if (!tile) { cairo_set_source_surface(xcb_ctx, img, 0, 0); cairo_paint(xcb_ctx); } else { /* create a pattern and fill a rectangle as big as the screen */ cairo_pattern_t *pattern; pattern = cairo_pattern_create_for_surface(img); cairo_set_source(xcb_ctx, pattern); cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); cairo_rectangle(xcb_ctx, 0, 0, resolution[0], resolution[1]); cairo_fill(xcb_ctx); cairo_pattern_destroy(pattern); } } else { char strgroups[3][3] = {{color[0], color[1], '\0'}, {color[2], color[3], '\0'}, {color[4], color[5], '\0'}}; uint32_t rgb16[3] = {(strtol(strgroups[0], NULL, 16)), (strtol(strgroups[1], NULL, 16)), (strtol(strgroups[2], NULL, 16))}; cairo_set_source_rgb(xcb_ctx, rgb16[0] / 255.0, rgb16[1] / 255.0, rgb16[2] / 255.0); cairo_rectangle(xcb_ctx, 0, 0, resolution[0], resolution[1]); cairo_fill(xcb_ctx); } if (unlock_indicator) { cairo_scale(ctx, scaling_factor(), scaling_factor()); cairo_set_source_rgb(ctx, 1, 1, 1); cairo_set_font_size(ctx, 60.0); cairo_select_font_face(ctx, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); if (pam_state == STATE_PAM_VERIFY) { passwdlength = 0; } if (unlock_state == STATE_KEY_ACTIVE) { passwdlength = passwdlength + 1; } else if (unlock_state == STATE_BACKSPACE_ACTIVE && passwdlength > 0){ passwdlength = passwdlength - 1; } else if (unlock_state == STATE_ESCAPE_ACTIVE) { passwdlength = 0; } char passwd[passwdlength + 1]; for (int i = 0; i < passwdlength; ++i) { passwd[i] = '*'; } passwd[passwdlength] = '\0'; cairo_text_extents_t extents; double x, y; cairo_text_extents(ctx, passwd, &extents); x = BUTTON_RADIUS - ((extents.width / 2) + extents.x_bearing); y = BUTTON_RADIUS - ((extents.height / 2) + extents.y_bearing); cairo_move_to(ctx, x, y); /* cairo_show_text(ctx, passwd); */ cairo_text_path(ctx, passwd); cairo_fill_preserve(ctx); cairo_set_source_rgb(ctx, 0, 0, 0); cairo_set_line_width(ctx, 1.0); cairo_stroke(ctx); cairo_close_path(ctx); } if (xr_screens > 0) { /* Composite the unlock indicator in the middle of each screen. */ for (int screen = 0; screen < xr_screens; screen++) { int x = (xr_resolutions[screen].x + ((xr_resolutions[screen].width / 2) - (button_diameter_physical / 2))); int y = (xr_resolutions[screen].y + ((xr_resolutions[screen].height / 2) - (button_diameter_physical / 2))); cairo_set_source_surface(xcb_ctx, output, x, y); cairo_rectangle(xcb_ctx, x, y, button_diameter_physical, button_diameter_physical); cairo_fill(xcb_ctx); } } else { /* We have no information about the screen sizes/positions, so we just * place the unlock indicator in the middle of the X root window and * hope for the best. */ int x = (last_resolution[0] / 2) - (button_diameter_physical / 2); int y = (last_resolution[1] / 2) - (button_diameter_physical / 2); cairo_set_source_surface(xcb_ctx, output, x, y); cairo_rectangle(xcb_ctx, x, y, button_diameter_physical, button_diameter_physical); cairo_fill(xcb_ctx); } cairo_surface_destroy(xcb_output); cairo_surface_destroy(output); cairo_destroy(ctx); cairo_destroy(xcb_ctx); return bg_pixmap; }
/* * Draws global image with fill color onto a pixmap with the given * resolution and returns it. * */ xcb_pixmap_t draw_image(uint32_t *resolution) { xcb_pixmap_t bg_pixmap = XCB_NONE; #ifndef NOLIBCAIRO if (!vistype) vistype = get_root_visual_type(screen); bg_pixmap = create_bg_pixmap(conn, screen, resolution, color); /* Initialize cairo: Create one in-memory surface to render the unlock * indicator on, create one XCB surface to actually draw (one or more, * depending on the amount of screens) unlock indicators on. */ cairo_surface_t *output = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, BUTTON_DIAMETER, BUTTON_DIAMETER); cairo_t *ctx = cairo_create(output); cairo_surface_t *xcb_output = cairo_xcb_surface_create(conn, bg_pixmap, vistype, resolution[0], resolution[1]); cairo_t *xcb_ctx = cairo_create(xcb_output); if (img) { if (!tile) { cairo_set_source_surface(xcb_ctx, img, 0, 0); cairo_paint(xcb_ctx); } else { /* create a pattern and fill a rectangle as big as the screen */ cairo_pattern_t *pattern; pattern = cairo_pattern_create_for_surface(img); cairo_set_source(xcb_ctx, pattern); cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); cairo_rectangle(xcb_ctx, 0, 0, resolution[0], resolution[1]); cairo_fill(xcb_ctx); cairo_pattern_destroy(pattern); } } else { char strgroups[3][3] = {{color[0], color[1], '\0'}, {color[2], color[3], '\0'}, {color[4], color[5], '\0'}}; uint32_t rgb16[3] = {(strtol(strgroups[0], NULL, 16)), (strtol(strgroups[1], NULL, 16)), (strtol(strgroups[2], NULL, 16))}; cairo_set_source_rgb(xcb_ctx, rgb16[0] / 255.0, rgb16[1] / 255.0, rgb16[2] / 255.0); cairo_rectangle(xcb_ctx, 0, 0, resolution[0], resolution[1]); cairo_fill(xcb_ctx); } #ifndef NOLIBCAIRO /* build indicator color arrays */ char strgroupsiv[4][3] = {{insidevercolor[0], insidevercolor[1], '\0'}, {insidevercolor[2], insidevercolor[3], '\0'}, {insidevercolor[4], insidevercolor[5], '\0'}, {insidevercolor[6], insidevercolor[7], '\0'}}; uint32_t insidever16[4] = {(strtol(strgroupsiv[0], NULL, 16)), (strtol(strgroupsiv[1], NULL, 16)), (strtol(strgroupsiv[2], NULL, 16)), (strtol(strgroupsiv[3], NULL, 16))}; char strgroupsiw[4][3] = {{insidewrongcolor[0], insidewrongcolor[1], '\0'}, {insidewrongcolor[2], insidewrongcolor[3], '\0'}, {insidewrongcolor[4], insidewrongcolor[5], '\0'}, {insidewrongcolor[6], insidewrongcolor[7], '\0'}}; uint32_t insidewrong16[4] = {(strtol(strgroupsiw[0], NULL, 16)), (strtol(strgroupsiw[1], NULL, 16)), (strtol(strgroupsiw[2], NULL, 16)), (strtol(strgroupsiw[3], NULL, 16))}; char strgroupsi[4][3] = {{insidecolor[0], insidecolor[1], '\0'}, {insidecolor[2], insidecolor[3], '\0'}, {insidecolor[4], insidecolor[5], '\0'}, {insidecolor[6], insidecolor[7], '\0'}}; uint32_t inside16[4] = {(strtol(strgroupsi[0], NULL, 16)), (strtol(strgroupsi[1], NULL, 16)), (strtol(strgroupsi[2], NULL, 16)), (strtol(strgroupsi[3], NULL, 16))}; char strgroupsrv[4][3] = {{ringvercolor[0], ringvercolor[1], '\0'}, {ringvercolor[2], ringvercolor[3], '\0'}, {ringvercolor[4], ringvercolor[5], '\0'}, {ringvercolor[6], ringvercolor[7], '\0'}}; uint32_t ringver16[4] = {(strtol(strgroupsrv[0], NULL, 16)), (strtol(strgroupsrv[1], NULL, 16)), (strtol(strgroupsrv[2], NULL, 16)), (strtol(strgroupsrv[3], NULL, 16))}; char strgroupsrw[4][3] = {{ringwrongcolor[0], ringwrongcolor[1], '\0'}, {ringwrongcolor[2], ringwrongcolor[3], '\0'}, {ringwrongcolor[4], ringwrongcolor[5], '\0'}, {ringwrongcolor[6], ringwrongcolor[7], '\0'}}; uint32_t ringwrong16[4] = {(strtol(strgroupsrw[0], NULL, 16)), (strtol(strgroupsrw[1], NULL, 16)), (strtol(strgroupsrw[2], NULL, 16)), (strtol(strgroupsrw[3], NULL, 16))}; char strgroupsr[4][3] = {{ringcolor[0], ringcolor[1], '\0'}, {ringcolor[2], ringcolor[3], '\0'}, {ringcolor[4], ringcolor[5], '\0'}, {ringcolor[6], ringcolor[7], '\0'}}; uint32_t ring16[4] = {(strtol(strgroupsr[0], NULL, 16)), (strtol(strgroupsr[1], NULL, 16)), (strtol(strgroupsr[2], NULL, 16)), (strtol(strgroupsr[3], NULL, 16))}; char strgroupsl[4][3] = {{linecolor[0], linecolor[1], '\0'}, {linecolor[2], linecolor[3], '\0'}, {linecolor[4], linecolor[5], '\0'}, {linecolor[6], linecolor[7], '\0'}}; uint32_t line16[4] = {(strtol(strgroupsl[0], NULL, 16)), (strtol(strgroupsl[1], NULL, 16)), (strtol(strgroupsl[2], NULL, 16)), (strtol(strgroupsl[3], NULL, 16))}; char strgroupst[4][3] = {{textcolor[0], textcolor[1], '\0'}, {textcolor[2], textcolor[3], '\0'}, {textcolor[4], textcolor[5], '\0'}, {textcolor[6], textcolor[7], '\0'}}; uint32_t text16[4] = {(strtol(strgroupst[0], NULL, 16)), (strtol(strgroupst[1], NULL, 16)), (strtol(strgroupst[2], NULL, 16)), (strtol(strgroupst[3], NULL, 16))}; char strgroupsk[4][3] = {{keyhlcolor[0], textcolor[1], '\0'}, {keyhlcolor[2], textcolor[3], '\0'}, {keyhlcolor[4], textcolor[5], '\0'}, {keyhlcolor[6], textcolor[7], '\0'}}; uint32_t keyhl16[4] = {(strtol(strgroupsk[0], NULL, 16)), (strtol(strgroupsk[1], NULL, 16)), (strtol(strgroupsk[2], NULL, 16)), (strtol(strgroupsk[3], NULL, 16))}; char strgroupsb[4][3] = {{bshlcolor[0], textcolor[1], '\0'}, {bshlcolor[2], textcolor[3], '\0'}, {bshlcolor[4], textcolor[5], '\0'}, {bshlcolor[6], textcolor[7], '\0'}}; uint32_t bshl16[4] = {(strtol(strgroupsb[0], NULL, 16)), (strtol(strgroupsb[1], NULL, 16)), (strtol(strgroupsb[2], NULL, 16)), (strtol(strgroupsb[3], NULL, 16))}; #endif if (unlock_state >= STATE_KEY_PRESSED && unlock_indicator) { /* Draw a (centered) circle with transparent background. */ cairo_set_line_width(ctx, 10.0); cairo_arc(ctx, BUTTON_CENTER /* x */, BUTTON_CENTER /* y */, BUTTON_RADIUS /* radius */, 0 /* start */, 2 * M_PI /* end */); /* Use the appropriate color for the different PAM states * (currently verifying, wrong password, or default) */ switch (pam_state) { case STATE_PAM_VERIFY: cairo_set_source_rgba(ctx, (double)insidever16[0]/255, (double)insidever16[1]/255, (double)insidever16[2]/255, (double)insidever16[3]/255); break; case STATE_PAM_WRONG: cairo_set_source_rgba(ctx, (double)insidewrong16[0]/255, (double)insidewrong16[1]/255, (double)insidewrong16[2]/255, (double)insidewrong16[3]/255); break; default: cairo_set_source_rgba(ctx, (double)inside16[0]/255, (double)inside16[1]/255, (double)inside16[2]/255, (double)inside16[3]/255); break; } cairo_fill_preserve(ctx); switch (pam_state) { case STATE_PAM_VERIFY: cairo_set_source_rgba(ctx, (double)ringver16[0]/255, (double)ringver16[1]/255, (double)ringver16[2]/255, (double)ringver16[3]/255); break; case STATE_PAM_WRONG: cairo_set_source_rgba(ctx, (double)ringwrong16[0]/255, (double)ringwrong16[1]/255, (double)ringwrong16[2]/255, (double)ringwrong16[3]/255); break; case STATE_PAM_IDLE: cairo_set_source_rgba(ctx, (double)ring16[0]/255, (double)ring16[1]/255, (double)ring16[2]/255, (double)ring16[3]/255); break; } cairo_stroke(ctx); /* Draw an inner seperator line. */ cairo_set_source_rgba(ctx, (double)line16[0]/255, (double)line16[1]/255, (double)line16[2]/255, (double)line16[3]/255); cairo_set_line_width(ctx, 2.0); cairo_arc(ctx, BUTTON_CENTER /* x */, BUTTON_CENTER /* y */, BUTTON_RADIUS - 5 /* radius */, 0, 2 * M_PI); cairo_stroke(ctx); cairo_set_line_width(ctx, 10.0); /* Display a (centered) text of the current PAM state. */ char *text = NULL; switch (pam_state) { case STATE_PAM_VERIFY: text = verifying_text; break; case STATE_PAM_WRONG: text = wrong_text; break; default: break; } if (text) { cairo_text_extents_t extents; double x, y; cairo_set_source_rgba(ctx, (double)text16[0]/255, (double)text16[1]/255, (double)text16[2]/255, (double)text16[3]/255); cairo_set_font_size(ctx, 28.0); cairo_text_extents(ctx, text, &extents); x = BUTTON_CENTER - ((extents.width / 2) + extents.x_bearing); y = BUTTON_CENTER - ((extents.height / 2) + extents.y_bearing); cairo_move_to(ctx, x, y); cairo_show_text(ctx, text); cairo_close_path(ctx); } /* After the user pressed any valid key or the backspace key, we * highlight a random part of the unlock indicator to confirm this * keypress. */ if (unlock_state == STATE_KEY_ACTIVE || unlock_state == STATE_BACKSPACE_ACTIVE) { cairo_new_sub_path(ctx); double highlight_start = (rand() % (int)(2 * M_PI * 100)) / 100.0; cairo_arc(ctx, BUTTON_CENTER /* x */, BUTTON_CENTER /* y */, BUTTON_RADIUS /* radius */, highlight_start, highlight_start + (M_PI / 3.0)); if (unlock_state == STATE_KEY_ACTIVE) { /* For normal keys, we use a lighter green. */ cairo_set_source_rgba(ctx, (double)keyhl16[0]/255, (double)keyhl16[1]/255, (double)keyhl16[2]/255, (double)keyhl16[3]/255); } else { /* For backspace, we use red. */ cairo_set_source_rgba(ctx, (double)bshl16[0]/255, (double)bshl16[1]/255, (double)bshl16[2]/255, (double)bshl16[3]/255); } cairo_stroke(ctx); /* Draw two little separators for the highlighted part of the * unlock indicator. */ cairo_set_source_rgba(ctx, (double)line16[0]/255, (double)line16[1]/255, (double)line16[2]/255, (double)line16[3]/255); cairo_arc(ctx, BUTTON_CENTER /* x */, BUTTON_CENTER /* y */, BUTTON_RADIUS /* radius */, highlight_start /* start */, highlight_start + (M_PI / 128.0) /* end */); cairo_stroke(ctx); cairo_arc(ctx, BUTTON_CENTER /* x */, BUTTON_CENTER /* y */, BUTTON_RADIUS /* radius */, highlight_start + (M_PI / 3.0) /* start */, (highlight_start + (M_PI / 3.0)) + (M_PI / 128.0) /* end */); cairo_stroke(ctx); } } if (xr_screens > 0) { /* Composite the unlock indicator in the middle of each screen. */ for (int screen = 0; screen < xr_screens; screen++) { int x = (xr_resolutions[screen].x + ((xr_resolutions[screen].width / 2) - (BUTTON_DIAMETER / 2))); int y = (xr_resolutions[screen].y + ((xr_resolutions[screen].height / 2) - (BUTTON_DIAMETER / 2))); cairo_set_source_surface(xcb_ctx, output, x, y); cairo_rectangle(xcb_ctx, x, y, BUTTON_DIAMETER, BUTTON_DIAMETER); cairo_fill(xcb_ctx); } } else { /* We have no information about the screen sizes/positions, so we just * place the unlock indicator in the middle of the X root window and * hope for the best. */ int x = (last_resolution[0] / 2); int y = (last_resolution[1] / 2); cairo_set_source_surface(xcb_ctx, output, x, y); cairo_rectangle(xcb_ctx, x, y, BUTTON_DIAMETER, BUTTON_DIAMETER); cairo_fill(xcb_ctx); } cairo_surface_destroy(xcb_output); cairo_surface_destroy(output); cairo_destroy(ctx); cairo_destroy(xcb_ctx); #endif return bg_pixmap; }
/* * Draws global image with fill color onto a pixmap with the given * resolution and returns it. * */ xcb_pixmap_t draw_image(uint32_t *resolution) { xcb_pixmap_t bg_pixmap = XCB_NONE; RsvgDimensionData svg_dimensions; rsvg_handle_get_dimensions(svg, &svg_dimensions); int indicator_x_physical = ceil(scaling_factor() * svg_dimensions.width); int indicator_y_physical = ceil(scaling_factor() * svg_dimensions.height); if (!vistype) vistype = get_root_visual_type(screen); bg_pixmap = create_bg_pixmap(conn, screen, resolution, color); /* Initialize cairo: Create one in-memory surface to render the unlock * indicator on, create one XCB surface to actually draw (one or more, * depending on the amount of screens) unlock indicators on. */ cairo_surface_t *output = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, indicator_x_physical, indicator_y_physical); cairo_t *ctx = cairo_create(output); cairo_surface_t *xcb_output = cairo_xcb_surface_create(conn, bg_pixmap, vistype, resolution[0], resolution[1]); cairo_t *xcb_ctx = cairo_create(xcb_output); if (img) { if (!tile) { cairo_set_source_surface(xcb_ctx, img, 0, 0); cairo_paint(xcb_ctx); } else { /* create a pattern and fill a rectangle as big as the screen */ cairo_pattern_t *pattern; pattern = cairo_pattern_create_for_surface(img); cairo_set_source(xcb_ctx, pattern); cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); cairo_rectangle(xcb_ctx, 0, 0, resolution[0], resolution[1]); cairo_fill(xcb_ctx); cairo_pattern_destroy(pattern); } } else { char strgroups[3][3] = {{color[0], color[1], '\0'}, {color[2], color[3], '\0'}, {color[4], color[5], '\0'}}; uint32_t rgb16[3] = {(strtol(strgroups[0], NULL, 16)), (strtol(strgroups[1], NULL, 16)), (strtol(strgroups[2], NULL, 16))}; cairo_set_source_rgb(xcb_ctx, rgb16[0] / 255.0, rgb16[1] / 255.0, rgb16[2] / 255.0); cairo_rectangle(xcb_ctx, 0, 0, resolution[0], resolution[1]); cairo_fill(xcb_ctx); } if (unlock_state >= STATE_KEY_PRESSED && unlock_indicator) { cairo_scale(ctx, scaling_factor(), scaling_factor()); rsvg_handle_render_cairo_sub(svg, ctx, "#bg"); /* Use the appropriate color for the different PAM states * (currently verifying, wrong password, or default) */ if (!(unlock_state == STATE_KEY_ACTIVE || unlock_state == STATE_BACKSPACE_ACTIVE) || !remove_background) { switch (pam_state) { case STATE_PAM_VERIFY: rsvg_handle_render_cairo_sub(svg, ctx, "#verify"); break; case STATE_PAM_WRONG: rsvg_handle_render_cairo_sub(svg, ctx, "#fail"); break; default: rsvg_handle_render_cairo_sub(svg, ctx, "#idle"); break; } } /* After the user pressed any valid key or the backspace key, we * highlight a random part of the unlock indicator to confirm this * keypress. */ if (unlock_state == STATE_KEY_ACTIVE || unlock_state == STATE_BACKSPACE_ACTIVE) { if(++current_frame >= anim_layer_count) current_frame = 0; if (unlock_state == STATE_KEY_ACTIVE) { if(!sequential_animation) current_frame = rand() % anim_layer_count; char anim_id[9]; snprintf(anim_id, sizeof(anim_id), "#anim%02d", current_frame); rsvg_handle_render_cairo_sub(svg, ctx, anim_id); } else { rsvg_handle_render_cairo_sub(svg, ctx, "#backspace"); } } rsvg_handle_render_cairo_sub(svg, ctx, "#fg"); } if (xr_screens > 0) { /* Composite the unlock indicator in the middle of each screen. */ for (int screen = 0; screen < xr_screens; screen++) { int x = (xr_resolutions[screen].x + ((xr_resolutions[screen].width / 2) - (indicator_x_physical / 2))); int y = (xr_resolutions[screen].y + ((xr_resolutions[screen].height / 2) - (indicator_y_physical / 2))); cairo_set_source_surface(xcb_ctx, output, x, y); cairo_rectangle(xcb_ctx, x, y, indicator_x_physical, indicator_y_physical); cairo_fill(xcb_ctx); } } else { /* We have no information about the screen sizes/positions, so we just * place the unlock indicator in the middle of the X root window and * hope for the best. */ int x = (last_resolution[0] / 2) - (indicator_x_physical / 2); int y = (last_resolution[1] / 2) - (indicator_y_physical / 2); cairo_set_source_surface(xcb_ctx, output, x, y); cairo_rectangle(xcb_ctx, x, y, indicator_x_physical, indicator_y_physical); cairo_fill(xcb_ctx); } cairo_surface_destroy(xcb_output); cairo_surface_destroy(output); cairo_destroy(ctx); cairo_destroy(xcb_ctx); return bg_pixmap; }
/* * Draws global image with fill color onto a pixmap with the given * resolution and returns it. * */ xcb_pixmap_t draw_image(uint32_t *resolution) { xcb_pixmap_t bg_pixmap = XCB_NONE; int button_diameter_physical = ceil(scaling_factor() * BUTTON_DIAMETER); DEBUG("scaling_factor is %.f, physical diameter is %d px\n", scaling_factor(), button_diameter_physical); if (!vistype) vistype = get_root_visual_type(screen); bg_pixmap = create_bg_pixmap(conn, screen, resolution, color); /* Initialize cairo: Create one in-memory surface to render the unlock * indicator on, create one XCB surface to actually draw (one or more, * depending on the amount of screens) unlock indicators on. */ cairo_surface_t *output = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, button_diameter_physical, button_diameter_physical); cairo_t *ctx = cairo_create(output); cairo_surface_t *xcb_output = cairo_xcb_surface_create(conn, bg_pixmap, vistype, resolution[0], resolution[1]); cairo_t *xcb_ctx = cairo_create(xcb_output); if (img) { if (!tile) { cairo_set_source_surface(xcb_ctx, img, 0, 0); cairo_paint(xcb_ctx); } else { /* create a pattern and fill a rectangle as big as the screen */ cairo_pattern_t *pattern; pattern = cairo_pattern_create_for_surface(img); cairo_set_source(xcb_ctx, pattern); cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); cairo_rectangle(xcb_ctx, 0, 0, resolution[0], resolution[1]); cairo_fill(xcb_ctx); cairo_pattern_destroy(pattern); } } else { char strgroups[3][3] = {{color[0], color[1], '\0'}, {color[2], color[3], '\0'}, {color[4], color[5], '\0'}}; uint32_t rgb16[3] = {(strtol(strgroups[0], NULL, 16)), (strtol(strgroups[1], NULL, 16)), (strtol(strgroups[2], NULL, 16))}; cairo_set_source_rgb(xcb_ctx, rgb16[0] / 255.0, rgb16[1] / 255.0, rgb16[2] / 255.0); cairo_rectangle(xcb_ctx, 0, 0, resolution[0], resolution[1]); cairo_fill(xcb_ctx); } /* build indicator color arrays */ char strgroupsiv[4][3] = {{insidevercolor[0], insidevercolor[1], '\0'}, {insidevercolor[2], insidevercolor[3], '\0'}, {insidevercolor[4], insidevercolor[5], '\0'}, {insidevercolor[6], insidevercolor[7], '\0'}}; uint32_t insidever16[4] = {(strtol(strgroupsiv[0], NULL, 16)), (strtol(strgroupsiv[1], NULL, 16)), (strtol(strgroupsiv[2], NULL, 16)), (strtol(strgroupsiv[3], NULL, 16))}; char strgroupsiw[4][3] = {{insidewrongcolor[0], insidewrongcolor[1], '\0'}, {insidewrongcolor[2], insidewrongcolor[3], '\0'}, {insidewrongcolor[4], insidewrongcolor[5], '\0'}, {insidewrongcolor[6], insidewrongcolor[7], '\0'}}; uint32_t insidewrong16[4] = {(strtol(strgroupsiw[0], NULL, 16)), (strtol(strgroupsiw[1], NULL, 16)), (strtol(strgroupsiw[2], NULL, 16)), (strtol(strgroupsiw[3], NULL, 16))}; char strgroupsi[4][3] = {{insidecolor[0], insidecolor[1], '\0'}, {insidecolor[2], insidecolor[3], '\0'}, {insidecolor[4], insidecolor[5], '\0'}, {insidecolor[6], insidecolor[7], '\0'}}; uint32_t inside16[4] = {(strtol(strgroupsi[0], NULL, 16)), (strtol(strgroupsi[1], NULL, 16)), (strtol(strgroupsi[2], NULL, 16)), (strtol(strgroupsi[3], NULL, 16))}; char strgroupsrv[4][3] = {{ringvercolor[0], ringvercolor[1], '\0'}, {ringvercolor[2], ringvercolor[3], '\0'}, {ringvercolor[4], ringvercolor[5], '\0'}, {ringvercolor[6], ringvercolor[7], '\0'}}; uint32_t ringver16[4] = {(strtol(strgroupsrv[0], NULL, 16)), (strtol(strgroupsrv[1], NULL, 16)), (strtol(strgroupsrv[2], NULL, 16)), (strtol(strgroupsrv[3], NULL, 16))}; char strgroupsrw[4][3] = {{ringwrongcolor[0], ringwrongcolor[1], '\0'}, {ringwrongcolor[2], ringwrongcolor[3], '\0'}, {ringwrongcolor[4], ringwrongcolor[5], '\0'}, {ringwrongcolor[6], ringwrongcolor[7], '\0'}}; uint32_t ringwrong16[4] = {(strtol(strgroupsrw[0], NULL, 16)), (strtol(strgroupsrw[1], NULL, 16)), (strtol(strgroupsrw[2], NULL, 16)), (strtol(strgroupsrw[3], NULL, 16))}; char strgroupsr[4][3] = {{ringcolor[0], ringcolor[1], '\0'}, {ringcolor[2], ringcolor[3], '\0'}, {ringcolor[4], ringcolor[5], '\0'}, {ringcolor[6], ringcolor[7], '\0'}}; uint32_t ring16[4] = {(strtol(strgroupsr[0], NULL, 16)), (strtol(strgroupsr[1], NULL, 16)), (strtol(strgroupsr[2], NULL, 16)), (strtol(strgroupsr[3], NULL, 16))}; char strgroupsl[4][3] = {{linecolor[0], linecolor[1], '\0'}, {linecolor[2], linecolor[3], '\0'}, {linecolor[4], linecolor[5], '\0'}, {linecolor[6], linecolor[7], '\0'}}; uint32_t line16[4] = {(strtol(strgroupsl[0], NULL, 16)), (strtol(strgroupsl[1], NULL, 16)), (strtol(strgroupsl[2], NULL, 16)), (strtol(strgroupsl[3], NULL, 16))}; char strgroupst[4][3] = {{textcolor[0], textcolor[1], '\0'}, {textcolor[2], textcolor[3], '\0'}, {textcolor[4], textcolor[5], '\0'}, {textcolor[6], textcolor[7], '\0'}}; uint32_t text16[4] = {(strtol(strgroupst[0], NULL, 16)), (strtol(strgroupst[1], NULL, 16)), (strtol(strgroupst[2], NULL, 16)), (strtol(strgroupst[3], NULL, 16))}; char strgroupsk[4][3] = {{keyhlcolor[0], keyhlcolor[1], '\0'}, {keyhlcolor[2], keyhlcolor[3], '\0'}, {keyhlcolor[4], keyhlcolor[5], '\0'}, {keyhlcolor[6], keyhlcolor[7], '\0'}}; uint32_t keyhl16[4] = {(strtol(strgroupsk[0], NULL, 16)), (strtol(strgroupsk[1], NULL, 16)), (strtol(strgroupsk[2], NULL, 16)), (strtol(strgroupsk[3], NULL, 16))}; char strgroupsb[4][3] = {{bshlcolor[0], bshlcolor[1], '\0'}, {bshlcolor[2], bshlcolor[3], '\0'}, {bshlcolor[4], bshlcolor[5], '\0'}, {bshlcolor[6], bshlcolor[7], '\0'}}; uint32_t bshl16[4] = {(strtol(strgroupsb[0], NULL, 16)), (strtol(strgroupsb[1], NULL, 16)), (strtol(strgroupsb[2], NULL, 16)), (strtol(strgroupsb[3], NULL, 16))}; char strgroupss[4][3] = {{separatorcolor[0], separatorcolor[1], '\0'}, {separatorcolor[2], separatorcolor[3], '\0'}, {separatorcolor[4], separatorcolor[5], '\0'}, {separatorcolor[6], separatorcolor[7], '\0'}}; uint32_t sep16[4] = {(strtol(strgroupss[0], NULL, 16)), (strtol(strgroupss[1], NULL, 16)), (strtol(strgroupss[2], NULL, 16)), (strtol(strgroupss[3], NULL, 16))}; /* https://github.com/ravinrabbid/i3lock-clock/commit/0de3a411fa5249c3a4822612c2d6c476389a1297 */ time_t rawtime; struct tm* timeinfo; time(&rawtime); timeinfo = localtime(&rawtime); if (unlock_indicator && (unlock_state >= STATE_KEY_PRESSED || pam_state > STATE_PAM_IDLE || show_clock)) { cairo_scale(ctx, scaling_factor(), scaling_factor()); /* Draw a (centered) circle with transparent background. */ cairo_set_line_width(ctx, 7.0); cairo_arc(ctx, BUTTON_CENTER /* x */, BUTTON_CENTER /* y */, BUTTON_RADIUS /* radius */, 0 /* start */, 2 * M_PI /* end */); /* Use the appropriate color for the different PAM states * (currently verifying, wrong password, or default) */ switch (pam_state) { case STATE_PAM_VERIFY: case STATE_PAM_LOCK: cairo_set_source_rgba(ctx, (double)insidever16[0]/255, (double)insidever16[1]/255, (double)insidever16[2]/255, (double)insidever16[3]/255); break; case STATE_PAM_WRONG: case STATE_I3LOCK_LOCK_FAILED: cairo_set_source_rgba(ctx, (double)insidewrong16[0]/255, (double)insidewrong16[1]/255, (double)insidewrong16[2]/255, (double)insidewrong16[3]/255); break; default: cairo_set_source_rgba(ctx, (double)inside16[0]/255, (double)inside16[1]/255, (double)inside16[2]/255, (double)inside16[3]/255); break; } cairo_fill_preserve(ctx); switch (pam_state) { case STATE_PAM_VERIFY: case STATE_PAM_LOCK: cairo_set_source_rgba(ctx, (double)ringver16[0]/255, (double)ringver16[1]/255, (double)ringver16[2]/255, (double)ringver16[3]/255); if (internal_line_source == 1) { line16[0] = ringver16[0]; line16[1] = ringver16[1]; line16[2] = ringver16[2]; line16[3] = ringver16[3]; } break; case STATE_PAM_WRONG: case STATE_I3LOCK_LOCK_FAILED: cairo_set_source_rgba(ctx, (double)ringwrong16[0]/255, (double)ringwrong16[1]/255, (double)ringwrong16[2]/255, (double)ringwrong16[3]/255); if (internal_line_source == 1) { line16[0] = ringwrong16[0]; line16[1] = ringwrong16[1]; line16[2] = ringwrong16[2]; line16[3] = ringwrong16[3]; } break; case STATE_PAM_IDLE: cairo_set_source_rgba(ctx, (double)ring16[0]/255, (double)ring16[1]/255, (double)ring16[2]/255, (double)ring16[3]/255); if (internal_line_source == 1) { line16[0] = ring16[0]; line16[1] = ring16[1]; line16[2] = ring16[2]; line16[3] = ring16[3]; } break; } cairo_stroke(ctx); /* Draw an inner separator line. */ if (internal_line_source != 2) { //pretty sure this only needs drawn if it's being drawn over the inside? cairo_set_source_rgba(ctx, (double)line16[0]/255, (double)line16[1]/255, (double)line16[2]/255, (double)line16[3]/255); cairo_set_line_width(ctx, 2.0); cairo_arc(ctx, BUTTON_CENTER /* x */, BUTTON_CENTER /* y */, BUTTON_RADIUS - 5 /* radius */, 0, 2 * M_PI); cairo_stroke(ctx); } cairo_set_line_width(ctx, 10.0); /* Display a (centered) text of the current PAM state. */ char *text = NULL; char *date = NULL; char time_text[40] = {0}; char date_text[40] = {0}; /* We don't want to show more than a 3-digit number. */ char buf[4]; cairo_set_source_rgba(ctx, (double)text16[0]/255, (double)text16[1]/255, (double)text16[2]/255, (double)text16[3]/255); //this was moved up to here cairo_select_font_face(ctx, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_set_font_size(ctx, 28.0); switch (pam_state) { case STATE_PAM_VERIFY: text = "verifying…"; break; case STATE_PAM_LOCK: text = "locking…"; break; case STATE_PAM_WRONG: text = "wrong!"; break; case STATE_I3LOCK_LOCK_FAILED: text = "lock failed!"; break; default: if (show_failed_attempts && failed_attempts > 0) { if (failed_attempts > 999) { text = "> 999"; } else { snprintf(buf, sizeof(buf), "%d", failed_attempts); text = buf; } cairo_set_source_rgba(ctx, (double)text16[0]/255, (double)text16[1]/255, (double)text16[2]/255, (double)text16[3]/255); cairo_set_font_size(ctx, 32.0); } else if (show_clock) { strftime(time_text, 40, time_format, timeinfo); strftime(date_text, 40, date_format, timeinfo); text = time_text; date = date_text; } break; } if (text) { cairo_text_extents_t extents; double x, y; cairo_text_extents(ctx, text, &extents); x = BUTTON_CENTER - ((extents.width / 2) + extents.x_bearing); if (date) { y = BUTTON_CENTER - ((extents.height / 2) + extents.y_bearing) - 6; } else { y = BUTTON_CENTER - ((extents.height / 2) + extents.y_bearing); } cairo_move_to(ctx, x, y); cairo_show_text(ctx, text); cairo_close_path(ctx); } if (date) { cairo_text_extents_t extents; double x, y; // TODO: different date/time colors cairo_set_source_rgba(ctx, (double)text16[0]/255, (double)text16[1]/255, (double)text16[2]/255, (double)text16[3]/255); cairo_set_font_size(ctx, 14.0); cairo_text_extents(ctx, date, &extents); x = BUTTON_CENTER - ((extents.width / 2) + extents.x_bearing); y = BUTTON_CENTER - ((extents.height / 2) + extents.y_bearing) + 14; cairo_move_to(ctx, x, y); cairo_show_text(ctx, date); cairo_close_path(ctx); } if (pam_state == STATE_PAM_WRONG && (modifier_string != NULL)) { cairo_text_extents_t extents; double x, y; cairo_set_font_size(ctx, 14.0); cairo_text_extents(ctx, modifier_string, &extents); x = BUTTON_CENTER - ((extents.width / 2) + extents.x_bearing); y = BUTTON_CENTER - ((extents.height / 2) + extents.y_bearing) + 28.0; cairo_move_to(ctx, x, y); cairo_show_text(ctx, modifier_string); cairo_close_path(ctx); } /* After the user pressed any valid key or the backspace key, we * highlight a random part of the unlock indicator to confirm this * keypress. */ if (unlock_state == STATE_KEY_ACTIVE || unlock_state == STATE_BACKSPACE_ACTIVE) { cairo_set_line_width(ctx, 7.0); cairo_new_sub_path(ctx); double highlight_start = (rand() % (int)(2 * M_PI * 100)) / 100.0; cairo_arc(ctx, BUTTON_CENTER /* x */, BUTTON_CENTER /* y */, BUTTON_RADIUS /* radius */, highlight_start, highlight_start + (M_PI / 3.0)); if (unlock_state == STATE_KEY_ACTIVE) { /* For normal keys, we use a lighter green. */ //lol no cairo_set_source_rgba(ctx, (double)keyhl16[0]/255, (double)keyhl16[1]/255, (double)keyhl16[2]/255, (double)keyhl16[3]/255); } else { /* For backspace, we use red. */ //lol no cairo_set_source_rgba(ctx, (double)bshl16[0]/255, (double)bshl16[1]/255, (double)bshl16[2]/255, (double)bshl16[3]/255); } cairo_stroke(ctx); /* Draw two little separators for the highlighted part of the * unlock indicator. */ cairo_set_source_rgba(ctx, (double)sep16[0]/255, (double)sep16[1]/255, (double)sep16[2]/255, (double)sep16[3]/255); cairo_arc(ctx, BUTTON_CENTER /* x */, BUTTON_CENTER /* y */, BUTTON_RADIUS /* radius */, highlight_start /* start */, highlight_start + (M_PI / 128.0) /* end */); cairo_stroke(ctx); cairo_arc(ctx, BUTTON_CENTER /* x */, BUTTON_CENTER /* y */, BUTTON_RADIUS /* radius */, highlight_start + (M_PI / 3.0) /* start */, (highlight_start + (M_PI / 3.0)) + (M_PI / 128.0) /* end */); cairo_stroke(ctx); } } if (xr_screens > 0) { /* Composite the unlock indicator in the middle of each screen. */ // excuse me, just gonna hack something in right here if (screen_number != -1 && screen_number < xr_screens) { int x = (xr_resolutions[screen_number].x + ((xr_resolutions[screen_number].width / 2) - (button_diameter_physical / 2))); int y = (xr_resolutions[screen_number].y + ((xr_resolutions[screen_number].height / 2) - (button_diameter_physical / 2))); cairo_set_source_surface(xcb_ctx, output, x, y); cairo_rectangle(xcb_ctx, x, y, button_diameter_physical, button_diameter_physical); cairo_fill(xcb_ctx); } else { for (int screen = 0; screen < xr_screens; screen++) { int x = (xr_resolutions[screen].x + ((xr_resolutions[screen].width / 2) - (button_diameter_physical / 2))); int y = (xr_resolutions[screen].y + ((xr_resolutions[screen].height / 2) - (button_diameter_physical / 2))); cairo_set_source_surface(xcb_ctx, output, x, y); cairo_rectangle(xcb_ctx, x, y, button_diameter_physical, button_diameter_physical); cairo_fill(xcb_ctx); } } } else { /* We have no information about the screen sizes/positions, so we just * place the unlock indicator in the middle of the X root window and * hope for the best. */ int x = (last_resolution[0] / 2) - (button_diameter_physical / 2); int y = (last_resolution[1] / 2) - (button_diameter_physical / 2); cairo_set_source_surface(xcb_ctx, output, x, y); cairo_rectangle(xcb_ctx, x, y, button_diameter_physical, button_diameter_physical); cairo_fill(xcb_ctx); } cairo_surface_destroy(xcb_output); cairo_surface_destroy(output); cairo_destroy(ctx); cairo_destroy(xcb_ctx); return bg_pixmap; }
/* * Draws global image with fill color onto a pixmap with the given * resolution and returns it. * */ xcb_pixmap_t draw_image(uint32_t *resolution) { xcb_pixmap_t bg_pixmap = XCB_NONE; int button_diameter_physical = ceil(scaling_factor() * BUTTON_DIAMETER); DEBUG("scaling_factor is %.f, physical diameter is %d px\n", scaling_factor(), button_diameter_physical); if (!vistype) vistype = get_root_visual_type(screen); bg_pixmap = create_bg_pixmap(conn, screen, resolution, color); /* Initialize cairo: Create one in-memory surface to render the unlock * indicator on, create one XCB surface to actually draw (one or more, * depending on the amount of screens) unlock indicators on. */ cairo_surface_t *output = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, button_diameter_physical, button_diameter_physical); cairo_t *ctx = cairo_create(output); cairo_surface_t *xcb_output = cairo_xcb_surface_create(conn, bg_pixmap, vistype, resolution[0], resolution[1]); cairo_t *xcb_ctx = cairo_create(xcb_output); if (img) { if (!tile) { cairo_set_source_surface(xcb_ctx, img, 0, 0); cairo_paint(xcb_ctx); } else { /* create a pattern and fill a rectangle as big as the screen */ cairo_pattern_t *pattern; pattern = cairo_pattern_create_for_surface(img); cairo_set_source(xcb_ctx, pattern); cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); cairo_rectangle(xcb_ctx, 0, 0, resolution[0], resolution[1]); cairo_fill(xcb_ctx); cairo_pattern_destroy(pattern); } } else { char strgroups[3][3] = {{color[0], color[1], '\0'}, {color[2], color[3], '\0'}, {color[4], color[5], '\0'} }; uint32_t rgb16[3] = {(strtol(strgroups[0], NULL, 16)), (strtol(strgroups[1], NULL, 16)), (strtol(strgroups[2], NULL, 16)) }; cairo_set_source_rgb(xcb_ctx, rgb16[0] / 255.0, rgb16[1] / 255.0, rgb16[2] / 255.0); cairo_rectangle(xcb_ctx, 0, 0, resolution[0], resolution[1]); cairo_fill(xcb_ctx); } if (unlock_indicator) { cairo_scale(ctx, scaling_factor(), scaling_factor()); /* Draw a (centered) circle with transparent background. */ cairo_set_line_width(ctx, 3.0); cairo_arc(ctx, BUTTON_CENTER /* x */, BUTTON_CENTER /* y */, BUTTON_RADIUS /* radius */, 0 /* start */, 2 * M_PI /* end */); /* Use the appropriate color for the different PAM states * (currently verifying, wrong password, or default) * Basic function so we don't have to use this code * repeatedly for objects of the same color */ void get_color(void) { switch (pam_state) { case STATE_PAM_VERIFY: cairo_set_source_rgba(ctx, 68.0/255, 80.0/255, 41.0/255, 0.8); break; case STATE_PAM_WRONG: cairo_set_source_rgba(ctx, 143.0/255, 53.0/255, 53.0/255, 0.8); break; case STATE_PAM_IDLE: if (unlock_state == STATE_BACKSPACE_ACTIVE) { cairo_set_source_rgba(ctx, 143.0/255, 53.0/255, 53.0/255, 0.8); } else { cairo_set_source_rgba(ctx, 1, 1, 1, 0.8); } break; } } /* Circle fill */ switch (pam_state) { case STATE_PAM_VERIFY: cairo_set_source_rgba(ctx, 144.0/255, 169.0/255, 89.0/255, 0.2); break; case STATE_PAM_WRONG: cairo_set_source_rgba(ctx, 172.0/255, 65.0/255, 66.0/255, 0.2); break; default: cairo_set_source_rgba(ctx, 0, 0, 0, 0); break; } cairo_fill_preserve(ctx); /* Circle border */ get_color(); cairo_stroke(ctx); /* Display (centered) Time */ char *timetext = malloc(6); time_t curtime = time(NULL); struct tm *tm = localtime(&curtime); strftime(timetext, 100, TIME_FORMAT, tm); /* Color text, same as border */ get_color(); cairo_set_font_size(ctx, 32.0); cairo_text_extents_t time_extents; double time_x, time_y; cairo_text_extents(ctx, timetext, &time_extents); time_x = BUTTON_CENTER - ((time_extents.width / 2) + time_extents.x_bearing); time_y = BUTTON_CENTER - ((time_extents.height / 2) + time_extents.y_bearing); cairo_move_to(ctx, time_x, time_y); cairo_show_text(ctx, timetext); cairo_close_path(ctx); free(timetext); /* After the user pressed any valid key or the backspace key, we * highlight a random part of the unlock indicator to confirm this * keypress. */ if (unlock_state == STATE_KEY_ACTIVE || unlock_state == STATE_BACKSPACE_ACTIVE) { cairo_set_line_width(ctx, 4); cairo_new_sub_path(ctx); double highlight_start = (rand() % (int)(2 * M_PI * 100)) / 100.0; cairo_arc(ctx, BUTTON_CENTER /* x */, BUTTON_CENTER /* y */, BUTTON_RADIUS /* radius */, highlight_start, highlight_start + (M_PI / 2.5)); cairo_set_operator(ctx,CAIRO_OPERATOR_CLEAR); /* Set newly drawn lines to erase what they're drawn over*/ cairo_stroke(ctx); /* Draw two little separators for the highlighted part of the * unlock indicator. */ cairo_set_operator(ctx,CAIRO_OPERATOR_OVER); /* back to normal operator */ cairo_set_line_width(ctx, 10); /* Change color of separators based on backspace/active keypress */ get_color(); /* separator 1 */ cairo_arc(ctx, BUTTON_CENTER /* x */, BUTTON_CENTER /* y */, BUTTON_RADIUS /* radius */, highlight_start /* start */, highlight_start + (M_PI / 128.0) /* end */); cairo_stroke(ctx); /* separator 2 */ cairo_arc(ctx, BUTTON_CENTER /* x */, BUTTON_CENTER /* y */, BUTTON_RADIUS /* radius */, highlight_start + (M_PI / 2.5) /* start */, (highlight_start + (M_PI / 2.5)) + (M_PI / 128.0) /* end */); cairo_stroke(ctx); } } if (xr_screens > 0) { /* Composite the unlock indicator in the middle of each screen. */ for (int screen = 0; screen < xr_screens; screen++) { int x = (xr_resolutions[screen].x + ((xr_resolutions[screen].width / 2) - (button_diameter_physical / 2))); int y = (xr_resolutions[screen].y + ((xr_resolutions[screen].height / 2) - (button_diameter_physical / 2))); cairo_set_source_surface(xcb_ctx, output, x, y); cairo_rectangle(xcb_ctx, x, y, button_diameter_physical, button_diameter_physical); cairo_fill(xcb_ctx); } } else { /* We have no information about the screen sizes/positions, so we just * place the unlock indicator in the middle of the X root window and * hope for the best. */ int x = (last_resolution[0] / 2) - (button_diameter_physical / 2); int y = (last_resolution[1] / 2) - (button_diameter_physical / 2); cairo_set_source_surface(xcb_ctx, output, x, y); cairo_rectangle(xcb_ctx, x, y, button_diameter_physical, button_diameter_physical); cairo_fill(xcb_ctx); } cairo_surface_destroy(xcb_output); cairo_surface_destroy(output); cairo_destroy(ctx); cairo_destroy(xcb_ctx); return bg_pixmap; }
static cairo_surface_t * _cairo_boilerplate_xcb_create_fallback (const char *name, cairo_content_t content, double width, double height, double max_width, double max_height, cairo_boilerplate_mode_t mode, int id, void **closure) { xcb_target_closure_t *xtc; xcb_connection_t *c; xcb_screen_t *s; xcb_void_cookie_t cookie; cairo_surface_t *tmp, *surface; cairo_status_t status; uint32_t values[] = { 1 }; *closure = xtc = xmalloc (sizeof (xcb_target_closure_t)); if (width == 0) width = 1; if (height == 0) height = 1; xtc->c = c = xcb_connect (NULL,NULL); if (xcb_connection_has_error(c)) { free (xtc); return NULL; } s = xcb_setup_roots_iterator (xcb_get_setup (c)).data; if (width > s->width_in_pixels || height > s->height_in_pixels) { xcb_disconnect (c); free (xtc); return NULL; } xtc->surface = NULL; xtc->is_pixmap = FALSE; xtc->drawable = xcb_generate_id (c); cookie = xcb_create_window_checked (c, s->root_depth, xtc->drawable, s->root, 0, 0, width, height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, s->root_visual, XCB_CW_OVERRIDE_REDIRECT, values); xcb_map_window (c, xtc->drawable); /* slow, but sure */ if (xcb_request_check (c, cookie) != NULL) { xcb_disconnect (c); free (xtc); return NULL; } tmp = cairo_xcb_surface_create (c, xtc->drawable, lookup_visual (s, s->root_visual), width, height); if (cairo_surface_status (tmp)) { xcb_disconnect (c); free (xtc); return tmp; } cairo_xcb_device_debug_cap_xrender_version (cairo_surface_get_device (tmp), -1, -1); /* recreate with impaired connection */ surface = cairo_xcb_surface_create (c, xtc->drawable, lookup_visual (s, s->root_visual), width, height); cairo_surface_destroy (tmp); xtc->device = cairo_device_reference (cairo_surface_get_device (surface)); status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL); if (status == CAIRO_STATUS_SUCCESS) return surface; cairo_surface_destroy (surface); _cairo_boilerplate_xcb_cleanup (xtc); return cairo_boilerplate_surface_create_in_error (status); }
explicit xcb_surface(xcb_connection_t* c, xcb_pixmap_t p, xcb_visualtype_t* v, int w, int h) : surface(cairo_xcb_surface_create(c, p, v, w, h)) {}
void menuwin_init() { key_win.surface=cairo_xcb_surface_create(conn,key_win.window,visual_type,width,1); // Set the _NET_SUPPORTING_WM_CHECK property pointing to the window ID in both the root and fake windows // Also set the WM_NAME property in both windows to TWM_NAME xcb_change_property(conn,XCB_PROP_MODE_REPLACE,scr->root,atoms[TWM_ATOM__NET_SUPPORTING_WM_CHECK],XCB_ATOM_WINDOW,32,1,&key_win.window); xcb_change_property(conn,XCB_PROP_MODE_REPLACE,scr->root,atoms[TWM_ATOM__NET_WM_NAME],XCB_ATOM_STRING,8,strlen(TWM_NAME),TWM_NAME); xcb_change_property(conn,XCB_PROP_MODE_REPLACE,key_win.window,atoms[TWM_ATOM__NET_SUPPORTING_WM_CHECK],XCB_ATOM_WINDOW,32,1,&key_win.window); xcb_change_property(conn,XCB_PROP_MODE_REPLACE,key_win.window,atoms[TWM_ATOM__NET_WM_NAME],XCB_ATOM_STRING,8,strlen(TWM_NAME),TWM_NAME); xcb_change_property(conn,XCB_PROP_MODE_REPLACE,key_win.window,atoms[TWM_ATOM__NET_WM_WINDOW_TYPE],XCB_ATOM_ATOM,32,1,&atoms[TWM_ATOM__NET_WM_WINDOW_TYPE_DOCK]); xcb_map_window(conn,key_win.window); xcb_flush(conn); key_win.cache=wincache_fill_element(key_win.window); key_win.cache->mapped=1; key_win.possition=0; key_win.has_keyboard=0; key_win.width=width; key_win.height=1; key_win.enabled_by_mouse=0; key_win.wait_for=0; fill_keycodes(); }