/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Small example demonstrating emulating knockout-groups as in PDF-1.4 * using cairo_set_operator(). * * Owen Taylor, * v0.1 30 November 2002 * v0.2 1 December 2002 - typo fixes from Keith Packard * v0.3 17 April 2003 - Tracking changes in Xr, (Removal of Xr{Push,Pop}Group) * v0.4 29 September 2003 - Use cairo_rectangle rather than private rect_path * Use cairo_arc for oval_path * Keeping log of changes in ChangeLog/CVS now. (2003-11-19) Carl Worth */ #include "conky.h" #include #include #include #include #include #include /* Fill the given area with checks in the standard style * for showing compositing effects. */ static void fill_checks(cairo_t * cr, int x, int y, int width, int height) { cairo_surface_t *check; cairo_pattern_t *check_pattern; cairo_save(cr); #define CHECK_SIZE 32 check = cairo_surface_create_similar(cairo_current_target_surface(cr), CAIRO_FORMAT_RGB24, 2 * CHECK_SIZE, 2 * CHECK_SIZE); cairo_surface_set_repeat(check, 1); /* Draw the check */ { cairo_save(cr); cairo_set_target_surface(cr, check); cairo_set_operator(cr, CAIRO_OPERATOR_SRC); cairo_set_rgb_color(cr, 0.4, 0.4, 0.4); cairo_rectangle(cr, 0, 0, 2 * CHECK_SIZE, 2 * CHECK_SIZE); cairo_fill(cr); cairo_set_rgb_color(cr, 0.7, 0.7, 0.7); cairo_rectangle(cr, x, y, CHECK_SIZE, CHECK_SIZE); cairo_fill(cr); cairo_rectangle(cr, x + CHECK_SIZE, y + CHECK_SIZE, CHECK_SIZE, CHECK_SIZE); cairo_fill(cr); cairo_restore(cr); } /* Fill the whole surface with the check */ check_pattern = cairo_pattern_create_for_surface(check); cairo_set_pattern(cr, check_pattern); cairo_rectangle(cr, 0, 0, width, height); cairo_fill(cr); cairo_pattern_destroy(check_pattern); cairo_surface_destroy(check); cairo_restore(cr); } static void draw_pee(cairo_t * cr, double xc, double yc) { cairo_set_rgb_color(cr, 0, 0, 0); cairo_show_text(cr, "Conky"); } static void draw(cairo_t * cr, int width, int height) { cairo_surface_t *overlay; /* Fill the background */ double xc = width / 2.; double yc = height / 2.; overlay = cairo_surface_create_similar(cairo_current_target_surface(cr), CAIRO_FORMAT_ARGB32, width, height); if (overlay == NULL) return; fill_checks(cr, 0, 0, width, height); cairo_save(cr); cairo_set_target_surface(cr, overlay); cairo_set_alpha(cr, 0.5); cairo_set_operator(cr, CAIRO_OPERATOR_OVER); draw_pee(cr, xc, yc); cairo_restore(cr); cairo_show_surface(cr, overlay, width, height); cairo_surface_destroy(overlay); } int do_it(void) { Display *dpy; int screen; Window w; Pixmap pixmap; char *title = "cairo: Knockout Groups"; unsigned int quit_keycode; int needs_redraw; GC gc; XWMHints *wmhints; XSizeHints *normalhints; XClassHint *classhint; int width = 400; int height = 400; dpy = XOpenDisplay(NULL); screen = DefaultScreen(dpy); w = XCreateSimpleWindow(dpy, RootWindow(dpy, screen), 0, 0, width, height, 0, BlackPixel(dpy, screen), WhitePixel(dpy, screen)); normalhints = XAllocSizeHints(); normalhints->flags = 0; normalhints->x = 0; normalhints->y = 0; normalhints->width = width; normalhints->height = height; classhint = XAllocClassHint(); classhint->res_name = "cairo-knockout"; classhint->res_class = "Cairo-knockout"; wmhints = XAllocWMHints(); wmhints->flags = InputHint; wmhints->input = True; XmbSetWMProperties(dpy, w, title, "cairo-knockout", 0, 0, normalhints, wmhints, classhint); XFree(wmhints); XFree(classhint); XFree(normalhints); pixmap = XCreatePixmap(dpy, w, width, height, DefaultDepth(dpy, screen)); gc = XCreateGC(dpy, pixmap, 0, NULL); quit_keycode = XKeysymToKeycode(dpy, XStringToKeysym("Q")); XSelectInput(dpy, w, ExposureMask | StructureNotifyMask | ButtonPressMask | KeyPressMask); XMapWindow(dpy, w); needs_redraw = 1; while (1) { XEvent xev; /* Only do the redraw if there are no events pending. This * avoids us getting behind doing several redraws for several * consecutive resize events for example. */ if (!XPending(dpy) && needs_redraw) { cairo_t *cr = cairo_create(); cairo_set_target_drawable(cr, dpy, pixmap); draw(cr, width, height); cairo_destroy(cr); XCopyArea(dpy, pixmap, w, gc, 0, 0, width, height, 0, 0); needs_redraw = 0; } XNextEvent(dpy, &xev); switch (xev.xany.type) { case ButtonPress: /* A click on the canvas ends the program */ goto DONE; case KeyPress: if (xev.xkey.keycode == quit_keycode) goto DONE; break; case ConfigureNotify: /* Note new size and create new pixmap. */ width = xev.xconfigure.width; height = xev.xconfigure.height; XFreePixmap(dpy, pixmap); pixmap = XCreatePixmap(dpy, w, width, height, DefaultDepth(dpy, screen)); needs_redraw = 1; break; case Expose: XCopyArea(dpy, pixmap, w, gc, xev.xexpose.x, xev.xexpose.y, xev.xexpose.width, xev.xexpose.height, xev.xexpose.x, xev.xexpose.y); break; } } DONE: XFreeGC(dpy, gc); XCloseDisplay(dpy); return 0; }