comparison src/aosd/ghosd-main.c @ 569:d401f87f89f7 trunk

[svn] - added Audacious OSD, yet-another-written-from-scratch plugin to display OSD, based on Ghosd library; currently untied from configure, to compile it you have to run make in its directory; will be added to configure after some testing
author giacomo
date Mon, 29 Jan 2007 06:40:04 -0800
parents
children f574c2c52beb
comparison
equal deleted inserted replaced
568:8c64b5abdcda 569:d401f87f89f7
1 /* ghosd -- OSD with fake transparency, cairo, and pango.
2 * Copyright (C) 2006 Evan Martin <martine@danga.com>
3 */
4
5 #include "config.h"
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <sys/time.h>
10 #include <sys/poll.h>
11 #include <string.h>
12 #include <time.h>
13 #include <unistd.h>
14
15 #include "ghosd.h"
16 #include "ghosd-internal.h"
17
18 static void
19 ghosd_main_iteration(Ghosd *ghosd) {
20 XEvent ev, pev;
21 XNextEvent(ghosd->dpy, &ev);
22
23 /* smash multiple configure/exposes into one. */
24 if (ev.type == ConfigureNotify) {
25 while (XPending(ghosd->dpy)) {
26 XPeekEvent(ghosd->dpy, &pev);
27 if (pev.type != ConfigureNotify && pev.type != Expose)
28 break;
29 XNextEvent(ghosd->dpy, &ev);
30 }
31 }
32
33 switch (ev.type) {
34 case Expose:
35 break;
36 case ConfigureNotify:
37 if (ghosd->width > 0) {
38 /* XXX if the window manager disagrees with our positioning here,
39 * we loop. */
40 if (ghosd->x != ev.xconfigure.x ||
41 ghosd->y != ev.xconfigure.y) {
42 /*width = ev.xconfigure.width;
43 height = ev.xconfigure.height;*/
44 XMoveResizeWindow(ghosd->dpy, ghosd->win,
45 ghosd->x, ghosd->y, ghosd->width, ghosd->height);
46 }
47 }
48 break;
49 }
50 }
51
52 void
53 ghosd_main_iterations(Ghosd *ghosd) {
54 while (XPending(ghosd->dpy))
55 ghosd_main_iteration(ghosd);
56 }
57
58 void
59 ghosd_main_until(Ghosd *ghosd, struct timeval *until) {
60 struct timeval tv_now;
61
62 ghosd_main_iterations(ghosd);
63
64 for (;;) {
65 gettimeofday(&tv_now, NULL);
66 int dt = (until->tv_sec - tv_now.tv_sec )*1000 +
67 (until->tv_usec - tv_now.tv_usec)/1000;
68 if (dt <= 0) break;
69
70 struct pollfd pollfd = { ghosd_get_socket(ghosd), POLLIN, 0 };
71 int ret = poll(&pollfd, 1, dt);
72 if (ret < 0) {
73 perror("poll");
74 exit(1);
75 } else if (ret > 0) {
76 ghosd_main_iterations(ghosd);
77 } else {
78 /* timer expired. */
79 break;
80 }
81 }
82 }
83
84 typedef struct {
85 cairo_surface_t* surface;
86 float alpha;
87 RenderCallback user_render;
88 } GhosdFlashData;
89
90 static void
91 flash_render(Ghosd *ghosd, cairo_t *cr, void* data) {
92 GhosdFlashData *flash = data;
93
94 /* the first time we render, let the client render into their own surface. */
95 if (flash->surface == NULL) {
96 cairo_t *rendered_cr;
97 flash->surface = cairo_surface_create_similar(cairo_get_target(cr),
98 CAIRO_CONTENT_COLOR_ALPHA,
99 ghosd->width, ghosd->height);
100 rendered_cr = cairo_create(flash->surface);
101 flash->user_render.func(ghosd, rendered_cr, flash->user_render.data);
102 cairo_destroy(rendered_cr);
103 }
104
105 /* now that we have a rendered surface, all we normally do is copy that to
106 * the screen. */
107 cairo_set_source_surface(cr, flash->surface, 0, 0);
108 cairo_paint_with_alpha(cr, flash->alpha);
109 }
110
111 /* we don't need to free the flashdata object, because we stack-allocate that.
112 * but we do need to let the old user data free itself... */
113 static void
114 flash_destroy(void *data) {
115 GhosdFlashData *flash = data;
116 if (flash->user_render.data_destroy)
117 flash->user_render.data_destroy(flash->user_render.data);
118 }
119
120 void
121 ghosd_flash(Ghosd *ghosd, int fade_ms, int total_display_ms) {
122 GhosdFlashData flash = {0};
123 memcpy(&flash.user_render, &ghosd->render, sizeof(RenderCallback));
124 ghosd_set_render(ghosd, flash_render, &flash, flash_destroy);
125
126 ghosd_show(ghosd);
127
128 const int STEP_MS = 50;
129 const float dalpha = 1.0 / (fade_ms / (float)STEP_MS);
130 struct timeval tv_nextupdate;
131
132 /* fade in. */
133 for (flash.alpha = 0; flash.alpha < 1.0; flash.alpha += dalpha) {
134 if (flash.alpha > 1.0) flash.alpha = 1.0;
135 ghosd_render(ghosd);
136
137 gettimeofday(&tv_nextupdate, NULL);
138 tv_nextupdate.tv_usec += STEP_MS*1000;
139 ghosd_main_until(ghosd, &tv_nextupdate);
140 }
141
142 /* full display. */
143 flash.alpha = 1.0;
144 ghosd_render(ghosd);
145
146 gettimeofday(&tv_nextupdate, NULL);
147 tv_nextupdate.tv_usec += (total_display_ms - (2*fade_ms))*1000;
148 ghosd_main_until(ghosd, &tv_nextupdate);
149
150 /* fade out. */
151 for (flash.alpha = 1.0; flash.alpha > 0.0; flash.alpha -= dalpha) {
152 ghosd_render(ghosd);
153
154 gettimeofday(&tv_nextupdate, NULL);
155 tv_nextupdate.tv_usec += STEP_MS*1000;
156 ghosd_main_until(ghosd, &tv_nextupdate);
157 }
158
159 flash.alpha = 0;
160 ghosd_render(ghosd);
161
162 /* display for another half-second,
163 * because otherwise the fade out attracts your eye
164 * and then you'll see a flash while it repaints where the ghosd was.
165 */
166 gettimeofday(&tv_nextupdate, NULL);
167 tv_nextupdate.tv_usec += 500*1000;
168 ghosd_main_until(ghosd, &tv_nextupdate);
169 }
170
171 /* vim: set ts=2 sw=2 et cino=(0 : */