1 /**
2 * This file is a part of the Cairo-Dock project
3 *
4 * Copyright : (C) see the 'copyright' file.
5 * E-mail    : see the 'copyright' file.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 3
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include <stdlib.h>
21 #include <string.h>
22 #include <math.h>
23 
24 #include "applet-notifications.h"
25 #include "star-tex.h"
26 
27 static double fRadius = .33;
28 static double a = .2;
29 
30 
cd_show_mouse_render(gpointer pUserData,GldiContainer * pContainer,cairo_t * pCairoContext)31 gboolean cd_show_mouse_render (gpointer pUserData, GldiContainer *pContainer, cairo_t *pCairoContext)
32 {
33 	CDShowMouseData *pData = CD_APPLET_GET_MY_CONTAINER_DATA (pContainer);
34 	if (pData == NULL)
35 		return GLDI_NOTIFICATION_LET_PASS;
36 
37 	glPushMatrix();
38 
39 	if (CAIRO_DOCK_IS_DESKLET (pContainer))
40 	{
41 		CairoDesklet *pDesklet = CAIRO_DESKLET (pContainer);
42 		glTranslatef (-pDesklet->container.iWidth/2, -pDesklet->container.iHeight/2, -pDesklet->container.iHeight*(sqrt(3)/2));
43 	}
44 	if (pContainer->bIsHorizontal)
45 		glTranslatef (pContainer->iMouseX, pContainer->iHeight - pContainer->iMouseY, 0.);
46 	else
47 		glTranslatef (pContainer->iMouseY, pContainer->iWidth - pContainer->iMouseX, 0.);
48 	cairo_dock_render_particles (pData->pSystem);
49 
50 	glPopMatrix();
51 
52 	return GLDI_NOTIFICATION_LET_PASS;
53 }
54 
55 
56 #define _compute_area(area, pContainer, pData) do {\
57 if (pContainer->bIsHorizontal) {\
58 	area.x = pContainer->iMouseX - pData->pSystem->fWidth/2;\
59 	area.y = MAX (0, pContainer->iMouseY - pData->pSystem->fHeight);\
60 	area.width = pData->pSystem->fWidth;\
61 	area.height = pData->pSystem->fHeight*2; }\
62 else {\
63 	area.y = pContainer->iMouseX - pData->pSystem->fWidth/2;\
64 	area.x = MAX (0, pContainer->iMouseY - pData->pSystem->fHeight);\
65 	area.height = pData->pSystem->fWidth;\
66 	area.width = pData->pSystem->fHeight*2; } } while (0)
cd_show_mouse_update_container(gpointer pUserData,GldiContainer * pContainer,gboolean * bContinueAnimation)67 gboolean cd_show_mouse_update_container (gpointer pUserData, GldiContainer *pContainer, gboolean *bContinueAnimation)
68 {
69 	CDShowMouseData *pData = CD_APPLET_GET_MY_CONTAINER_DATA (pContainer);
70 	if (pData == NULL)
71 		return GLDI_NOTIFICATION_LET_PASS;
72 
73 	GdkRectangle area;
74 	if (! pContainer->bInside)
75 	{
76 		pData->fAlpha -= .05;
77 		if (pData->fAlpha <= 0)
78 		{
79 			_compute_area (area, pContainer, pData);
80 			cairo_dock_redraw_container_area (pContainer, &area);
81 
82 			cairo_dock_free_particle_system (pData->pSystem);
83 			g_free (pData);
84 			CD_APPLET_SET_MY_CONTAINER_DATA (pContainer, NULL);
85 
86 			return GLDI_NOTIFICATION_LET_PASS;
87 		}
88 	}
89 	else if (pData->fAlpha != 1)
90 		pData->fAlpha = MIN (1., pData->fAlpha + .05);
91 
92 	double dt = cairo_dock_get_animation_delta_t (pContainer) * 1e-3;
93 	pData->fRotationAngle += 2*G_PI * myConfig.fRotationSpeed * dt;
94 
95 	cd_show_mouse_update_sources (pData);
96 	pData->pSystem->fWidth = 2 * MIN (96, pContainer->iHeight);
97 	pData->pSystem->fHeight =  MIN (96, pContainer->iHeight);
98 	cd_show_mouse_update_particle_system (pData->pSystem, pData);
99 
100 	_compute_area (area, pContainer, pData);
101 	cairo_dock_redraw_container_area (pContainer, &area);
102 
103 	*bContinueAnimation = TRUE;
104 	return GLDI_NOTIFICATION_LET_PASS;
105 }
106 
107 
cd_show_mouse_enter_container(gpointer pUserData,GldiContainer * pContainer,gboolean * bStartAnimation)108 gboolean cd_show_mouse_enter_container (gpointer pUserData, GldiContainer *pContainer, gboolean *bStartAnimation)
109 {
110 	if (! CAIRO_DOCK_CONTAINER_IS_OPENGL (pContainer))
111 		return GLDI_NOTIFICATION_LET_PASS;
112 
113 	CDShowMouseData *pData = CD_APPLET_GET_MY_CONTAINER_DATA (pContainer);
114 	if (pData == NULL)
115 	{
116 		pData = g_new0 (CDShowMouseData, 1);
117 		pData->fAlpha = 1.;
118 
119 		double dt = cairo_dock_get_animation_delta_t (pContainer);
120 		pData->pSourceCoords = cd_show_mouse_init_sources ();
121 		pData->pSystem = cd_show_mouse_init_system (pContainer, dt, pData->pSourceCoords);
122 
123 		CD_APPLET_SET_MY_CONTAINER_DATA (pContainer, pData);
124 	}
125 
126 
127 	*bStartAnimation = TRUE;
128 	return GLDI_NOTIFICATION_LET_PASS;
129 }
130 
131 
132 
cd_show_mouse_init_sources(void)133 gdouble *cd_show_mouse_init_sources (void)
134 {
135 	double *pSourceCoords = g_new (double, myConfig.iNbSources * 2);
136 	double fTheta;
137 	int i;
138 	for (i = 0; i < myConfig.iNbSources; i ++)
139 	{
140 		fTheta = 2*G_PI * i / myConfig.iNbSources;
141 		pSourceCoords[2*i] = fRadius * cos (fTheta);
142 		pSourceCoords[2*i+1] = fRadius * sin (fTheta);
143 	}
144 	return pSourceCoords;
145 }
146 
cd_show_mouse_init_system(GldiContainer * pContainer,double dt,double * pSourceCoords)147 CairoParticleSystem *cd_show_mouse_init_system (GldiContainer *pContainer, double dt, double *pSourceCoords)
148 {
149 	if (myData.iTexture == 0)
150 		myData.iTexture = cairo_dock_create_texture_from_raw_data (starTex, 32, 32);  /// 32 = sqrt (4096/4)
151 	double fHeight = pContainer->iHeight;  // iMaxDockHeight ?
152 	CairoParticleSystem *pParticleSystem = cairo_dock_create_particle_system (myConfig.iNbParticles * myConfig.iNbSources, myData.iTexture, 2*fHeight, fHeight);
153 	pParticleSystem->dt = dt;
154 
155 	int iNumSource;
156 	double fBlend;
157 	double r = myConfig.iParticleSize / (1 + a);
158 	double sigma = myConfig.fScattering;
159 	CairoParticle *p;
160 	int i;
161 	for (i = 0; i < pParticleSystem->iNbParticles; i ++)
162 	{
163 		p = &(pParticleSystem->pParticles[i]);
164 
165 		iNumSource = i / myConfig.iNbParticles;
166 
167 		p->x = pSourceCoords[2*iNumSource];
168 		p->y = pSourceCoords[2*iNumSource+1];
169 		p->z = 0;
170 		p->fWidth = r * (a + g_random_double ());
171 		p->fHeight = p->fWidth;
172 
173 		p->vx = sigma * (2 * g_random_double () - 1) * dt / myConfig.iParticleLifeTime;
174 		p->vy = sigma * (2 * g_random_double () - 1) * dt / myConfig.iParticleLifeTime;
175 		p->iInitialLife = ceil (myConfig.iParticleLifeTime / dt);
176 		p->iLife = g_random_int_range (1, p->iInitialLife+1);
177 
178 		if (myConfig.bMysticalFire)
179 		{
180 			p->color[0] = g_random_double ();
181 			p->color[1] = g_random_double ();
182 			p->color[2] = g_random_double ();
183 		}
184 		else
185 		{
186 			fBlend = g_random_double ();
187 			p->color[0] = fBlend * myConfig.pColor1[0] + (1 - fBlend) * myConfig.pColor2[0];
188 			p->color[1] = fBlend * myConfig.pColor1[1] + (1 - fBlend) * myConfig.pColor2[1];
189 			p->color[2] = fBlend * myConfig.pColor1[2] + (1 - fBlend) * myConfig.pColor2[2];
190 		}
191 		p->color[3] = 1.;
192 
193 		p->fSizeFactor = 1.;
194 		p->fResizeSpeed = .5 / myConfig.iParticleLifeTime * dt;  // zoom 1.5 a la fin.
195 	}
196 
197 	return pParticleSystem;
198 
199 }
200 
cd_show_mouse_update_sources(CDShowMouseData * pData)201 void cd_show_mouse_update_sources (CDShowMouseData *pData)
202 {
203 	double *pSourceCoords = pData->pSourceCoords;
204 	double fTheta;
205 	int i;
206 	for (i = 0; i < myConfig.iNbSources; i ++)
207 	{
208 		fTheta = 2*G_PI * i / myConfig.iNbSources + pData->fRotationAngle;
209 		pSourceCoords[2*i] = fRadius * cos (fTheta);
210 		pSourceCoords[2*i+1] = fRadius * sin (fTheta);
211 	}
212 }
213 
214 
cd_show_mouse_update_particle_system(CairoParticleSystem * pParticleSystem,CDShowMouseData * pData)215 void cd_show_mouse_update_particle_system (CairoParticleSystem *pParticleSystem, CDShowMouseData *pData)
216 {
217 	double *pSourceCoords = pData->pSourceCoords;
218 	CairoParticle *p;
219 	double dt = pParticleSystem->dt;
220 	int i;
221 	double sigma = myConfig.fScattering;
222 	for (i = 0; i < pParticleSystem->iNbParticles; i ++)
223 	{
224 		p = &(pParticleSystem->pParticles[i]);
225 
226 		p->x += p->vx;
227 		p->y += p->vy;
228 		p->color[3] = pData->fAlpha * p->iLife / p->iInitialLife;
229 		p->fSizeFactor += p->fResizeSpeed;
230 		if (p->iLife > 0)
231 		{
232 			p->iLife --;
233 			if (p->iLife == 0)
234 			{
235 				int iNumSource = i / myConfig.iNbParticles;
236 				p->x = pSourceCoords[2*iNumSource];
237 				p->y = pSourceCoords[2*iNumSource+1];
238 
239 				p->vx = sigma * (2 * g_random_double () - 1) * dt / myConfig.iParticleLifeTime;
240 				p->vy = sigma * (2 * g_random_double () - 1) * dt / myConfig.iParticleLifeTime;
241 
242 				p->color[3] = pData->fAlpha;
243 				p->fSizeFactor = 1.;
244 
245 				p->iLife = g_random_int_range (1, p->iInitialLife+1);
246 			}
247 		}
248 	}
249 }
250 
cd_show_mouse_free_data(gpointer pUserData,GldiContainer * pContainer)251 gboolean cd_show_mouse_free_data (gpointer pUserData, GldiContainer *pContainer)
252 {
253 	cd_message ("");
254 	CDShowMouseData *pData = CD_APPLET_GET_MY_CONTAINER_DATA (pContainer);
255 	if (pData == NULL)
256 		return GLDI_NOTIFICATION_LET_PASS;
257 
258 	cairo_dock_free_particle_system (pData->pSystem);
259 	g_free (pData);
260 	CD_APPLET_SET_MY_CONTAINER_DATA (pContainer, NULL);
261 	return GLDI_NOTIFICATION_LET_PASS;
262 }
263