Mercurial > audlegacy-plugins
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 : */ |