/* ghosd -- OSD with fake transparency, cairo, and pango. * Copyright (C) 2006 Evan Martin */ #include "config.h" #include #include #include #include #include #include #include "ghosd.h" #include "ghosd-internal.h" static void ghosd_main_iteration(Ghosd *ghosd) { XEvent ev, pev; XNextEvent(ghosd->dpy, &ev); /* smash multiple configure/exposes into one. */ if (ev.type == ConfigureNotify) { while (XPending(ghosd->dpy)) { XPeekEvent(ghosd->dpy, &pev); if (pev.type != ConfigureNotify && pev.type != Expose) break; XNextEvent(ghosd->dpy, &ev); } } switch (ev.type) { case Expose: break; case ConfigureNotify: if (ghosd->width > 0) { /* XXX if the window manager disagrees with our positioning here, * we loop. */ if (ghosd->x != ev.xconfigure.x || ghosd->y != ev.xconfigure.y) { /*width = ev.xconfigure.width; height = ev.xconfigure.height;*/ XMoveResizeWindow(ghosd->dpy, ghosd->win, ghosd->x, ghosd->y, ghosd->width, ghosd->height); } } break; } } void ghosd_main_iterations(Ghosd *ghosd) { while (XPending(ghosd->dpy)) ghosd_main_iteration(ghosd); } typedef struct { GhosdRenderFunc render_func; void *render_data; cairo_surface_t* surface; float alpha; } GhosdFlashData; static void ghosd_flash_render(Ghosd *ghosd, cairo_t *cr, void* data) { GhosdFlashData *flash = data; /* the first time we render, let the client render into their own surface. */ if (flash->surface == NULL) { cairo_t *rendered_cr; flash->surface = cairo_surface_create_similar(cairo_get_target(cr), CAIRO_CONTENT_COLOR_ALPHA, ghosd->width, ghosd->height); rendered_cr = cairo_create(flash->surface); flash->render_func(ghosd, rendered_cr, flash->render_data); cairo_destroy(rendered_cr); } /* now that we have a rendered surface, all we normally do is copy that to * the screen. */ cairo_set_source_surface(cr, flash->surface, 0, 0); cairo_paint_with_alpha(cr, flash->alpha); } void ghosd_main_until(Ghosd *ghosd, struct timeval *until) { struct timeval tv_now; ghosd_main_iterations(ghosd); for (;;) { gettimeofday(&tv_now, NULL); int dt = (until->tv_sec - tv_now.tv_sec )*1000 + (until->tv_usec - tv_now.tv_usec)/1000; if (dt <= 0) break; struct pollfd pollfd = { ghosd_get_socket(ghosd), POLLIN, 0 }; int ret = poll(&pollfd, 1, dt); if (ret < 0) { perror("poll"); exit(1); } else if (ret > 0) { ghosd_main_iterations(ghosd); } else { /* timer expired. */ break; } } } void ghosd_flash(Ghosd *ghosd, int fade_ms, int total_display_ms) { GhosdFlashData flash = {0}; flash.render_func = ghosd->render_func; flash.render_data = ghosd->render_data; ghosd->render_func = ghosd_flash_render; ghosd->render_data = &flash; ghosd_render(ghosd); ghosd_show(ghosd); const int STEP_MS = 50; const float dalpha = 1.0 / (fade_ms / (float)STEP_MS); struct timeval tv_nextupdate; /* fade in. */ for (flash.alpha = 0; flash.alpha < 1.0; flash.alpha += dalpha) { if (flash.alpha > 1.0) flash.alpha = 1.0; ghosd_render(ghosd); gettimeofday(&tv_nextupdate, NULL); tv_nextupdate.tv_usec += STEP_MS*1000; ghosd_main_until(ghosd, &tv_nextupdate); } /* full display. */ flash.alpha = 1.0; ghosd_render(ghosd); gettimeofday(&tv_nextupdate, NULL); tv_nextupdate.tv_usec += (total_display_ms - (2*fade_ms))*1000; ghosd_main_until(ghosd, &tv_nextupdate); /* fade out. */ for (flash.alpha = 1.0; flash.alpha > 0.0; flash.alpha -= dalpha) { ghosd_render(ghosd); gettimeofday(&tv_nextupdate, NULL); tv_nextupdate.tv_usec += STEP_MS*1000; ghosd_main_until(ghosd, &tv_nextupdate); } flash.alpha = 0; ghosd_render(ghosd); ghosd_main_iterations(ghosd); } /* vim: set ts=2 sw=2 et cino=(0 : */